seta hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight 0.1 "weight of latest data point"
seta hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold 0.5 "threshold for fps change when to update instantly, to make big fps changes update faster"
+seta hud_panel_physics_acceleration_movingaverage 1 "use an averaging method for calculating acceleration instead of the real value"
+seta hud_panel_phisics_update_interval 0.0666 "how often (in seconds) numeric values get updated on screen"
+
// hud panel aliases
alias hud_panel_radar_rotate "toggle hud_panel_radar_rotation 0 1 2 3 4"
alias +hud_panel_radar_maximized "cl_cmd hud radar 1"
alias mobedit "qc_cmd_cmd mobedit ${* ?}" // Edit a monster's properties
alias mobkill "qc_cmd_cmd mobkill ${* ?}" // Kill a monster
alias mobspawn "qc_cmd_cmd mobspawn ${* ?}" // Spawn a monster infront of the player
+alias physics "qc_cmd_cmd physics ${* ?}" // Change physics set
alias spectate "qc_cmd_cmd spectate ${* ?}" // Become an observer
alias suggestmap "qc_cmd_cmd suggestmap ${* ?}" // Suggest a map to the mapvote at match end
//alias tell "qc_cmd_cmd tell ${* ?}" // Send a message directly to a player
// e.g. Xonotic 1.5.1 RC1 will be 15101
set g_xonoticversion git "Xonotic version (formatted for humans)"
-gameversion 800 // 0.8.0
+gameversion 801 // 0.8.1
gameversion_min 0 // git builds see all versions
gameversion_max 65535 // git builds see all versions
// use default physics
set sv_friction_on_land 0
+set sv_friction_slick 0.5
set sv_player_viewoffset "0 0 35" "view offset of the player model"
set sv_player_mins "-16 -16 -24" "playermodel mins"
set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
set g_spawn_alloweffects 1 "allow clients to enable spawn point and event effects such as particles and sounds, see cl_spawn_ cvars for more info"
-set g_spawn_furthest 1.0 "this amount of the spawns shall be far away from any players"
+set g_spawn_furthest 0.5 "this amount of the spawns shall be far away from any players"
set g_spawn_useallspawns 0 "use all spawns, e.g. also team spawns in non-teamplay, and all spawns, even enemy spawns, in teamplay"
// respawn delay
set g_respawn_delay_small 2 "small game number of seconds you have to wait before you can respawn again"
exec mutators.cfg
exec notifications.cfg
exec monsters.cfg
+exec physics.cfg
// load console command aliases and settings
exec commands.cfg
// =====================
// gametype vote hooks
// =====================
-// these are called when the mode is switched via gametype vote screen, earlier than gamestart hooks (useful for enabling per-gamemode mutators)
-alias sv_vote_gametype_hook_all
+// These are called when the mode is switched via gametype vote screen,
+// earlier than gamestart hooks (useful for enabling per-gamemode mutators)
+// The _all hook is called before the specific one
+// here it sets g_maxplayers to undo what duel does
+alias sv_vote_gametype_hook_all "set g_maxplayers 0"
alias sv_vote_gametype_hook_as
alias sv_vote_gametype_hook_ca
alias sv_vote_gametype_hook_ctf
alias sv_vote_gametype_hook_rc
alias sv_vote_gametype_hook_tdm
+// Preset to allow duel to be used for the gametype voting screen
+// sv_vote_gametype_*_type Must be set to the name of the gametype the option is based on
+// sv_vote_gametype_*_name Contains a human-readable name of the gametype
+// sv_vote_gametype_*_description Contains a longer description
+set sv_vote_gametype_duel_type dm
+set sv_vote_gametype_duel_name Duel
+set sv_vote_gametype_duel_description "One vs One match"
+alias sv_vote_gametype_hook_duel "set g_maxplayers 2"
+
// ===========
// leadlimit
// charmap
ALPHA_CHARMAP_CHAR 0.85
COLOR_CHARMAP_CHAR '1 1 1'
-ALPHA_CHARMAP_FOCUS 0.85
-COLOR_CHARMAP_FOCUS '0.09 0.42 0.69'
+
+// crosshairpicker
+ALPHA_CROSSHAIRPICKER_CROSSHAIR 0.6
+COLOR_CROSSHAIRPICKER_CROSSHAIR '1 1 1'
// checkbox
COLOR_CHECKBOX_C '1 1 1'
FONTSIZE_NORMAL 12
FONTSIZE_TITLE 16
FONTSIZE_TOOLTIP 12
-HEIGHT_NORMAL 1.5
-HEIGHT_TITLE 1.5
+HEIGHT_NORMAL 1.45
+HEIGHT_TITLE 1.45
HEIGHT_ZOOMEDTITLE -1
+// gametypelist
+BOOL_GAMETYPELIST_ICON_BLUR 0
+
// inputbox
COLOR_INPUTBOX_F '1 1 1'
COLOR_INPUTBOX_N '1 1 1'
COLOR_LISTBOX_SELECTED '0.97 0.56 0.27'
ALPHA_LISTBOX_WAITING 0.8
COLOR_LISTBOX_WAITING '0.73 0.82 0.9'
+ALPHA_LISTBOX_FOCUSED 0.55
+FADEALPHA_LISTBOX_FOCUSED 0.3
+COLOR_LISTBOX_FOCUSED '0.09 0.42 0.69'
// mainmenu
ALPHAS_MAINMENU '0.8 0.9 1'
-title Luminos (default)
+title Luminos
author sev
// Colors: 'Red Green Blue'
// font sizes (used for everything)
FONTSIZE_NORMAL 12
-HEIGHT_NORMAL 1.5
+HEIGHT_NORMAL 1.45
FONTSIZE_TITLE 16
-HEIGHT_TITLE 1.5
+HEIGHT_TITLE 1.45
HEIGHT_ZOOMEDTITLE -1
// general
ALPHA_LISTBOX_SELECTED 1
COLOR_LISTBOX_WAITING '1 1 1'
ALPHA_LISTBOX_WAITING 0.5
+COLOR_LISTBOX_FOCUSED '0 0.25 0.5'
+ALPHA_LISTBOX_FOCUSED 0.6
+FADEALPHA_LISTBOX_FOCUSED 0.3
// item: map list
COLOR_MAPLIST_TITLE '1 1 1'
COLOR_CHECKBOX_F '1 1 1'
COLOR_CHECKBOX_D '1 1 1'
-// item: crosshair button
-// uses "crosshairbutton" images
-
// dialog background colors
// uses "border" images
COLOR_DIALOG_MULTIPLAYER '1 1 1'
COLOR_DIALOG_CVARS '1 0 0'
COLOR_DIALOG_HUDCONFIRM '1 0 0'
+// gametypelist
+BOOL_GAMETYPELIST_ICON_BLUR 1
+
// item: input box
// uses "inputbox" images
COLOR_INPUTBOX_N '1 1 1'
// item: charmap
ALPHA_CHARMAP_CHAR 0.85
COLOR_CHARMAP_CHAR '1 1 1'
-ALPHA_CHARMAP_FOCUS 1
-COLOR_CHARMAP_FOCUS '0 0.25 0.5'
+
+// item: crosshairpicker
+ALPHA_CROSSHAIRPICKER_CROSSHAIR 0.6
+COLOR_CROSSHAIRPICKER_CROSSHAIR '1 1 1'
// item: radio button
// uses "radiobutton" images
ALPHA_LISTBOX_SELECTED 1
COLOR_LISTBOX_WAITING '1 1 1'
ALPHA_LISTBOX_WAITING 0.5
+COLOR_LISTBOX_FOCUSED '0 0.375 0.75'
+ALPHA_LISTBOX_FOCUSED 0.35
+FADEALPHA_LISTBOX_FOCUSED 0.75
// item: map list
COLOR_MAPLIST_TITLE '1 1 1'
COLOR_CHECKBOX_F '0.5 0.75 1'
COLOR_CHECKBOX_D '1 1 1'
-// item: crosshair button
-// uses "crosshairbutton" images
-
// dialog background colors
// uses "border" images
COLOR_DIALOG_MULTIPLAYER '1 1 1'
COLOR_DIALOG_CVARS '1 0 0'
COLOR_DIALOG_HUDCONFIRM '1 0 0'
+// gametypelist
+BOOL_GAMETYPELIST_ICON_BLUR 1
+
// item: input box
// uses "inputbox" images
COLOR_INPUTBOX_N '1 1 1'
// item: charmap
ALPHA_CHARMAP_CHAR 0.85
COLOR_CHARMAP_CHAR '1 1 1'
-ALPHA_CHARMAP_FOCUS 0.75
-COLOR_CHARMAP_FOCUS '0 0.375 0.75'
+
+// item: crosshairpicker
+ALPHA_CROSSHAIRPICKER_CROSSHAIR 0.85
+COLOR_CROSSHAIRPICKER_CROSSHAIR '1 1 1'
// item: radio button
// uses "radiobutton" images
ROWS_CREDITS 20
WIDTH_CREDITS 0.5
-// item: crosshair button
-// uses "crosshairbutton" images
-
// item: cvar list
ALPHA_CVARLIST_SAVED 1
ALPHA_CVARLIST_TEMPORARY 0.7
COLOR_CVARLIST_UNCHANGED '1 1 1'
COLOR_CVARLIST_CONTROLS '1 0 0'
+// gametypelist
+BOOL_GAMETYPELIST_ICON_BLUR 1
+
// item: dialog
// uses "border" images
// uses "closebutton" images
ALPHA_LISTBOX_SELECTED 1
COLOR_LISTBOX_WAITING '1 0 0'
ALPHA_LISTBOX_WAITING 0.5
-COLOR_LISTBOX_BACKGROUND '0 0 0'
-ALPHA_LISTBOX_BACKGROUND 0
+COLOR_LISTBOX_BACKGROUND '0 0 0'
+ALPHA_LISTBOX_BACKGROUND 0
+COLOR_LISTBOX_FOCUSED '0 0 0'
+ALPHA_LISTBOX_FOCUSED 0.3
+FADEALPHA_LISTBOX_FOCUSED 0.3
// item: map list
COLOR_MAPLIST_TITLE '1 1 1'
// item: charmap
ALPHA_CHARMAP_CHAR 0.85
COLOR_CHARMAP_CHAR '1 1 1'
-ALPHA_CHARMAP_FOCUS 0.5
-COLOR_CHARMAP_FOCUS '0 0 0'
+
+// item: crosshairpicker
+ALPHA_CROSSHAIRPICKER_CROSSHAIR 0.85
+COLOR_CROSSHAIRPICKER_CROSSHAIR '1 1 1'
// item: radio button
// uses "radiobutton" images
--- /dev/null
+// ==================================================
+// Main configuration for client selectable physics
+// ==================================================
+
+
+// ==============
+// Main options
+// ==============
+seta cl_physics "default" "client selected physics set"
+
+set g_physics_clientselect 0 "allow clients to select their physics set"
+set g_physics_clientselect_options "xonotic nexuiz quake warsow defrag quake3 vecxis quake2 bones"
+set g_physics_clientselect_default "" "override default physics"
+
+// =========
+// Xonotic
+// =========
+set g_physics_xonotic_airaccel_qw -0.8
+set g_physics_xonotic_airstrafeaccel_qw -0.95
+set g_physics_xonotic_airspeedlimit_nonqw 900
+set g_physics_xonotic_maxspeed 360
+set g_physics_xonotic_jumpvelocity 260
+set g_physics_xonotic_maxairstrafespeed 100
+set g_physics_xonotic_maxairspeed 360
+set g_physics_xonotic_airstrafeaccelerate 18
+set g_physics_xonotic_warsowbunny_turnaccel 0
+set g_physics_xonotic_airaccel_qw_stretchfactor 2
+set g_physics_xonotic_airaccel_sideways_friction 0
+set g_physics_xonotic_aircontrol 100
+set g_physics_xonotic_aircontrol_power 2
+set g_physics_xonotic_aircontrol_penalty 0
+set g_physics_xonotic_warsowbunny_airforwardaccel 1.00001
+set g_physics_xonotic_warsowbunny_topspeed 925
+set g_physics_xonotic_warsowbunny_accel 0.1593
+set g_physics_xonotic_warsowbunny_backtosideratio 0.8
+set g_physics_xonotic_friction 6
+set g_physics_xonotic_accelerate 15
+set g_physics_xonotic_stopspeed 100
+set g_physics_xonotic_airaccelerate 2
+set g_physics_xonotic_airstopaccelerate 3
+
+// ========
+// Nexuiz
+// ========
+set g_physics_nexuiz_airaccel_qw 0.95
+set g_physics_nexuiz_airstrafeaccel_qw 0
+set g_physics_nexuiz_airspeedlimit_nonqw 0
+set g_physics_nexuiz_maxspeed 400
+set g_physics_nexuiz_jumpvelocity 300 "333 to match xonotic physics"
+set g_physics_nexuiz_maxairstrafespeed 0
+set g_physics_nexuiz_maxairspeed 220
+set g_physics_nexuiz_airstrafeaccelerate 0
+set g_physics_nexuiz_warsowbunny_turnaccel 0
+set g_physics_nexuiz_airaccel_qw_stretchfactor 0
+set g_physics_nexuiz_airaccel_sideways_friction 0.35
+set g_physics_nexuiz_aircontrol 0
+set g_physics_nexuiz_aircontrol_power 2
+set g_physics_nexuiz_aircontrol_penalty 0
+set g_physics_nexuiz_warsowbunny_airforwardaccel 1.00001
+set g_physics_nexuiz_warsowbunny_topspeed 925
+set g_physics_nexuiz_warsowbunny_accel 0.1593
+set g_physics_nexuiz_warsowbunny_backtosideratio 0.8
+set g_physics_nexuiz_friction 7
+set g_physics_nexuiz_accelerate 8
+set g_physics_nexuiz_stopspeed 100
+set g_physics_nexuiz_airaccelerate 5.5
+set g_physics_nexuiz_airstopaccelerate 0
+
+// =======
+// Quake
+// =======
+set g_physics_quake_airaccel_qw 1
+set g_physics_quake_airstrafeaccel_qw 0
+set g_physics_quake_airspeedlimit_nonqw 0
+set g_physics_quake_maxspeed 320
+set g_physics_quake_jumpvelocity 270
+set g_physics_quake_maxairstrafespeed 0
+set g_physics_quake_maxairspeed 30
+set g_physics_quake_airstrafeaccelerate 0
+set g_physics_quake_warsowbunny_turnaccel 0
+set g_physics_quake_airaccel_qw_stretchfactor 0
+set g_physics_quake_airaccel_sideways_friction 0
+set g_physics_quake_aircontrol 0
+set g_physics_quake_aircontrol_power 2
+set g_physics_quake_aircontrol_penalty 0
+set g_physics_quake_warsowbunny_airforwardaccel 1.00001
+set g_physics_quake_warsowbunny_topspeed 925
+set g_physics_quake_warsowbunny_accel 0.1593
+set g_physics_quake_warsowbunny_backtosideratio 0.8
+set g_physics_quake_friction 4
+set g_physics_quake_accelerate 10
+set g_physics_quake_stopspeed 100
+set g_physics_quake_airaccelerate 106.66666666666666666666
+set g_physics_quake_airstopaccelerate 0
+
+// ========
+// Warsow
+// ========
+set g_physics_warsow_airaccel_qw 1
+set g_physics_warsow_airstrafeaccel_qw 0
+set g_physics_warsow_airspeedlimit_nonqw 0
+set g_physics_warsow_maxspeed 320
+set g_physics_warsow_jumpvelocity 280
+set g_physics_warsow_maxairstrafespeed 30
+set g_physics_warsow_maxairspeed 320
+set g_physics_warsow_airstrafeaccelerate 70
+set g_physics_warsow_warsowbunny_turnaccel 9
+set g_physics_warsow_airaccel_qw_stretchfactor 0
+set g_physics_warsow_airaccel_sideways_friction 0
+set g_physics_warsow_aircontrol 0
+set g_physics_warsow_aircontrol_power 2
+set g_physics_warsow_aircontrol_penalty 0
+set g_physics_warsow_warsowbunny_airforwardaccel 1.00001
+set g_physics_warsow_warsowbunny_topspeed 925
+set g_physics_warsow_warsowbunny_accel 0.1593
+set g_physics_warsow_warsowbunny_backtosideratio 0.8
+set g_physics_warsow_friction 8
+set g_physics_warsow_accelerate 15
+set g_physics_warsow_stopspeed 100
+set g_physics_warsow_airaccelerate 1
+set g_physics_warsow_airstopaccelerate 2.5
+
+// ========
+// DeFrag
+// ========
+set g_physics_defrag_airaccel_qw 0.95
+set g_physics_defrag_airstrafeaccel_qw 1
+set g_physics_defrag_airspeedlimit_nonqw 0
+set g_physics_defrag_maxspeed 320
+set g_physics_defrag_jumpvelocity 270
+set g_physics_defrag_maxairstrafespeed 30
+set g_physics_defrag_maxairspeed 320
+set g_physics_defrag_airstrafeaccelerate 70
+set g_physics_defrag_warsowbunny_turnaccel 0
+set g_physics_defrag_airaccel_qw_stretchfactor 0
+set g_physics_defrag_airaccel_sideways_friction 0
+set g_physics_defrag_aircontrol 150
+set g_physics_defrag_aircontrol_power 2
+set g_physics_defrag_aircontrol_penalty 0
+set g_physics_defrag_warsowbunny_airforwardaccel 1.00001
+set g_physics_defrag_warsowbunny_topspeed 925
+set g_physics_defrag_warsowbunny_accel 0.1593
+set g_physics_defrag_warsowbunny_backtosideratio 0.8
+set g_physics_defrag_friction 5.8
+set g_physics_defrag_accelerate 15
+set g_physics_defrag_stopspeed 100
+set g_physics_defrag_airaccelerate 1
+set g_physics_defrag_airstopaccelerate 2.5
+
+// =========
+// Quake 3
+// =========
+set g_physics_quake3_airaccel_qw 1
+set g_physics_quake3_airstrafeaccel_qw 0
+set g_physics_quake3_airspeedlimit_nonqw 0
+set g_physics_quake3_maxspeed 320
+set g_physics_quake3_jumpvelocity 270
+set g_physics_quake3_maxairstrafespeed 0
+set g_physics_quake3_maxairspeed 320
+set g_physics_quake3_airstrafeaccelerate 0
+set g_physics_quake3_warsowbunny_turnaccel 0
+set g_physics_quake3_airaccel_qw_stretchfactor 0
+set g_physics_quake3_airaccel_sideways_friction 0
+set g_physics_quake3_aircontrol 0
+set g_physics_quake3_aircontrol_power 2
+set g_physics_quake3_aircontrol_penalty 0
+set g_physics_quake3_warsowbunny_airforwardaccel 1.00001
+set g_physics_quake3_warsowbunny_topspeed 925
+set g_physics_quake3_warsowbunny_accel 0.1593
+set g_physics_quake3_warsowbunny_backtosideratio 0.8
+set g_physics_quake3_friction 6
+set g_physics_quake3_accelerate 10
+set g_physics_quake3_stopspeed 100
+set g_physics_quake3_airaccelerate 1
+set g_physics_quake3_airstopaccelerate 0
+
+// ========
+// Vecxis
+// ========
+set g_physics_vecxis_airaccel_qw 0.93
+set g_physics_vecxis_airstrafeaccel_qw 0
+set g_physics_vecxis_airspeedlimit_nonqw 0
+set g_physics_vecxis_maxspeed 400
+set g_physics_vecxis_jumpvelocity 300 "333 to match xonotic physics"
+set g_physics_vecxis_maxairstrafespeed 0
+set g_physics_vecxis_maxairspeed 220
+set g_physics_vecxis_airstrafeaccelerate 0
+set g_physics_vecxis_warsowbunny_turnaccel 0
+set g_physics_vecxis_airaccel_qw_stretchfactor 0
+set g_physics_vecxis_airaccel_sideways_friction 0.3
+set g_physics_vecxis_aircontrol 0
+set g_physics_vecxis_aircontrol_power 2
+set g_physics_vecxis_aircontrol_penalty 0
+set g_physics_vecxis_warsowbunny_airforwardaccel 1.00001
+set g_physics_vecxis_warsowbunny_topspeed 925
+set g_physics_vecxis_warsowbunny_accel 0.1593
+set g_physics_vecxis_warsowbunny_backtosideratio 0.8
+set g_physics_vecxis_friction 5
+set g_physics_vecxis_accelerate 5.5
+set g_physics_vecxis_stopspeed 100
+set g_physics_vecxis_airaccelerate 5.5
+set g_physics_vecxis_airstopaccelerate 0
+
+// =========
+// Quake 2
+// =========
+set g_physics_quake2_airaccel_qw 1
+set g_physics_quake2_airstrafeaccel_qw 0
+set g_physics_quake2_airspeedlimit_nonqw 0
+set g_physics_quake2_maxspeed 300
+set g_physics_quake2_jumpvelocity 270
+set g_physics_quake2_maxairstrafespeed 0
+set g_physics_quake2_maxairspeed 300
+set g_physics_quake2_airstrafeaccelerate 0
+set g_physics_quake2_warsowbunny_turnaccel 0
+set g_physics_quake2_airaccel_qw_stretchfactor 0
+set g_physics_quake2_airaccel_sideways_friction 0
+set g_physics_quake2_aircontrol 0
+set g_physics_quake2_aircontrol_power 2
+set g_physics_quake2_aircontrol_penalty 0
+set g_physics_quake2_warsowbunny_airforwardaccel 1.00001
+set g_physics_quake2_warsowbunny_topspeed 925
+set g_physics_quake2_warsowbunny_accel 0.1593
+set g_physics_quake2_warsowbunny_backtosideratio 0.8
+set g_physics_quake2_friction 6
+set g_physics_quake2_accelerate 10
+set g_physics_quake2_stopspeed 100
+set g_physics_quake2_airaccelerate 1
+set g_physics_quake2_airstopaccelerate 0
+
+// =======
+// Bones
+// =======
+set g_physics_bones_airaccel_qw 1
+set g_physics_bones_airstrafeaccel_qw 1
+set g_physics_bones_airspeedlimit_nonqw 0
+set g_physics_bones_maxspeed 320
+set g_physics_bones_jumpvelocity 270
+set g_physics_bones_maxairstrafespeed 30
+set g_physics_bones_maxairspeed 320
+set g_physics_bones_airstrafeaccelerate 70
+set g_physics_bones_warsowbunny_turnaccel 0
+set g_physics_bones_airaccel_qw_stretchfactor 0
+set g_physics_bones_airaccel_sideways_friction 0
+set g_physics_bones_aircontrol 150
+set g_physics_bones_aircontrol_power 2
+set g_physics_bones_aircontrol_penalty 0
+set g_physics_bones_warsowbunny_airforwardaccel 1.00001
+set g_physics_bones_warsowbunny_topspeed 925
+set g_physics_bones_warsowbunny_accel 0.1593
+set g_physics_bones_warsowbunny_backtosideratio 0.8
+set g_physics_bones_friction 5.97
+set g_physics_bones_accelerate 15
+set g_physics_bones_stopspeed 100
+set g_physics_bones_airaccelerate 1
+set g_physics_bones_airstopaccelerate 2.5
sv_warsowbunny_topspeed 925
sv_warsowbunny_backtosideratio 0.8
sv_friction_on_land 0
+sv_friction_slick 0.5
sv_doublejump 0
sv_jumpspeedcap_min ""
sv_jumpspeedcap_max ""
sv_warsowbunny_topspeed 925
sv_warsowbunny_backtosideratio 0.8
sv_friction_on_land 0
+sv_friction_slick 0.5
sv_doublejump 0
sv_jumpspeedcap_min ""
sv_jumpspeedcap_max ""
sv_warsowbunny_topspeed 925
sv_warsowbunny_backtosideratio 0.8
sv_friction_on_land 0
+sv_friction_slick 0.5
sv_doublejump 0
sv_jumpspeedcap_min ""
sv_jumpspeedcap_max ""
sv_warsowbunny_topspeed 925
sv_warsowbunny_backtosideratio 0.8
sv_friction_on_land 0
+sv_friction_slick 0.5
sv_doublejump 1
sv_jumpspeedcap_min 0
sv_jumpspeedcap_max 0.5
sv_warsowbunny_topspeed 925
sv_warsowbunny_backtosideratio 0.8
sv_friction_on_land 0
+sv_friction_slick 0.5
sv_doublejump 0
sv_jumpspeedcap_min ""
sv_jumpspeedcap_max ""
-Werror -fno-bail-on-werror -Wall \
-fftepp -fftepp-predefs -Wcpp -futf8 \
$(QCCFLAGS_WTFS) \
+ $(QCCFLAGS_FEATURES) \
$(QCCFLAGS_EXTRA) $(QCCFLAGS_WATERMARK)
+QCCFLAGS_FEATURES ?= \
+ -DVEHICLES_ENABLED=1 \
+ -DVEHICLES_USE_ODE=0
+
# xonotic build system overrides this by command line argument to turn off the update-cvarcount step
XON_BUILDSYSTEM =
--- /dev/null
+#ifndef CLIENT_ALL_H
+#define CLIENT_ALL_H
+
+#include "autocvars.qh"
+#include "defs.qh"
+#include "main.qh"
+#include "miscfunctions.qh"
+
+#include "../dpdefs/csprogsdefs.qh"
+
+#endif
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../common/stats.qh"
- #include "../common/util.qh"
- #include "autocvars.qh"
- #include "../common/notifications.qh"
- #include "main.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "announcer.qh"
+#include "_all.qh"
+
+#include "../common/notifications.qh"
+#include "../common/stats.qh"
+#include "../common/util.qh"
bool announcer_1min;
bool announcer_5min;
--- /dev/null
+#ifndef ANNOUNCER_H
+#define ANNOUNCER_H
+
+void Announcer();
+
+#endif
float autocvar_hud_panel_notify_time;
float autocvar_hud_panel_notify_icon_aspect;
bool autocvar_hud_panel_physics;
+float autocvar_hud_panel_physics_acceleration_movingaverage = 1;
float autocvar_hud_panel_physics_acceleration_progressbar_mode;
float autocvar_hud_panel_physics_acceleration_progressbar_scale;
float autocvar_hud_panel_physics_acceleration_progressbar_nonlinear;
float autocvar_hud_panel_physics_acceleration_max;
+float autocvar_hud_panel_physics_update_interval;
int autocvar_hud_panel_physics_progressbar;
bool autocvar_hud_panel_physics_acceleration_vertical;
int autocvar_hud_panel_physics_baralign;
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "defs.qh"
- #include "../common/util.qh"
- #include "autocvars.qh"
- #include "bgmscript.qh"
- #include "main.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "bgmscript.qh"
+#include "_all.qh"
+
+#include "../common/util.qh"
#define CONSTANT_SPEED_DECAY
float bgmscriptbufsize;
float bgmscriptbufloaded;
-.float bgmscriptline;
-.float bgmscriptline0;
-.float bgmscriptvolume;
-.float bgmscripttime;
-.float bgmscriptstate;
-.float bgmscriptstatetime;
+class(BGMScript) .float bgmscriptline;
+class(BGMScript) .float bgmscriptline0;
+class(BGMScript) .float bgmscriptvolume;
+class(BGMScript) .float bgmscripttime;
+class(BGMScript) .float bgmscriptstate;
+class(BGMScript) .float bgmscriptstatetime;
float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
{
}
}
-float BGMScript(entity e)
+float doBGMScript(entity e)
{
float amp, vel;
#ifndef BGMSCRIPT_H
#define BGMSCRIPT_H
-.string bgmscript;
-.float bgmscriptattack;
-.float bgmscriptdecay;
-.float bgmscriptsustain;
-.float bgmscriptrelease;
+entityclass(BGMScript);
+class(BGMScript) .string bgmscript;
+class(BGMScript) .float bgmscriptattack;
+class(BGMScript) .float bgmscriptdecay;
+class(BGMScript) .float bgmscriptsustain;
+class(BGMScript) .float bgmscriptrelease;
-.float just_toggled;
+class(BGMScript) .float just_toggled;
+#ifdef CSQC
void BGMScript_InitEntity(entity e);
-float BGMScript(entity e);
+float doBGMScript(entity e);
+#endif
+
#endif
-#if defined(CSQC)
- #include "movetypes.qh"
- #include "prandom.qh"
- #include "rubble.qh"
+#include "casings.qh"
+#include "_all.qh"
- .float cnt;
- .float alpha;
- .int state;
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "../common/movetypes/movetypes.qh"
+#include "prandom.qh"
+#include "rubble.qh"
+#include "../common/util.qh"
-.bool silent;
+.float cnt;
+.float alpha;
+.int state;
+
+entityclass(Casing);
+class(Casing) .bool silent;
void Casing_Delete()
{
--- /dev/null
+#ifndef CASINGS_H
+#define CASINGS_H
+
+void Casings_Precache();
+
+void Ent_Casing(float isNew);
+
+#endif
--- /dev/null
+#include "../_all.qh"
+
+#include "../../common/command/all.qc"
+
+#include "cl_cmd.qc"
--- /dev/null
+#ifndef CLIENT_COMMANDS_ALL_H
+#define CLIENT_COMMANDS_ALL_H
+
+#include "../../common/command/all.qh"
+
+#include "cl_cmd.qh"
+
+#endif
// Last updated: December 28th, 2011
// ==============================================
+#include "../../common/command/command.qh"
+#include "cl_cmd.qh"
+
+#include "../autocvars.qh"
+#include "../defs.qh"
+#include "../hud.qh"
+#include "../hud_config.qh"
+#include "../main.qh"
+#include "../mapvoting.qh"
+#include "../miscfunctions.qh"
+
+#include "../../common/mapinfo.qh"
+
#include "../../common/command/generic.qh"
-#include "../../common/command/shared_defs.qh"
void DrawDebugModel()
{
}
}
+void LocalCommand_find(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ entity client;
+
+ for(client = world; (client = find(client, classname, argv(1))); )
+ print(etos(client), "\n");
+
+ return;
+ }
+
+ default:
+ print("Incorrect parameters for ^2find^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ print("\nUsage:^3 cl_cmd find classname\n");
+ print(" Where 'classname' is the classname to search for.\n");
+ return;
+ }
+ }
+}
+
void LocalCommand_sendcvar(int request, int argc)
{
switch(request)
CLIENT_COMMAND("handlevote", LocalCommand_handlevote(request, arguments), "System to handle selecting a vote or option") \
CLIENT_COMMAND("hud", LocalCommand_hud(request, arguments), "Commands regarding/controlling the HUD system") \
CLIENT_COMMAND("localprint", LocalCommand_localprint(request, arguments), "Create your own centerprint sent to yourself") \
+ CLIENT_COMMAND("find", LocalCommand_find(request, arguments), "Search through entities for matching classname") \
CLIENT_COMMAND("mv_download", LocalCommand_mv_download(request, arguments), "Retrieve mapshot picture from the server") \
CLIENT_COMMAND("sendcvar", LocalCommand_sendcvar(request, arguments), "Send a cvar to the server (like weaponpriority)") \
/* nothing */
+++ /dev/null
-// MenuQC redefines world, change define it here to be safe
-#define world world
-
-// Mask Constants (set .drawmask on entities; use R_AddEntities to add all entities based on mask)
-const int MASK_ENGINE = 1;
-const int MASK_ENGINEVIEWMODELS = 2;
-const int MASK_NORMAL = 4;
-
-// Renderflag Constants (used for CSQC entities)
-const int RF_VIEWMODEL = 1;
-const int RF_EXTERNALMODEL = 2;
-const int RF_DEPTHHACK = 4;
-const int RF_ADDITIVE = 8;
-const int RF_USEAXIS = 16;
-
-// Viewflag Constants (use with R_SetView)
-const int VF_MIN = 1; //(vector)
-const int VF_MIN_X = 2; //(float)
-const int VF_MIN_Y = 3; //(float)
-const int VF_SIZE = 4; //(vector) (viewport size)
-const int VF_SIZE_Y = 5; //(float)
-const int VF_SIZE_X = 6; //(float)
-const int VF_VIEWPORT = 7; //(vector, vector)
-const int VF_FOV = 8; //(vector)
-const int VF_FOVX = 9; //(float)
-const int VF_FOVY = 10; //(float)
-const int VF_ORIGIN = 11; //(vector)
-const int VF_ORIGIN_X = 12; //(float)
-const int VF_ORIGIN_Y = 13; //(float)
-const int VF_ORIGIN_Z = 14; //(float)
-const int VF_ANGLES = 15; //(vector)
-const int VF_ANGLES_X = 16; //(float)
-const int VF_ANGLES_Y = 17; //(float)
-const int VF_ANGLES_Z = 18; //(float)
-const int VF_DRAWWORLD = 19; //(float)
-const int VF_DRAWENGINEHUD = 20; //(float)
-const int VF_DRAWCROSSHAIR = 21; //(float)
-const int VF_PERSPECTIVE = 200; //(float)
-
-const int VF_CL_VIEWANGLES = 33; //(vector)
-const int VF_CL_VIEWANGLES_X = 34; //(float)
-const int VF_CL_VIEWANGLES_Y = 35; //(float)
-const int VF_CL_VIEWANGLES_Z = 36; //(float)
-
-// Quake-style Point Contents
-const int CONTENT_EMPTY = -1;
-const int CONTENT_SOLID = -2;
-const int CONTENT_WATER = -3;
-const int CONTENT_SLIME = -4;
-const int CONTENT_LAVA = -5;
-const int CONTENT_SKY = -6;
-
-// Vector / Hull Constants
-const vector VEC_1 = '1 1 1';
-const vector VEC_0 = '0 0 0';
-const vector VEC_M1 = '-1 -1 -1';
-
-const vector VEC_HULL_MIN = '-16 -16 -24';
-const vector VEC_HULL_MAX = '16 16 32';
-
-// Effect Constants
-const int EF_NODRAW = 16;
-const int EF_ADDITIVE = 32;
-const int EF_BLUE = 64;
-const int EF_RED = 128;
-const int EF_FULLBRIGHT = 512;
-const int EF_FLAME = 1024;
-const int EF_STARDUST = 2048;
-const int EF_NOSHADOW = 4096;
-const int EF_NODEPTHTEST = 8192;
-
-// Quake Player Flag Constants
-const int PFL_ONGROUND = 1;
-const int PFL_CROUCH = 2;
-const int PFL_DEAD = 4;
-const int PFL_GIBBED = 8;
-
-// Quake Temporary Entity Constants
-const int TE_SPIKE = 0;
-const int TE_SUPERSPIKE = 1;
-const int TE_GUNSHOT = 2;
-const int TE_EXPLOSION = 3;
-const int TE_TAREXPLOSION = 4;
-const int TE_LIGHTNING1 = 5;
-const int TE_LIGHTNING2 = 6;
-const int TE_WIZSPIKE = 7;
-const int TE_KNIGHTSPIKE = 8;
-const int TE_LIGHTNING3 = 9;
-const int TE_LAVASPLASH = 10;
-const int TE_TELEPORT = 11;
-const int TE_EXPLOSION2 = 12;
-// Darkplaces Additions
-const int TE_EXPLOSIONRGB = 53;
-const int TE_GUNSHOTQUAD = 57;
-const int TE_EXPLOSIONQUAD = 70;
-
-// Math Constants
-const int EXTRA_LOW = -99999999;
-const int EXTRA_HIGH = 99999999;
-
-// Frik File Constants
-const int FILE_READ = 0;
-const int FILE_APPEND = 1;
-const int FILE_WRITE = 2;
-
-// Button values used by input_buttons
-const int BUTTON_ATTACK = 1;
-const int BUTTON_JUMP = 2;
-const int BUTTON_3 = 4;
-const int BUTTON_4 = 8;
-const int BUTTON_5 = 16;
-const int BUTTON_6 = 32;
-const int BUTTON7 = 64;
-const int BUTTON8 = 128;
-const int BUTTON_USE = 256;
-const int BUTTON_CHAT = 512;
-const int BUTTON_PRYDONCURSOR = 1024;
-const int BUTTON_9 = 2048;
-const int BUTTON_10 = 4096;
-const int BUTTON_11 = 8192;
-const int BUTTON_12 = 16384;
-const int BUTTON_13 = 32768;
-const int BUTTON_14 = 65536;
-const int BUTTON_15 = 131072;
-const int BUTTON_16 = 262144;
-
-const int SOLID_NOT = 0; // no interaction with other objects
-const int SOLID_TRIGGER = 1; // touch on edge, but not blocking
-const int SOLID_BBOX = 2; // touch on edge, block
-const int SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
-const int SOLID_BSP = 4; // bsp clip, touch on edge, block
-const int SOLID_CORPSE = 5; // same as SOLID_BBOX, except it behaves as SOLID_NOT against SOLID_SLIDEBOX objects (players/monsters)
-
-const int MOVE_NORMAL = 0; // same as false
-const int MOVE_NOMONSTERS = 1; // same as true
-const int MOVE_MISSILE = 2; // save as movement with .movetype == MOVETYPE_FLYMISSILE
-const int MOVE_HITMODEL = 4;
-const int MOVE_WORLDONLY = 3;
-
-const int CAMERA_FREE = 1;
-const int CAMERA_CHASE = 2;
-
-const int EF_NOMODELFLAGS = 8388608;
--- /dev/null
+#ifndef CSQC_CONSTANTS
+#define CSQC_CONSTANTS
+
+// MenuQC redefines world, change define it here to be safe
+#define world world
+
+// Mask Constants (set .drawmask on entities; use R_AddEntities to add all entities based on mask)
+const int MASK_ENGINE = 1;
+const int MASK_ENGINEVIEWMODELS = 2;
+const int MASK_NORMAL = 4;
+
+// Renderflag Constants (used for CSQC entities)
+const int RF_VIEWMODEL = 1;
+const int RF_EXTERNALMODEL = 2;
+const int RF_DEPTHHACK = 4;
+const int RF_ADDITIVE = 8;
+const int RF_USEAXIS = 16;
+
+// Viewflag Constants (use with R_SetView)
+const int VF_MIN = 1; //(vector)
+const int VF_MIN_X = 2; //(float)
+const int VF_MIN_Y = 3; //(float)
+const int VF_SIZE = 4; //(vector) (viewport size)
+const int VF_SIZE_Y = 5; //(float)
+const int VF_SIZE_X = 6; //(float)
+const int VF_VIEWPORT = 7; //(vector, vector)
+const int VF_FOV = 8; //(vector)
+const int VF_FOVX = 9; //(float)
+const int VF_FOVY = 10; //(float)
+const int VF_ORIGIN = 11; //(vector)
+const int VF_ORIGIN_X = 12; //(float)
+const int VF_ORIGIN_Y = 13; //(float)
+const int VF_ORIGIN_Z = 14; //(float)
+const int VF_ANGLES = 15; //(vector)
+const int VF_ANGLES_X = 16; //(float)
+const int VF_ANGLES_Y = 17; //(float)
+const int VF_ANGLES_Z = 18; //(float)
+const int VF_DRAWWORLD = 19; //(float)
+const int VF_DRAWENGINEHUD = 20; //(float)
+const int VF_DRAWCROSSHAIR = 21; //(float)
+const int VF_PERSPECTIVE = 200; //(float)
+
+const int VF_CL_VIEWANGLES = 33; //(vector)
+const int VF_CL_VIEWANGLES_X = 34; //(float)
+const int VF_CL_VIEWANGLES_Y = 35; //(float)
+const int VF_CL_VIEWANGLES_Z = 36; //(float)
+
+// Quake-style Point Contents
+const int CONTENT_EMPTY = -1;
+const int CONTENT_SOLID = -2;
+const int CONTENT_WATER = -3;
+const int CONTENT_SLIME = -4;
+const int CONTENT_LAVA = -5;
+const int CONTENT_SKY = -6;
+
+// Vector / Hull Constants
+const vector VEC_1 = '1 1 1';
+const vector VEC_0 = '0 0 0';
+const vector VEC_M1 = '-1 -1 -1';
+
+const vector VEC_HULL_MIN = '-16 -16 -24';
+const vector VEC_HULL_MAX = '16 16 32';
+
+// Effect Constants
+const int EF_NODRAW = 16;
+const int EF_ADDITIVE = 32;
+const int EF_BLUE = 64;
+const int EF_RED = 128;
+const int EF_FULLBRIGHT = 512;
+const int EF_FLAME = 1024;
+const int EF_STARDUST = 2048;
+const int EF_NOSHADOW = 4096;
+const int EF_NODEPTHTEST = 8192;
+
+// Quake Player Flag Constants
+const int PFL_ONGROUND = 1;
+const int PFL_CROUCH = 2;
+const int PFL_DEAD = 4;
+const int PFL_GIBBED = 8;
+
+// Quake Temporary Entity Constants
+const int TE_SPIKE = 0;
+const int TE_SUPERSPIKE = 1;
+const int TE_GUNSHOT = 2;
+const int TE_EXPLOSION = 3;
+const int TE_TAREXPLOSION = 4;
+const int TE_LIGHTNING1 = 5;
+const int TE_LIGHTNING2 = 6;
+const int TE_WIZSPIKE = 7;
+const int TE_KNIGHTSPIKE = 8;
+const int TE_LIGHTNING3 = 9;
+const int TE_LAVASPLASH = 10;
+const int TE_TELEPORT = 11;
+const int TE_EXPLOSION2 = 12;
+// Darkplaces Additions
+const int TE_EXPLOSIONRGB = 53;
+const int TE_GUNSHOTQUAD = 57;
+const int TE_EXPLOSIONQUAD = 70;
+
+// Math Constants
+const int EXTRA_LOW = -99999999;
+const int EXTRA_HIGH = 99999999;
+
+// Frik File Constants
+const int FILE_READ = 0;
+const int FILE_APPEND = 1;
+const int FILE_WRITE = 2;
+
+// Button values used by input_buttons
+const int BUTTON_ATTACK = 1;
+const int BUTTON_JUMP = 2;
+const int BUTTON_3 = 4;
+const int BUTTON_4 = 8;
+const int BUTTON_5 = 16;
+const int BUTTON_6 = 32;
+const int BUTTON7 = 64;
+const int BUTTON8 = 128;
+const int BUTTON_USE = 256;
+const int BUTTON_CHAT = 512;
+const int BUTTON_PRYDONCURSOR = 1024;
+const int BUTTON_9 = 2048;
+const int BUTTON_10 = 4096;
+const int BUTTON_11 = 8192;
+const int BUTTON_12 = 16384;
+const int BUTTON_13 = 32768;
+const int BUTTON_14 = 65536;
+const int BUTTON_15 = 131072;
+const int BUTTON_16 = 262144;
+
+const int SOLID_NOT = 0; // no interaction with other objects
+const int SOLID_TRIGGER = 1; // touch on edge, but not blocking
+const int SOLID_BBOX = 2; // touch on edge, block
+const int SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
+const int SOLID_BSP = 4; // bsp clip, touch on edge, block
+const int SOLID_CORPSE = 5; // same as SOLID_BBOX, except it behaves as SOLID_NOT against SOLID_SLIDEBOX objects (players/monsters)
+
+const int MOVE_NORMAL = 0; // same as false
+const int MOVE_NOMONSTERS = 1; // same as true
+const int MOVE_MISSILE = 2; // save as movement with .movetype == MOVETYPE_FLYMISSILE
+const int MOVE_HITMODEL = 4;
+const int MOVE_WORLDONLY = 3;
+
+const int CAMERA_FREE = 1;
+const int CAMERA_CHASE = 2;
+
+const int EF_NOMODELFLAGS = 8388608;
+
+#endif
-#if defined(CSQC)
- #include "gibs.qh"
- #include "miscfunctions.qh"
- #include "player_skeleton.qh"
- #include "sortlist.qh"
+#include "csqcmodel_hooks.qh"
+#include "_all.qh"
- #include "../client/weapons/projectile.qh"
+#include "gibs.qh"
+#include "player_skeleton.qh"
+#include "sortlist.qh"
- #include "../common/animdecide.qh"
- #include "../common/csqcmodel_settings.qh"
+#include "weapons/projectile.qh"
- #include "../csqcmodellib/cl_model.qh"
- #include "../csqcmodellib/cl_player.qh"
- #include "../csqcmodellib/interpolate.qh"
+#include "../common/animdecide.qh"
+#include "../common/csqcmodel_settings.qh"
+#include "../common/teams.qh"
- #include "../warpzonelib/mathlib.qh"
+#include "../csqcmodellib/cl_model.qh"
+#include "../csqcmodellib/cl_player.qh"
+#include "../csqcmodellib/interpolate.qh"
- .float death_time;
- .int modelflags;
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "../warpzonelib/mathlib.qh"
+.float death_time;
+.int modelflags;
void CSQCModel_Hook_PreDraw(bool isplayer);
bool onground = 0;
if(self == csqcplayer)
{
- if(self.pmove_flags & PMF_ONGROUND)
+ if(self.flags & FL_ONGROUND)
onground = 1;
- self.anim_prev_pmove_flags = self.pmove_flags;
- if(self.pmove_flags & PMF_DUCKED)
+ self.anim_prev_pmove_flags = self.flags;
+ if(self.flags & FL_DUCKED)
animdecide_setstate(self, self.anim_state | ANIMSTATE_DUCK, false);
else if(self.anim_state & ANIMSTATE_DUCK)
animdecide_setstate(self, self.anim_state - ANIMSTATE_DUCK, false);
--- /dev/null
+#ifndef CSQCMODEL_HOOKS
+#define CSQCMODEL_HOOKS
+
+void CSQCPlayer_Precache();
+
+#endif
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "defs.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
- #include "autocvars.qh"
- #include "../common/deathtypes.qh"
- #include "damage.qh"
- #include "movetypes.qh"
- #include "prandom.qh"
- #include "vehicles/vehicles.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "damage.qh"
+#include "_all.qh"
+
+#include "gibs.qh"
+#include "prandom.qh"
+
+#include "vehicles/all.qh"
+
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/movetypes/movetypes.qh"
+#include "../common/util.qh"
+
+#include "../common/weapons/all.qh"
+
+.entity tag_entity;
+
+.float cnt;
+.int state;
+.bool isplayermodel;
void DamageEffect_Think()
{
pointparticles(self.team, org, '0 0 0', 1);
}
-void DamageEffect(vector hitorg, float dmg, int type, int specnum)
+void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
{
// particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
return; // allow a single damage on non-skeletal models
}
- life = bound(autocvar_cl_damageeffect_lifetime_min, dmg * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
+ life = bound(autocvar_cl_damageeffect_lifetime_min, thedamage * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
effectname = get_weaponinfo(DEATH_WEAPONOF(type)).netname;
void Ent_DamageInfo(float isNew)
{
- float dmg, rad, edge, thisdmg;
+ float thedamage, rad, edge, thisdmg;
bool hitplayer = false;
int species, forcemul;
vector force, thisforce;
w_org.y = ReadCoord();
w_org.z = ReadCoord();
- dmg = ReadByte();
+ thedamage = ReadByte();
rad = ReadByte();
edge = ReadByte();
force = decompressShortVector(ReadShort());
continue;
if(thisdmg < 0)
thisdmg = 0;
- if(dmg)
+ if(thedamage)
{
- thisdmg = dmg + (edge - dmg) * thisdmg;
- thisforce = forcemul * vlen(force) * (thisdmg / dmg) * normalize(self.origin - w_org);
+ thisdmg = thedamage + (edge - thedamage) * thisdmg;
+ thisforce = forcemul * vlen(force) * (thisdmg / thedamage) * normalize(self.origin - w_org);
}
else
{
if(vlen(nearest - w_org) > bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS))
continue;
- thisdmg = dmg;
+ thisdmg = thedamage;
thisforce = forcemul * force;
}
#define DAMAGE_H
.float total_damages; // number of effects which currently are attached to a player
+
+void Ent_DamageInfo(float isNew);
+
#endif
-#ifndef DEFS_H
-#define DEFS_H
+#ifndef CLIENT_DEFS_H
+#define CLIENT_DEFS_H
// Additional OPTIONAL Fields and Globals
//float intermission;
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "autocvars.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "effects.qh"
+#include "_all.qh"
/*
.vector fx_start;
.string fx_texture;
.float fx_lifetime;
-void SUB_Remove()
-{ remove(self); }
-
void b_draw()
{
//Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin);
--- /dev/null
+#ifndef EFFECTS_H
+#define EFFECTS_H
+
+void Net_ReadArc();
+
+#endif
#include "gibs.qh"
+#include "_all.qh"
+
+#include "prandom.qh"
+#include "rubble.qh"
+
+#include "../common/constants.qh"
+#include "../common/movetypes/movetypes.qh"
+#include "../common/util.qh"
+
+.float scale;
+.float alpha;
+.float cnt;
+.float gravity;
void Gib_Delete()
{
+#include "hook.qh"
+#include "_all.qh"
+
#include "hud.qh"
#include "noise.qh"
+
+#include "../common/teams.qh"
+
+#include "../csqcmodellib/interpolate.qh"
+
#include "../warpzonelib/common.qh"
+#include "../warpzonelib/mathlib.qh"
-.float HookType; // ENT_CLIENT_*
-.vector origin;
-.vector velocity;
-.float HookSilent;
-.float HookRange;
+entityclass(Hook);
+class(Hook) .float HookType; // ENT_CLIENT_*
+class(Hook) .vector origin;
+class(Hook) .vector velocity;
+class(Hook) .float HookSilent;
+class(Hook) .float HookRange;
void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
{
Draw_GrapplingHook_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
}
-.float teleport_time;
+class(Hook) .float teleport_time;
void Draw_GrapplingHook()
{
vector a, b, atrans;
--- /dev/null
+#ifndef HOOK_H
+#define HOOK_H
+
+void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg);
+void Hook_Precache();
+
+void Ent_ReadHook(float bIsNew, float type);
+
+#endif
+#include "hud.qh"
+#include "_all.qh"
+
+#include "hud_config.qh"
#include "scoreboard.qh"
+#include "sortlist.qh"
#include "teamradar.qh"
+#include "t_items.qh"
+
#include "../common/buffs.qh"
+#include "../common/constants.qh"
#include "../common/counting.qh"
+#include "../common/deathtypes.qh"
#include "../common/mapinfo.qh"
#include "../common/nades.qh"
-#include "../server/t_items.qh"
+#include "../common/stats.qh"
+
+#include "../csqcmodellib/cl_player.qh"
+
+#include "../warpzonelib/mathlib.qh"
/*
==================
return color;
}
-float HUD_GetRowCount(float item_count, vector size, float item_aspect)
+float HUD_GetRowCount(int item_count, vector size, float item_aspect)
{
float aspect = size_y / size_x;
return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
}
-vector HUD_GetTableSize(float item_count, vector psize, float item_aspect)
+vector HUD_GetTableSize(int item_count, vector psize, float item_aspect)
{
float columns, rows;
float ratio, best_ratio = 0;
return stringwidth(s, false, theSize);
}
-void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag)
+void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
{
position.x -= 2 / 3 * strlen(text) * theScale.x;
drawstring(position, text, theScale, rgb, theAlpha, flag);
}
-void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag)
+void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
{
position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
drawstring(position, text, theScale, rgb, theAlpha, flag);
}
// return the string of the onscreen race timer
-string MakeRaceString(float cp, float mytime, float histime, float lapdelta, string hisname)
+string MakeRaceString(int cp, float mytime, float theirtime, float lapdelta, string theirname)
{
string col;
string timestr;
string lapstr;
lapstr = "";
- if(histime == 0) // goal hit
+ if(theirtime == 0) // goal hit
{
if(mytime > 0)
{
col = "^1";
}
}
- else if(histime > 0) // anticipation
+ else if(theirtime > 0) // anticipation
{
- if(mytime >= histime)
- timestr = strcat("+", ftos_decimals(mytime - histime, TIME_DECIMALS));
+ if(mytime >= theirtime)
+ timestr = strcat("+", ftos_decimals(mytime - theirtime, TIME_DECIMALS));
else
- timestr = TIME_ENCODED_TOSTRING(TIME_ENCODE(histime));
+ timestr = TIME_ENCODED_TOSTRING(TIME_ENCODE(theirtime));
col = "^3";
}
else
else
cpname = _("Finish line");
- if(histime < 0)
+ if(theirtime < 0)
return strcat(col, cpname);
- else if(hisname == "")
+ else if(theirname == "")
return strcat(col, sprintf("%s (%s)", cpname, timestr));
else
- return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(hisname, col, lapstr)));
+ return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(theirname, col, lapstr)));
}
// Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
-float race_CheckName(string net_name) {
- float i;
+int race_CheckName(string net_name)
+{
+ int i;
for (i=RANKINGS_CNT-1;i>=0;--i)
if(grecordholder[i] == net_name)
return i+1;
return 0;
}
-float GetPlayerColorForce(int i)
+int GetPlayerColorForce(int i)
{
if(!teamplay)
return 0;
return stof(getplayerkeyvalue(i, "colors")) & 15;
}
-float GetPlayerColor(int i)
+int GetPlayerColor(int i)
{
if(!playerslots[i].gotscores) // unconnected
return NUM_SPECTATOR;
} while(0)
//basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
-void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, float vertical, float baralign, vector theColor, float theAlpha, float drawflag)
+void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
{
if(!length_ratio || !theAlpha)
return;
}
}
-void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, float drawflag)
+void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
{
if(!theAlpha)
return;
}
string weaponorder_cmp_str;
-float weaponorder_cmp(float i, float j, entity pass)
+int weaponorder_cmp(int i, int j, entity pass)
{
- float ai, aj;
+ int ai, aj;
ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].weapon), 0);
aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].weapon), 0);
return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
{
// declarations
WepSet weapons_stat = WepSet_GetFromStat();
- float i, f, a;
+ int i;
+ float f, a;
float screen_ar;
vector center = '0 0 0';
- float weapon_count, weapon_id;
- float row, column, rows = 0, columns = 0;
+ int weapon_count, weapon_id;
+ int row, column, rows = 0, columns = 0;
bool vertical_order = true;
float aspect = autocvar_hud_panel_weapons_aspect;
// update generic hud functions
HUD_Panel_UpdateCvars();
- draw_beginBoldFont();
-
// figure out weapon order (how the weapons are sorted) // TODO make this configurable
if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
{
// might as well commit suicide now, no reason to live ;)
if (weapon_count == 0)
- {
- draw_endBoldFont();
return;
- }
vector old_panel_size = panel_size;
vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
if(padded_panel_size.x / padded_panel_size.y < aspect)
{
// maximum number of rows that allows to display items with the desired aspect ratio
- float max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
+ int max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
columns = min(columns, ceil(weapon_count / max_rows));
rows = ceil(weapon_count / columns);
weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
}
else
{
- float max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
+ int max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
rows = min(rows, ceil(weapon_count / max_columns));
columns = ceil(weapon_count / rows);
weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
HUD_Panel_DrawBg(1);
if(center.x == -1)
- {
- draw_endBoldFont();
return;
- }
if(panel_bg_padding)
{
}
}
}
-
- draw_endBoldFont();
}
// Ammo (#1)
}
-void DrawAmmoNades(vector myPos, vector mySize, float draw_expanding, float expand_time)
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
{
float theAlpha = 1, a, b;
vector nade_color, picpos, numpos;
}
}
-void DrawAmmoItem(vector myPos, vector mySize, .float ammoType, float isCurrent, float isInfinite)
+void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
{
if(ammoType == ammo_none)
return;
// Initialize variables
- float ammo;
+ int ammo;
if(autocvar__hud_configure)
{
isCurrent = (ammoType == ammo_rockets); // Rockets always current
textPos = myPos + eX * mySize.y;
}
- float isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
+ bool isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
vector iconColor = isShadowed ? '0 0 0' : '1 1 1';
vector textColor;
drawpic_aspect_skin(iconPos, GetAmmoPicture(ammoType), '1 1 0' * mySize.y, iconColor, alpha, DRAWFLAG_NORMAL);
}
-float nade_prevstatus;
-float nade_prevframe;
+int nade_prevstatus;
+int nade_prevframe;
float nade_statuschange_time;
void HUD_Ammo(void)
{
mySize -= '2 2 0' * panel_bg_padding;
}
- float rows = 0, columns, row, column;
+ int rows = 0, columns, row, column;
float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
- float draw_nades = (nade_cnt > 0 || nade_score > 0), nade_statuschange_elapsedtime;
- float total_ammo_count;
+ bool draw_nades = (nade_cnt > 0 || nade_score > 0);
+ float nade_statuschange_elapsedtime;
+ int total_ammo_count;
vector ammo_size;
if (autocvar_hud_panel_ammo_onlycurrent)
ammo_size.y = newSize;
}
- float i;
- float infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
+ int i;
+ bool infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
row = column = 0;
if(autocvar_hud_panel_ammo_onlycurrent)
{
}
else
{
- .float ammotype;
+ .int ammotype;
row = column = 0;
for(i = 0; i < AMMO_COUNT; ++i)
{
draw_endBoldFont();
}
-void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, float vertical, float icon_right_align, vector color, float theAlpha, float fadelerp)
+void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha, float fadelerp)
{
vector newPos = '0 0 0', newSize = '0 0 0';
vector picpos, numpos;
drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
}
-void DrawNumIcon(vector myPos, vector mySize, float x, string icon, float vertical, float icon_right_align, vector color, float theAlpha)
+void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha)
{
DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
}
}
float panel_ar = mySize.x/mySize.y;
- float is_vertical = (panel_ar < 1);
+ bool is_vertical = (panel_ar < 1);
vector shield_offset = '0 0 0', strength_offset = '0 0 0', superweapons_offset = '0 0 0';
- float superweapons_is = -1;
+ int superweapons_is = -1;
if(superweapons_time)
{
}
}
- float shield_baralign, strength_baralign, superweapons_baralign;
- float shield_iconalign, strength_iconalign, superweapons_iconalign;
+ bool shield_baralign, strength_baralign, superweapons_baralign;
+ bool shield_iconalign, strength_iconalign, superweapons_iconalign;
if (autocvar_hud_panel_powerups_flip)
{
// Health/armor (#3)
//
-// prev_* vars contain the health/armor at the previous FRAME
-// set to -1 when player is dead or was not playing
-float prev_health, prev_armor;
-float health_damagetime, armor_damagetime;
-float health_beforedamage, armor_beforedamage;
-// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
-float old_p_health, old_p_armor;
-float old_p_healthtime, old_p_armortime;
-// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
-// set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
-float prev_p_health, prev_p_armor;
void HUD_HealthArmor(void)
{
- float armor, health, fuel;
+ int armor, health, fuel;
if(!autocvar__hud_configure)
{
if(!autocvar_hud_panel_healtharmor) return;
}
HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
vector pos, mySize;
pos = panel_pos;
mySize = panel_size;
mySize -= '2 2 0' * panel_bg_padding;
}
- float baralign = autocvar_hud_panel_healtharmor_baralign;
- float iconalign = autocvar_hud_panel_healtharmor_iconalign;
+ int baralign = autocvar_hud_panel_healtharmor_baralign;
+ int iconalign = autocvar_hud_panel_healtharmor_iconalign;
- float maxhealth = autocvar_hud_panel_healtharmor_maxhealth;
- float maxarmor = autocvar_hud_panel_healtharmor_maxarmor;
+ int maxhealth = autocvar_hud_panel_healtharmor_maxhealth;
+ int maxarmor = autocvar_hud_panel_healtharmor_maxarmor;
if(autocvar_hud_panel_healtharmor == 2) // combined health and armor display
{
vector v;
else
{
float panel_ar = mySize.x/mySize.y;
- float is_vertical = (panel_ar < 1);
+ bool is_vertical = (panel_ar < 1);
vector health_offset = '0 0 0', armor_offset = '0 0 0';
if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
{
armor_offset.y = mySize.y;
}
- float health_baralign, armor_baralign, fuel_baralign;
- float health_iconalign, armor_iconalign;
+ bool health_baralign, armor_baralign, fuel_baralign;
+ bool health_iconalign, armor_iconalign;
if (autocvar_hud_panel_healtharmor_flip)
{
armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
}
}
+
+ draw_endBoldFont();
}
// Notification area (#4)
float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
- float entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
+ int entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
float entry_height = size.y / entry_count;
float panel_width_half = size.x * 0.5;
vector attacker_pos, victim_pos, icon_pos;
string attacker, victim, icon;
- float i, j, count, step, limit, alpha;
+ int i, j, count, step, limit;
+ float alpha;
if (autocvar_hud_panel_notify_flip)
{
mySize -= '2 2 0' * panel_bg_padding;
}
- float color2;
+ int color2;
entity tm;
float scale2d, normalsize, bigsize;
{
float score;
entity tm = world, pl;
- float SCOREPANEL_MAX_ENTRIES = 6;
+ int SCOREPANEL_MAX_ENTRIES = 6;
float SCOREPANEL_ASPECTRATIO = 2;
- float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
+ int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
vector fontsize = '1 1 0' * (mySize.y/entries);
vector rgb, score_color;
float name_size = mySize.x*0.75;
float spacing_size = mySize.x*0.04;
const float highlight_alpha = 0.2;
- float i = 0, me_printed = 0, first_pl = 0;
+ int i = 0, first_pl = 0;
+ bool me_printed = false;
string s;
if (autocvar__hud_configure)
{
{
if (i == first_pl)
rgb = '0 1 0'; //first: green
- me_printed = 1;
+ me_printed = true;
drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
}
if (team_count)
HUD_Panel_UpdateCvars();
- draw_beginBoldFont();
-
vector pos, mySize;
pos = panel_pos;
mySize = panel_size;
if(autocvar__hud_configure)
{
s = "0:13:37";
+ draw_beginBoldFont();
drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.60 0.60 0' * mySize.y), s, '0.60 0.60 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
s = _("^1Intermediate 1 (+15.42)");
drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.60 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
s = sprintf(_("^1PENALTY: %.1f (%s)"), 2, "missing a checkpoint");
}
}
+ draw_beginBoldFont();
+
if(forcetime != "")
{
a = bound(0, (time - race_checkpointtime) / 0.5, 1);
s = TIME_ENCODED_TOSTRING(TIME_ENCODE(time + TIME_DECODE(race_penaltyaccumulator) - race_laptime));
drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.6 0.6 0' * mySize.y), s, '0.6 0.6 0' * mySize.y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
}
+
+ draw_endBoldFont();
}
else
{
}
}
}
-
- draw_endBoldFont();
}
// Vote window (#9)
//
-float vote_yescount;
-float vote_nocount;
-float vote_needed;
-float vote_highlighted; // currently selected vote
-
-float vote_active; // is there an active vote?
-float vote_prev; // previous state of vote_active to check for a change
-float vote_alpha;
-float vote_change; // "time" when vote_active changed
void HUD_Vote(void)
{
// Mod icons panel (#10)
//
-float mod_active; // is there any active mod icon?
+bool mod_active; // is there any active mod icon?
-void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, float i)
+void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
{
- float stat = -1;
+ int stat = -1;
string pic = "";
vector color = '0 0 0';
switch(i)
layout = autocvar_hud_panel_modicons_ca_layout;
else //if(gametype == MAPINFO_TYPE_FREEZETAG)
layout = autocvar_hud_panel_modicons_freezetag_layout;
- float rows, columns, aspect_ratio;
+ int rows, columns;
+ float aspect_ratio;
aspect_ratio = (layout) ? 2 : 1;
rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
columns = ceil(team_count/rows);
// CTF HUD modicon section
float redflag_prevframe, blueflag_prevframe; // status during previous frame
-float redflag_prevstatus, blueflag_prevstatus; // last remembered status
+int redflag_prevstatus, blueflag_prevstatus; // last remembered status
float redflag_statuschange_time, blueflag_statuschange_time; // time when the status changed
void HUD_Mod_CTF_Reset(void)
vector flag_size;
float f; // every function should have that
- float redflag, blueflag; // current status
+ int redflag, blueflag; // current status
float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime; // time since the status changed
- float stat_items;
+ int stat_items;
stat_items = getstati(STAT_ITEMS, 0, 24);
redflag = (stat_items/IT_RED_FLAG_TAKEN) & 3;
// Read current state
- float state = getstati(STAT_KH_KEYS);
- float i, key_state;
- float all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
+ int state = getstati(STAT_KH_KEYS);
+ int i, key_state;
+ int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
for(i = 0; i < 4; ++i)
}
// Keepaway HUD mod icon
-float kaball_prevstatus; // last remembered status
+int kaball_prevstatus; // last remembered status
float kaball_statuschange_time; // time when the status changed
// we don't need to reset for keepaway since it immediately
float BLINK_FREQ = 5;
float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
- float stat_items = getstati(STAT_ITEMS, 0, 24);
- float kaball = (stat_items/IT_KEY1) & 1;
+ int stat_items = getstati(STAT_ITEMS, 0, 24);
+ int kaball = (stat_items/IT_KEY1) & 1;
if(kaball != kaball_prevstatus)
{
// Nexball HUD mod icon
void HUD_Mod_NexBall(vector pos, vector mySize)
{
- float stat_items, nb_pb_starttime, dt, p;
+ float nb_pb_starttime, dt, p;
+ int stat_items;
stat_items = getstati(STAT_ITEMS, 0, 24);
nb_pb_starttime = getstatf(STAT_NB_METERSTART);
float srecordtime_change_time; // time when srecordtime last changed
float race_status_time;
-float race_status_prev;
+int race_status_prev;
string race_status_name_prev;
void HUD_Mod_Race(vector pos, vector mySize)
{
}
}
-void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, float i)
+void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
{
float stat = -1;
string pic = "";
mod_active = 1; // required in each mod function that always shows something
int layout = autocvar_hud_panel_modicons_dom_layout;
- float rows, columns, aspect_ratio;
+ int rows, columns;
+ float aspect_ratio;
aspect_ratio = (layout) ? 3 : 1;
rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
columns = ceil(team_count/rows);
}
}
-float mod_prev; // previous state of mod_active to check for a change
+int mod_prev; // previous state of mod_active to check for a change
float mod_alpha;
float mod_change; // "time" when mod_active changed
//
float prevfps;
float prevfps_time;
-float framecounter;
+int framecounter;
float frametimeavg;
float frametimeavg1; // 1 frame ago
//
vector acc_prevspeed;
float acc_prevtime, acc_avg, top_speed, top_speed_time;
+float physics_update_time, discrete_speed, discrete_acceleration;
void HUD_Physics(void)
{
if(!autocvar__hud_configure)
acc_prevspeed = vel;
acc_prevtime = time;
- f = bound(0, f * 10, 1);
- acc_avg = acc_avg * (1 - f) + acceleration * f;
+ if(autocvar_hud_panel_physics_acceleration_movingaverage)
+ {
+ f = bound(0, f * 10, 1);
+ acc_avg = acc_avg * (1 - f) + acceleration * f;
+ acceleration = acc_avg;
+ }
+ }
+
+ int acc_decimals = 2;
+ if(time > physics_update_time)
+ {
+ // workaround for ftos_decimals returning a negative 0
+ if(discrete_acceleration > -1 / pow(10, acc_decimals) && discrete_acceleration < 0)
+ discrete_acceleration = 0;
+ discrete_acceleration = acceleration;
+ discrete_speed = speed;
+ physics_update_time += autocvar_hud_panel_physics_update_interval;
}
//compute layout
else
acceleration_offset.y = panel_size.y;
}
- float speed_baralign, acceleration_baralign;
+ int speed_baralign, acceleration_baralign;
if (autocvar_hud_panel_physics_baralign == 1)
acceleration_baralign = speed_baralign = 1;
else if(autocvar_hud_panel_physics_baralign == 4)
//else
//tmp_offset_x = 0;
tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
- drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(discrete_speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
//draw speed unit
if (speed_baralign)
f = acceleration/autocvar_hud_panel_physics_acceleration_max;
if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
- f = sqrt(f);
+ f = (f >= 0 ? sqrt(f) : -sqrt(-f));
if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
{
HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
}
- tmp_size.x = panel_size.x;
- tmp_size.y = panel_size.y * text_scale;
- tmp_offset.x = 0;
- tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
- if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
- drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(acceleration, 2), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ if(autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
+ {
+ tmp_size.x = panel_size.x;
+ tmp_size.y = panel_size.y * text_scale;
+ tmp_offset.x = 0;
+ tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
+
+ drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(discrete_acceleration, acc_decimals), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
draw_endBoldFont();
}
// CenterPrint (#16)
//
-const float CENTERPRINT_MAX_MSGS = 10;
-const float CENTERPRINT_MAX_ENTRIES = 50;
+const int CENTERPRINT_MAX_MSGS = 10;
+const int CENTERPRINT_MAX_ENTRIES = 50;
const float CENTERPRINT_SPACING = 0.7;
-float cpm_index;
+int cpm_index;
string centerprint_messages[CENTERPRINT_MAX_MSGS];
-float centerprint_msgID[CENTERPRINT_MAX_MSGS];
+int centerprint_msgID[CENTERPRINT_MAX_MSGS];
float centerprint_time[CENTERPRINT_MAX_MSGS];
float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
-float centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
-float centerprint_showing;
+int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
+bool centerprint_showing;
-void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num)
+void centerprint_generic(int new_id, string strMessage, float duration, int countdown_num)
{
//printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
- float i, j;
+ int i, j;
if(strMessage == "" && new_id == 0)
return;
void reset_centerprint_messages(void)
{
- float i;
+ int i;
for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
{
centerprint_expire_time[i] = 0;
reset_centerprint_messages();
if (time > hud_configure_cp_generation_time)
{
- float r;
- r = random();
- if (r > 0.75)
- centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
- else if (r > 0.5)
- centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
+ if(HUD_PANEL(CENTERPRINT) == highlightedPanel)
+ {
+ float r;
+ r = random();
+ if (r > 0.8)
+ centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
+ else if (r > 0.55)
+ centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
+ else
+ centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
+ hud_configure_cp_generation_time = time + 1 + random()*4;
+ }
else
- centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
- hud_configure_cp_generation_time = time + 1 + random()*4;
+ {
+ centerprint_generic(0, sprintf("Centerprint message", seconds_tostring(time)), 10, 0);
+ hud_configure_cp_generation_time = time + 10 - random()*3;
+ }
}
}
panel_size -= '2 2 0' * panel_bg_padding;
}
- float entries, height;
+ int entries;
+ float height;
vector fontsize;
// entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
// height = panel_size_y/entries;
fontsize = '1 1 0' * height;
entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
- float i, j, k, n, g;
+ int i, j, k, n, g;
float a, sz, align, current_msg_posY = 0, msg_size;
vector pos;
string ts;
- float all_messages_expired = true;
+ bool all_messages_expired = true;
pos = panel_pos;
if (autocvar_hud_panel_centerprint_flip)
//
void HUD_Buffs(void)
{
- float buffs = getstati(STAT_BUFFS, 0, 24);
+ int buffs = getstati(STAT_BUFFS, 0, 24);
if(!autocvar__hud_configure)
{
if(!autocvar_hud_panel_buffs) return;
buffs = Buff_Type_first.items; // force first buff
}
- float b = 0; // counter to tell other functions that we have buffs
+ int b = 0; // counter to tell other functions that we have buffs
entity e;
string s = "";
for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
}
//float panel_ar = mySize_x/mySize_y;
- //float is_vertical = (panel_ar < 1);
+ //bool is_vertical = (panel_ar < 1);
//float buff_iconalign = autocvar_hud_panel_buffs_iconalign;
vector buff_offset = '0 0 0';
// draw the dock
if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
{
- float f;
+ int f;
vector color;
float hud_dock_color_team = autocvar_hud_dock_color_team;
if((teamplay) && hud_dock_color_team) {
for(i = 0; i < HUD_PANEL_NUM; ++i)
panel_order[i] = -1;
string s = "";
- float p_num, warning = false;
- float argc = tokenize_console(autocvar__hud_panelorder);
+ int p_num;
+ bool warning = false;
+ int argc = tokenize_console(autocvar__hud_panelorder);
if (argc > HUD_PANEL_NUM)
warning = true;
//first detect wrong/missing panel numbers
for(i = 0; i < HUD_PANEL_NUM; ++i) {
- p_num = stof(argv(i));
+ p_num = stoi(argv(i));
if (p_num >= 0 && p_num < HUD_PANEL_NUM) { //correct panel number?
if (panel_order[p_num] == -1) //found for the first time?
s = strcat(s, ftos(p_num), " ");
#ifndef HUD_H
#define HUD_H
-#include "../common/weapons/weapons.qh"
+#include "../common/weapons/all.qh"
const int HUD_PANEL_MAX = 24;
entity hud_panel[HUD_PANEL_MAX];
int panel_order[HUD_PANEL_MAX];
string hud_panelorder_prev;
+void HUD_Reset (void);
+void HUD_Main (void);
+
+int vote_yescount;
+int vote_nocount;
+int vote_needed;
+int vote_highlighted; // currently selected vote
+
+int vote_active; // is there an active vote?
+int vote_prev; // previous state of vote_active to check for a change
+float vote_alpha;
+float vote_change; // "time" when vote_active changed
+
float hud_draw_maximized;
float hud_panel_radar_maximized;
float chat_panel_modified;
vector panel_size_copied;
entity panel;
-.string panel_name;
-.int panel_id;
-.vector current_panel_pos;
-.vector current_panel_size;
-.string current_panel_bg;
-.float current_panel_bg_alpha;
-.float current_panel_bg_border;
-.vector current_panel_bg_color;
-.float current_panel_bg_color_team;
-.float current_panel_bg_padding;
-.float current_panel_fg_alpha;
-.float update_time;
+entityclass(HUDPanel);
+class(HUDPanel) .string panel_name;
+class(HUDPanel) .int panel_id;
+class(HUDPanel) .vector current_panel_pos;
+class(HUDPanel) .vector current_panel_size;
+class(HUDPanel) .string current_panel_bg;
+class(HUDPanel) .float current_panel_bg_alpha;
+class(HUDPanel) .float current_panel_bg_border;
+class(HUDPanel) .vector current_panel_bg_color;
+class(HUDPanel) .float current_panel_bg_color_team;
+class(HUDPanel) .float current_panel_bg_padding;
+class(HUDPanel) .float current_panel_fg_alpha;
+class(HUDPanel) .float update_time;
float panel_enabled;
vector panel_pos;
vector panel_size;
float panel_bg_padding;
string panel_bg_padding_str;
-.void() panel_draw;
+class(HUDPanel) .void() panel_draw;
float current_player;
float GetPlayerColorForce(int i);
+float stringwidth_colors(string s, vector theSize);
+int GetPlayerColor(int i);
+string GetPlayerName(int i);
+float stringwidth_nocolors(string s, vector theSize);
+void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
+
+
+// prev_* vars contain the health/armor at the previous FRAME
+// set to -1 when player is dead or was not playing
+int prev_health, prev_armor;
+float health_damagetime, armor_damagetime;
+int health_beforedamage, armor_beforedamage;
+// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
+int old_p_health, old_p_armor;
+float old_p_healthtime, old_p_armortime;
+// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
+// set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
+int prev_p_health, prev_p_armor;
+
#define HUD_PANELS(HUD_PANEL) \
HUD_PANEL(WEAPONS , HUD_Weapons , weapons) \
} while(0)
// return smoothly faded pos and size of given panel when a dialog is active
-#define HUD_Panel_UpdatePosSize_ForMenu() do { \
- vector menu_enable_pos; \
- vector menu_enable_size = '0 0 0'; \
- float menu_enable_maxsize_x = 0.3 * vid_conwidth; \
- float menu_enable_maxsize_y = 0.18 * vid_conheight; \
- if (panel_size.x > panel_size.y) { \
- if (panel_size.y > menu_enable_maxsize_y) { \
- menu_enable_size.y = menu_enable_maxsize_y; \
- menu_enable_size.x = panel_size.x * (menu_enable_maxsize_y/panel_size.y); \
- panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
- } \
- menu_enable_pos = eX * 0.5 * vid_conwidth - eX * 0.5 * panel_size.x + eY * (vid_conheight - menu_enable_maxsize_y);\
- } else { \
- if (panel_size.x > menu_enable_maxsize_x) { \
- menu_enable_size.x = menu_enable_maxsize_x; \
- menu_enable_size.y = panel_size.y * (menu_enable_maxsize_x/panel_size.x); \
- panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
- } \
- menu_enable_pos = eY * 0.5 * vid_conheight - eY * 0.5 * panel_size.y + eX * (vid_conwidth - menu_enable_maxsize_x);\
- } \
- panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos; \
+// don't center too wide panels, it doesn't work with different resolutions
+#define HUD_Panel_UpdatePosSize_ForMenu() do { \
+ vector menu_enable_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); \
+ } \
+ 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; \
} while(0)
// Scale the pos and size vectors to absolute coordinates
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "defs.qh"
- #include "../dpdefs/keycodes.qh"
- #include "../common/constants.qh"
- #include "autocvars.qh"
- #include "hud.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "hud_config.qh"
+#include "_all.qh"
+
+#include "hud.qh"
+
+#include "../common/constants.qh"
+
+#include "../dpdefs/keycodes.qh"
#define HUD_Write(s) fputs(fh, s)
{
panel = highlightedPanel;
HUD_Panel_UpdatePosSize();
- vector resizeorigin;
- resizeorigin = panel_click_resizeorigin;
+ vector resizeorigin = panel_click_resizeorigin;
vector myPos;
// minimum panel size cap
if (hudShiftState & S_ALT) // resize
{
- highlightedAction = 1;
if(nPrimary == K_UPARROW)
resizeCorner = 1;
else if(nPrimary == K_RIGHTARROW)
}
else // move
{
- highlightedAction = 2;
vector pos;
pos = panel_pos;
if(nPrimary == K_UPARROW)
if (!menu_enabled)
cvar_set("_hud_configure", "0");
}
- else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // select and highlight another panel
+ else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
{
if (bInputType == 1 || mouseClicked)
return true;
- //FIXME: if a panel is highlighted, has the same pos_x and lays in the same level
- //of other panels then next consecutive ctrl-tab will select the highlighted panel too
- //(it should only after every other panel of the hud)
- //It's a minor bug anyway, we can live with it
+ // FIXME minor bug: if a panel is highlighted, has the same pos_x and
+ // lays in the same level of another panel then the next consecutive
+ // CTRL TAB presses will reselect once more the highlighted panel
entity starting_panel;
entity old_tab_panel = tab_panel;
highlightedPanel_backup = world;
}
}
+ else if(nPrimary == 's' && hudShiftState & S_CTRL) // save config
+ {
+ if (bInputType == 1 || mouseClicked)
+ return true;
+ localcmd("hud save myconfig\n");
+ }
else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
{
if (bInputType == 1)
if (highlightedPanel)
HUD_Panel_EnableMenu();
}
- else if(hit_con_bind)
+ else if(hit_con_bind || nPrimary == K_PAUSE)
return false;
return true;
}
else
{
+ if(prevMouseClicked)
+ highlightedAction = 0;
if(menu_enabled == 2)
mouse_over_panel = 0;
else
--- /dev/null
+#ifndef HUD_CONFIG_H
+#define HUD_CONFIG_H
+
+void HUD_Panel_ExportCfg(string cfgname);
+
+void HUD_Panel_Mouse();
+
+void HUD_Configure_Frame();
+
+void HUD_Configure_PostDraw();
+
+float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
+
+#endif
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../common/buffs.qh"
- #include "../csqcmodellib/interpolate.qh"
- #include "main.qh"
- #include "../csqcmodellib/cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "laser.qh"
+#include "_all.qh"
+#include "hook.qh"
+
+#include "../common/buffs.qh"
+
+#include "../csqcmodellib/cl_model.qh"
+#include "../csqcmodellib/interpolate.qh"
// a laser goes from origin in direction angles
// it has color 'colormod'
// and stops when something is in the way
-.int cnt; // end effect
-.vector colormod;
-.int state; // on-off
-.int count; // flags for the laser
-.vector velocity;
-.float alpha;
-.float scale; // scaling factor of the thickness
-.float modelscale; // scaling factor of the dlight
+entityclass(Laser);
+class(Laser) .int cnt; // end effect
+class(Laser) .vector colormod;
+class(Laser) .int state; // on-off
+class(Laser) .int count; // flags for the laser
+class(Laser) .vector velocity;
+class(Laser) .float alpha;
+class(Laser) .float scale; // scaling factor of the thickness
+class(Laser) .float modelscale; // scaling factor of the dlight
void Draw_Laser()
{
--- /dev/null
+#ifndef LASER_H
+#define LASER_H
+
+void Ent_Laser();
+
+#endif
+#include "main.qh"
+#include "_all.qh"
+
+#include "casings.qh"
+#include "csqcmodel_hooks.qh"
+#include "damage.qh"
+#include "effects.qh"
+#include "gibs.qh"
+#include "hook.qh"
+#include "hud.qh"
+#include "hud_config.qh"
+#include "laser.qh"
#include "mapvoting.qh"
#include "modeleffects.qh"
#include "particles.qh"
+#include "prandom.qh"
#include "scoreboard.qh"
#include "shownames.qh"
-#include "target_music.qh"
+#include "sortlist.qh"
#include "tturrets.qh"
#include "tuba.qh"
+#include "t_items.qh"
#include "wall.qh"
#include "waypointsprites.qh"
-#include "vehicles/vehicles.qh"
+#include "vehicles/bumblebee.qh"
+#include "vehicles/all.qh"
-#include "../server/vehicles/bumblebee.qh"
+#include "weapons/projectile.qh"
+#include "../common/buffs.qh"
+#include "../common/deathtypes.qh"
+#include "../common/mapinfo.qh"
+#include "../common/monsters/all.qh"
+#include "../common/nades.qh"
#include "../common/net_notice.qh"
+#include "../common/notifications.qh"
+#include "../common/stats.qh"
+#include "../common/teams.qh"
-#include "../common/monsters/monsters.qh"
+#include "../common/items/all.qh"
+
+#include "../common/weapons/all.qh"
+
+#include "../csqcmodellib/cl_model.qh"
+#include "../csqcmodellib/interpolate.qh"
+
+#include "../common/triggers/include.qh"
#include "../warpzonelib/client.qh"
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
// --------------------------------------------------------------------------
// BEGIN OPTIONAL CSQC FUNCTIONS
+
void Ent_RemoveEntCS()
{
entcs_receiver[self.sv_entnum] = world;
if(is_new)
{
self.origin = spn_origin;
- setsize(self, PL_MIN, PL_MAX);
+ setsize(self, PL_MIN_CONST, PL_MAX_CONST);
droptofloor();
/*if(autocvar_cl_spawn_point_model) // needs a model first
case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break;
case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break;
+ case ENT_CLIENT_INVENTORY: Inventory_Read(self); break;
case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break;
case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break;
case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
case ENT_CLIENT_HEALING_ORB: ent_healer(); break;
+ case ENT_CLIENT_LADDER: ent_func_ladder(); break;
+ case ENT_CLIENT_TRIGGER_PUSH: ent_trigger_push(); break;
+ case ENT_CLIENT_TARGET_PUSH: ent_target_push(); break;
+ case ENT_CLIENT_CONVEYOR: ent_conveyor(); break;
+ case ENT_CLIENT_DOOR: ent_door(); break;
+ case ENT_CLIENT_PLAT: ent_plat(); break;
+ case ENT_CLIENT_SWAMP: ent_swamp(); break;
+ case ENT_CLIENT_CORNER: ent_corner(); break;
+ case ENT_CLIENT_KEYLOCK: ent_keylock(); break;
+ case ENT_CLIENT_TRAIN: ent_train(); break;
+ case ENT_CLIENT_TRIGGER_IMPULSE: ent_trigger_impulse(); break;
default:
//error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
#ifndef MAIN_H
#define MAIN_H
+#include "../common/constants.qh"
+
// --------------------------------------------------------------------------
// MENU Functionality
float zoomin_effect;
float warmup_stage;
+void Fog_Force();
+
string getcommandkey(string text, string command);
string vote_called_vote;
#include "mapvoting.qh"
+#include "_all.qh"
+
+#include "hud.qh"
#include "scoreboard.qh"
+#include "../common/mapinfo.qh"
+#include "../common/util.qh"
+
+#include "../dpdefs/keycodes.qh"
+
+
+int mv_num_maps;
+
+float mv_active;
+string mv_maps[MAPVOTE_COUNT];
+string mv_pics[MAPVOTE_COUNT];
+string mv_pk3[MAPVOTE_COUNT]; // map pk3 name or gametype human readable name
+string mv_desc[MAPVOTE_COUNT];
+float mv_preview[MAPVOTE_COUNT];
+float mv_votes[MAPVOTE_COUNT];
+float mv_flags[MAPVOTE_COUNT];
+float mv_flags_start[MAPVOTE_COUNT];
+entity mv_pk3list;
+float mv_abstain;
+float mv_ownvote;
+float mv_detail;
+float mv_timeout;
+float mv_top2_time;
+float mv_top2_alpha;
+
+vector mv_mousepos;
+int mv_selection;
+int mv_columns;
+int mv_mouse_selection;
+int mv_selection_keyboard;
+
+float gametypevote;
+string mapvote_chosenmap;
+vector gtv_text_size;
+vector gtv_text_size_small;
+
+const int NUM_SSDIRS = 4;
+string ssdirs[NUM_SSDIRS];
+int n_ssdirs;
+
string MapVote_FormatMapItem(int id, string map, float _count, float maxwidth, vector fontsize)
{
string pre, post;
{
if(_count == 1)
post = _(" (1 vote)");
- else if(_count >= 0 && mv_avail[id] == GTV_AVAILABLE)
+ else if(_count >= 0 && (mv_flags[id] & GTV_AVAILABLE))
post = sprintf(_(" (%d votes)"), _count);
else
post = "";
return strcat(pre, map, post);
}
-string GameTypeVote_DescriptionByID(int id)
-{
- return MapInfo_Type_Description(MapInfo_Type_FromString(mv_maps[id]));
-}
-
vector MapVote_RGB(int id)
{
- if(mv_avail[id] != GTV_AVAILABLE)
+ if(!(mv_flags[id] & GTV_AVAILABLE))
return '1 1 1';
if(id == mv_ownvote)
return '0 1 0';
void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string gtype, string pic, float _count, int id)
{
+ // Find the correct alpha
float alpha;
- float desc_padding = gtv_text_size.x * 3;
+ if(!(mv_flags_start[id] & GTV_AVAILABLE))
+ alpha = 0.2; // The gametype isn't supported by the map
+ else if ( !(mv_flags[id] & GTV_AVAILABLE) && mv_top2_alpha)
+ alpha = mv_top2_alpha; // Fade away if not one of the top 2 choice
+ else
+ alpha = 1; // Normal, full alpha
+
+ // Bounding box details
float rect_margin = hud_fontsize.y / 2;
vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
vector rect_size = '1 1 0';
rect_size.x = tsize + rect_margin;
rect_size.y = maxh + rect_margin;
- vector rgb = MapVote_RGB(id);
- vector offset = pos;
- float nlines = 0;
-
- if(mv_avail_start[id] != GTV_AVAILABLE)
- alpha = 0.2;
- else if ( mv_avail[id] != GTV_AVAILABLE && mv_top2_alpha)
- alpha = mv_top2_alpha;
- else
- alpha = 1;
- if(id == mv_selection && mv_avail[id] == GTV_AVAILABLE)
+ // Highlight selected item
+ if(id == mv_selection && (mv_flags[id] & GTV_AVAILABLE))
{
drawfill(rect_pos, rect_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
}
+
+ // Highlight current vote
+ vector rgb = MapVote_RGB(id);
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);
}
- entity title;
- title = spawn();
- title.message = MapVote_FormatMapItem(id, MapInfo_Type_ToText(MapInfo_Type_FromString(gtype)),
- _count, tsize, gtv_text_size);
- title.origin = pos-offset;
-
- pos.y += gtv_text_size_small.y;
- pos.y += gtv_text_size.y/2;
+ vector offset = pos;
- maxh -= gtv_text_size.y;
+ float title_gap = gtv_text_size.y * 1.4; // distance between the title and the description
+ pos.y += title_gap;
+ maxh -= title_gap;
- entity picent = spawn();
- picent.origin = pos-offset;
- picent.maxs = '1 1 0 ' * min(maxh, desc_padding) * 0.8;
+ // Evaluate the image size
+ vector image_size = '1 1 0' * gtv_text_size.x * 3;
+ if ( maxh < image_size.y )
+ image_size = '1 1 0' * maxh;
+ image_size *= 0.8;
+ float desc_padding = gtv_text_size.x * 0.6;
+ pos.x += image_size.x + desc_padding;
+ tsize -= image_size.x + desc_padding;
- pos.x += desc_padding;
- tsize -= desc_padding;
+ // Split the description into lines
+ entity title;
+ title = spawn();
+ title.message = MapVote_FormatMapItem(id, mv_pk3[id], _count, tsize, gtv_text_size);
- string thelabel = GameTypeVote_DescriptionByID(id), ts;
+ string thelabel = mv_desc[id], ts;
entity last = title;
entity next = world;
+ float nlines = 0;
if( thelabel != "")
{
float i,n = tokenizebyseparator(thelabel, "\n");
}
}
- maxh -= max(nlines*gtv_text_size_small.y,picent.maxs.y);
+ // Center the contents in the bounding box
+ maxh -= max(nlines*gtv_text_size_small.y,image_size.y);
if ( maxh > 0 )
offset.y += maxh/2;
- drawstring(title.origin+offset, title.message, gtv_text_size, rgb, alpha, DRAWFLAG_NORMAL);
+ // Draw the title
+ drawstring(offset, title.message, gtv_text_size, rgb, alpha, DRAWFLAG_NORMAL);
+
+ // Draw the icon
if(pic != "")
- drawpic(picent.origin+offset, pic, picent.maxs, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ drawpic('0 1 0'*title_gap+'0.5 0 0'*desc_padding+offset, pic, image_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ // Draw the description
for ( last = title.chain; last ; )
{
drawstring(last.origin+offset, last.message, gtv_text_size_small, '1 1 1', alpha, DRAWFLAG_NORMAL);
remove(next);
}
- remove(picent);
+ // Cleanup
remove(title);
}
text_size = stringwidth(label, false, hud_fontsize);
float theAlpha;
- if (mv_avail[id] != GTV_AVAILABLE && mv_top2_alpha)
+ if (!(mv_flags[id] & GTV_AVAILABLE) && mv_top2_alpha)
theAlpha = mv_top2_alpha;
else
theAlpha = 1;
else
drawborderlines(autocvar_scoreboard_border_thickness, pos, img_size, '0 0 0', theAlpha, DRAWFLAG_NORMAL);
- if(id == mv_selection && mv_avail[id] == GTV_AVAILABLE)
+ if(id == mv_selection && (mv_flags[id] & GTV_AVAILABLE))
drawfill(pos, img_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
}
mask = ReadLong();
for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)
- mv_avail[i] = (mask & power) ? GTV_AVAILABLE : GTV_FORBIDDEN;
+ {
+ if ( mask & power )
+ mv_flags[i] |= GTV_AVAILABLE;
+ else
+ mv_flags[i] &= ~GTV_AVAILABLE;
+ }
}
else
{
for(i = 0; i < mv_num_maps; ++i )
- mv_avail[i] = ReadByte();
+ mv_flags[i] = ReadByte();
}
}
-void MapVote_Init()
+void MapVote_ReadOption(int i)
+{
+ string map = strzone(ReadString());
+ string pk3 = strzone(ReadString());
+ int j = bound(0, ReadByte(), n_ssdirs - 1);
+
+ mv_maps[i] = map;
+ mv_pk3[i] = pk3;
+ mv_flags[i] = GTV_AVAILABLE;
+
+ string pic = strzone(strcat(ssdirs[j], "/", map));
+ mv_pics[i] = pic;
+ mv_preview[i] = false;
+ MapVote_CheckPic(pic, pk3, i);
+}
+
+void GameTypeVote_ReadOption(int i)
{
- int i, j;
- string map, pk3, s;
+ string gt = strzone(ReadString());
+
+ mv_maps[i] = gt;
+ mv_flags[i] = ReadByte();
+ string mv_picpath = sprintf("gfx/menu/%s/gametype_%s", autocvar_menu_skin, gt);
+ if(precache_pic(mv_picpath) == "")
+ mv_picpath = strcat("gfx/menu/default/gametype_", gt);
+ string pic = strzone(mv_picpath);
+ mv_pics[i] = pic;
+ mv_preview[i] = PreviewExists(pic);
+
+ if ( mv_flags[i] & GTV_CUSTOM )
+ {
+ string name = ReadString();
+ if ( strlen(name) < 1 )
+ name = gt;
+ mv_pk3[i] = strzone(name);
+ mv_desc[i] = strzone(ReadString());
+ }
+ else
+ {
+ int type = MapInfo_Type_FromString(gt);
+ mv_pk3[i] = strzone(MapInfo_Type_ToText(type));
+ mv_desc[i] = MapInfo_Type_Description(type);
+ }
+}
+
+void MapVote_Init()
+{
precache_sound ("misc/invshot.wav");
mv_active = 1;
mv_selection = -1;
mv_selection_keyboard = 0;
+ string s;
for(n_ssdirs = 0; ; ++n_ssdirs)
{
s = ReadString();
}
MapVote_ReadMask();
+ int i;
for(i = 0; i < mv_num_maps; ++i )
- mv_avail_start[i] = mv_avail[i];
+ mv_flags_start[i] = mv_flags[i];
// Assume mv_pk3list is world, there should only be 1 mapvote per round
mv_pk3list = world; // I'm still paranoid!
{
mv_votes[i] = 0;
- map = strzone(ReadString());
- pk3 = strzone(ReadString());
- j = bound(0, ReadByte(), n_ssdirs - 1);
-
- mv_maps[i] = map;
- mv_pk3[i] = pk3;
- mv_avail[i] = ReadByte();
-
- if(gametypevote)
- {
- //map = strzone(strcat("gfx/menu/default/gametype_", map));
- //map = strzone(sprintf("gfx/menu/%s/gametype_%s", autocvar_menu_skin, map));
- string mv_picpath = sprintf("gfx/menu/%s/gametype_%s", autocvar_menu_skin, map);
- if(precache_pic(mv_picpath) == "")
- mv_picpath = strcat("gfx/menu/default/gametype_", map);
- map = strzone(mv_picpath);
- mv_pics[i] = map;
- mv_preview[i] = PreviewExists(map);
- }
+ if ( gametypevote )
+ GameTypeVote_ReadOption(i);
else
- {
- map = strzone(strcat(ssdirs[j], "/", map));
- mv_pics[i] = map;
- mv_preview[i] = false;
- MapVote_CheckPic(map, pk3, i);
- }
+ MapVote_ReadOption(i);
}
for(i = 0; i < n_ssdirs; ++i)
imp = mv_num_maps - 1;
else
imp = pos < 1 ? mv_num_maps - 1 : pos - 1;
- if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ if ( !(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote )
imp = MapVote_MoveLeft(imp);
return imp;
}
imp = 0;
else
imp = pos >= mv_num_maps - 1 ? 0 : pos + 1;
- if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ if ( !(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote )
imp = MapVote_MoveRight(imp);
return imp;
}
imp -= mv_columns;
}
}
- if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ if ( !(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote )
imp = MapVote_MoveUp(imp);
return imp;
}
if ( imp >= mv_num_maps )
imp = imp % mv_columns;
}
- if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ if ( !(mv_flags[imp] & GTV_AVAILABLE) && imp != mv_ownvote )
imp = MapVote_MoveDown(imp);
return imp;
}
int i;
for(i = 0; i < mv_num_maps; ++i)
{
- if(mv_avail[i] == GTV_AVAILABLE)
+ if(mv_flags[i] & GTV_AVAILABLE)
{
if(mv_detail)
mv_votes[i] = ReadByte();
#ifndef MAPVOTING_H
#define MAPVOTING_H
-int mv_num_maps;
-
-float mv_active;
-string mv_maps[MAPVOTE_COUNT];
-string mv_pics[MAPVOTE_COUNT];
-string mv_pk3[MAPVOTE_COUNT];
-float mv_preview[MAPVOTE_COUNT];
-float mv_votes[MAPVOTE_COUNT];
-float mv_avail[MAPVOTE_COUNT];
-float mv_avail_start[MAPVOTE_COUNT];
-entity mv_pk3list;
-float mv_abstain;
-float mv_ownvote;
-float mv_detail;
-float mv_timeout;
-float mv_top2_time;
-float mv_top2_alpha;
-
-vector mv_mousepos;
-int mv_selection;
-int mv_columns;
-int mv_mouse_selection;
-int mv_selection_keyboard;
-
-float gametypevote;
-string mapvote_chosenmap;
-vector gtv_text_size;
-vector gtv_text_size_small;
-
-string MapVote_FormatMapItem(int id, string map, float count, float maxwidth, vector fontsize);
-
-string GameTypeVote_DescriptionByID(int id);
-
-vector MapVote_RGB(int id);
-
-void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string gtype, string pic, float count, int id);
-
-void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float count, int id);
-
-void MapVote_DrawAbstain(vector pos, float isize, float tsize, float count, int id);
-
-vector MapVote_GridVec(vector gridspec, int i, int m);
-
-float MapVote_Selection(vector topleft, vector cellsize, float rows, float columns);
-
+#include "../common/constants.qh"
void MapVote_Draw();
void Cmd_MapVote_MapDownload(float argc);
-void MapVote_CheckPK3(string pic, string pk3, int id);
-
-void MapVote_CheckPic(string pic, string pk3, int id);
-
-void MapVote_ReadMask();
-
-const int NUM_SSDIRS = 4;
-string ssdirs[NUM_SSDIRS];
-int n_ssdirs;
-void MapVote_Init();
-
-void MapVote_SendChoice(float index);
-
-int MapVote_MoveLeft(int pos);
-int MapVote_MoveRight(int pos);
-int MapVote_MoveUp(int pos);
-
-int MapVote_MoveDown(int pos);
-
float MapVote_InputEvent(float bInputType, float nPrimary, float nSecondary);
-void MapVote_UpdateMask();
-
-void MapVote_UpdateVotes();
-
void Ent_MapVote();
void Net_MapVote_Picture();
#include "miscfunctions.qh"
+#include "_all.qh"
-#include "../common/urllib.qh"
+#include "hud.qh"
+#include "sortlist.qh"
#include "../common/command/generic.qh"
+#include "../common/teams.qh"
+#include "../common/urllib.qh"
+#include "../common/util.qh"
+
+#include "../csqcmodellib/cl_model.qh"
+
+#include "../warpzonelib/mathlib.qh"
+
void AuditLists()
{
entity e;
break;
}
-void DrawCircleClippedPic(vector centre, float radius, string pic, float f, vector rgb, float a, float drawflag)
+void DrawCircleClippedPic(vector centre, float radi, string pic, float f, vector rgb, float a, float drawflag)
{
float x, y, q, d;
vector ringsize, v, t;
- ringsize = radius * '1 1 0';
+ ringsize = radi * '1 1 0';
x = cos(f * 2 * M_PI);
y = sin(f * 2 * M_PI);
entity teams;
float team_count; // real teams
+const int INITPRIO_FIRST = 0;
+const int INITPRIO_GAMETYPE = 0;
+const int INITPRIO_GAMETYPE_FALLBACK = 1;
+const int INITPRIO_FINDTARGET = 10;
+const int INITPRIO_DROPTOFLOOR = 20;
+const int INITPRIO_SETLOCATION = 90;
+const int INITPRIO_LINKDOORS = 91;
+const int INITPRIO_LAST = 99;
+
void AuditLists();
float RegisterPlayer(entity player);
float PolyDrawModelSurface(entity e, float i_s);
void PolyDrawModel(entity e);
-void DrawCircleClippedPic(vector centre, float radius, string pic, float f, vector rgb, float a, float drawflag);
+void DrawCircleClippedPic(vector centre, float radi, string pic, float f, vector rgb, float a, float drawflag);
const vector GETPLAYERORIGIN_ERROR = '1123581321 2357111317 3141592653'; // way out of bounds for anything on the map
vector getplayerorigin(int pl);
#include "modeleffects.qh"
+#include "_all.qh"
+
+.float cnt;
+.float scale;
+.float alpha;
void ModelEffect_Draw()
{
#ifndef MODELEFFECTS_H
#define MODELEFFECTS_H
-.float frame1time;
-.float lifetime, fadetime;
-.float teleport_time;
-.float scale1, scale2;
+entityclass(ModelEffect);
+class(ModelEffect) .float frame1time;
+class(ModelEffect) .float lifetime, fadetime;
+class(ModelEffect) .float teleport_time;
+class(ModelEffect) .float scale1, scale2;
void ModelEffect_Draw();
--- /dev/null
+#include "../server/movelib.qc"
--- /dev/null
+#include "../server/movelib.qh"
+++ /dev/null
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "defs.qh"
- #include "../common/stats.qh"
- #include "../common/util.qh"
- #include "movetypes.qh"
- #include "../csqcmodellib/common.qh"
- #include "../server/t_items.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-
-const int MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
-#define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
-
-.entity move_groundentity; // FIXME add move_groundnetworkentity?
-.float move_suspendedinair;
-.float move_didgravity;
-
-void _Movetype_CheckVelocity() // SV_CheckVelocity
-{
-}
-
-float _Movetype_CheckWater(entity ent) // SV_CheckWater
-{
- vector point = ent.move_origin;
- point.z += (ent.mins.z + 1);
-
- int nativecontents = pointcontents(point);
-
- if(ent.move_watertype)
- if(ent.move_watertype != nativecontents)
- {
- //print(sprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", ent.move_watertype, nativecontents));
- if(ent.contentstransition)
- ent.contentstransition(ent.move_watertype, nativecontents);
- }
-
- ent.move_waterlevel = 0;
- ent.move_watertype = CONTENT_EMPTY;
-
- int supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
- if(supercontents & DPCONTENTS_LIQUIDSMASK)
- {
- ent.move_watertype = nativecontents;
- ent.move_waterlevel = 1;
- point.y = (ent.origin.y + ((ent.mins.z + ent.maxs.y) * 0.5));
- if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
- {
- ent.move_waterlevel = 2;
- point.y = ent.origin.y + ent.view_ofs.y;
- if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
- ent.move_waterlevel = 3;
- }
- }
-
- return (ent.move_waterlevel > 1);
-}
-
-void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
-{
- float contents = pointcontents(ent.move_origin);
-
- if(!ent.move_watertype)
- {
- // just spawned here
- if(!autocvar_cl_gameplayfix_fixedcheckwatertransition)
- {
- ent.move_watertype = contents;
- ent.move_waterlevel = 1;
- return;
- }
- }
- else if(ent.move_watertype != contents)
- {
- //print(sprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents));
- if(ent.contentstransition)
- ent.contentstransition(ent.move_watertype, contents);
- }
-
- if(contents <= CONTENT_WATER)
- {
- ent.move_watertype = contents;
- ent.move_waterlevel = 1;
- }
- else
- {
- ent.move_watertype = CONTENT_EMPTY;
- ent.move_waterlevel = (autocvar_cl_gameplayfix_fixedcheckwatertransition ? 0 : contents);
- }
-}
-
-void _Movetype_Impact(entity oth) // SV_Impact
-{
- entity oldother, oldself;
-
- oldself = self;
- oldother = other;
-
- if(self.move_touch)
- {
- other = oth;
-
- self.move_touch();
-
- other = oldother;
- }
-
- if(oth.move_touch)
- {
- other = self;
- self = oth;
-
- self.move_touch();
-
- self = oldself;
- other = oldother;
- }
-}
-
-void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
-{
- entity e, oldself, oldother;
-
- oldself = self;
- oldother = other;
-
- for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
- {
- if(e.move_touch)
- if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
- {
- self = e;
- other = oldself;
-
- trace_allsolid = false;
- trace_startsolid = false;
- trace_fraction = 1;
- trace_inwater = false;
- trace_inopen = true;
- trace_endpos = e.origin;
- trace_plane_normal = '0 0 1';
- trace_plane_dist = 0;
- trace_ent = oldself;
-
- e.move_touch();
- }
- }
-
- other = oldother;
- self = oldself;
-}
-
-void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
-{
- vector mi, ma;
- if(self.solid == SOLID_BSP)
- {
- // TODO set the absolute bbox
- mi = self.mins;
- ma = self.maxs;
- }
- else
- {
- mi = self.mins;
- ma = self.maxs;
- }
- mi = mi + self.origin;
- ma = ma + self.origin;
-
- if(self.move_flags & FL_ITEM)
- {
- mi.x -= 15;
- mi.y -= 15;
- mi.z -= 1;
- ma.x += 15;
- ma.y += 15;
- ma.z += 1;
- }
- else
- {
- mi.x -= 1;
- mi.y -= 1;
- mi.z -= 1;
- ma.x += 1;
- ma.y += 1;
- ma.z += 1;
- }
-
- self.absmin = mi;
- self.absmax = ma;
-
- if(touch_triggers)
- _Movetype_LinkEdict_TouchAreaGrid();
-}
-
-float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
-{
- vector org;
- org = self.move_origin + ofs;
-
- int cont = self.dphitcontentsmask;
- self.dphitcontentsmask = DPCONTENTS_SOLID;
- tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
- self.dphitcontentsmask = cont;
-
- if(trace_startsolid)
- return true;
-
- if(vlen(trace_endpos - self.move_origin) > 0.0001)
- self.move_origin = trace_endpos;
- return false;
-}
-
-float _Movetype_UnstickEntity() // SV_UnstickEntity
-{
- if(!_Movetype_TestEntityPosition('0 0 0'))
- return true;
- if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
- if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
- if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
- if(!_Movetype_TestEntityPosition('0 1 0')) goto success;
- if(!_Movetype_TestEntityPosition('-1 -1 0')) goto success;
- if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
- if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
- if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
- float i;
- for(i = 1; i <= 17; ++i)
- {
- if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
- if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
- }
- dprintf("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
- return false;
-:success
- dprintf("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
- _Movetype_LinkEdict(true);
- return true;
-}
-
-vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
-{
- vel = vel - ((vel * norm) * norm) * f;
-
- if(vel.x > -0.1 && vel.x < 0.1) vel.x = 0;
- if(vel.y > -0.1 && vel.y < 0.1) vel.y = 0;
- if(vel.z > -0.1 && vel.z < 0.1) vel.z = 0;
-
- return vel;
-}
-
-void _Movetype_PushEntityTrace(vector push)
-{
- vector end;
- float type;
-
- end = self.move_origin + push;
-
- if(self.move_nomonsters)
- type = max(0, self.move_nomonsters);
- else if(self.move_movetype == MOVETYPE_FLYMISSILE)
- type = MOVE_MISSILE;
- else if(self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
- type = MOVE_NOMONSTERS;
- else
- type = MOVE_NORMAL;
-
- tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
-}
-
-float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
-{
- _Movetype_PushEntityTrace(push);
-
- if(trace_startsolid && failonstartsolid)
- return trace_fraction;
-
- self.move_origin = trace_endpos;
-
- if(trace_fraction < 1)
- if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent)))
- _Movetype_Impact(trace_ent);
-
- return trace_fraction;
-}
-
-const float MAX_CLIP_PLANES = 5;
-void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
-{
- if(self.move_flags & FL_ONGROUND)
- {
- if(self.move_velocity.z >= 1/32)
- self.move_flags &= ~FL_ONGROUND;
- else if(!self.move_groundentity)
- return;
- else if(self.move_suspendedinair && wasfreed(self.move_groundentity))
- {
- self.move_groundentity = world;
- return;
- }
- }
-
- self.move_suspendedinair = false;
-
- _Movetype_CheckVelocity();
-
- if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
- {
- self.move_didgravity = 1;
- if(GRAVITY_UNAFFECTED_BY_TICRATE)
- {
- if(self.gravity)
- self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
- }
- else
- {
- if(self.gravity)
- self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- self.move_velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
- }
- }
-
- self.move_angles = self.move_angles + self.move_avelocity * dt;
-
- float movetime, bump;
- movetime = dt;
- for(bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
- {
- vector move;
- move = self.move_velocity * movetime;
- _Movetype_PushEntity(move, true);
- if(wasfreed(self))
- return;
-
- if(trace_startsolid)
- {
- _Movetype_UnstickEntity();
- _Movetype_PushEntity(move, false);
- if(wasfreed(self))
- return;
- }
-
- if(trace_fraction == 1)
- break;
-
- movetime *= 1 - min(1, trace_fraction);
-
- if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
- {
- self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
- self.move_flags &= ~FL_ONGROUND;
- }
- else if(self.move_movetype == MOVETYPE_BOUNCE)
- {
- float d, bouncefac, bouncestop;
-
- bouncefac = self.move_bounce_factor; if(!bouncefac) bouncefac = 0.5;
- bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60 / 800;
- if(self.gravity)
- bouncestop *= self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- bouncestop *= getstatf(STAT_MOVEVARS_GRAVITY);
-
- self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
-
- d = trace_plane_normal * self.move_velocity;
- if(trace_plane_normal.z > 0.7 && d < bouncestop && d > -bouncestop)
- {
- self.move_flags |= FL_ONGROUND;
- self.move_groundentity = trace_ent;
- self.move_velocity = '0 0 0';
- self.move_avelocity = '0 0 0';
- }
- else
- self.move_flags &= ~FL_ONGROUND;
- }
- else
- {
- self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
- if(trace_plane_normal.z > 0.7)
- {
- self.move_flags |= FL_ONGROUND;
- self.move_groundentity = trace_ent;
- if(trace_ent.solid == SOLID_BSP)
- self.move_suspendedinair = true;
- self.move_velocity = '0 0 0';
- self.move_avelocity = '0 0 0';
- }
- else
- self.move_flags &= ~FL_ONGROUND;
- }
-
- // DP revision 8905 (just, WHY...)
- if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
- break;
-
- // DP revision 8918 (WHY...)
- if(self.move_flags & FL_ONGROUND)
- break;
- }
-
- if(GRAVITY_UNAFFECTED_BY_TICRATE)
- if(self.move_didgravity > 0)
- if(!(self.move_flags & FL_ONGROUND))
- {
- if(self.gravity)
- self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
- }
-
- _Movetype_CheckWaterTransition(self);
-}
-
-void _Movetype_Physics_Frame(float movedt)
-{
- self.move_didgravity = -1;
- switch(self.move_movetype)
- {
- case MOVETYPE_PUSH:
- case MOVETYPE_FAKEPUSH:
- error("SV_Physics_Pusher not implemented");
- break;
- case MOVETYPE_NONE:
- break;
- case MOVETYPE_FOLLOW:
- error("SV_Physics_Follow not implemented");
- break;
- case MOVETYPE_NOCLIP:
- _Movetype_CheckWater(self);
- self.move_origin = self.move_origin + ticrate * self.move_velocity;
- self.move_angles = self.move_angles + ticrate * self.move_avelocity;
- _Movetype_LinkEdict(false);
- break;
- case MOVETYPE_STEP:
- error("SV_Physics_Step not implemented");
- break;
- case MOVETYPE_WALK:
- error("SV_Physics_Walk not implemented");
- break;
- case MOVETYPE_TOSS:
- case MOVETYPE_BOUNCE:
- case MOVETYPE_BOUNCEMISSILE:
- case MOVETYPE_FLYMISSILE:
- case MOVETYPE_FLY:
- _Movetype_Physics_Toss(movedt);
- break;
- }
-}
-
-void Movetype_Physics_NoMatchServer() // optimized
-{
- float movedt;
-
- movedt = time - self.move_time;
- self.move_time = time;
-
- _Movetype_Physics_Frame(movedt);
- if(wasfreed(self))
- return;
-
- self.avelocity = self.move_avelocity;
- self.velocity = self.move_velocity;
- self.angles = self.move_angles;
- setorigin(self, self.move_origin);
-}
-
-void Movetype_Physics_MatchServer(bool sloppy)
-{
- Movetype_Physics_MatchTicrate(ticrate, sloppy);
-}
-
-void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
-{
- float n, i, dt, movedt;
-
- if(tr <= 0)
- {
- Movetype_Physics_NoMatchServer();
- return;
- }
-
- dt = time - self.move_time;
-
- movedt = tr;
- n = max(0, floor(dt / tr));
- dt -= n * tr;
- self.move_time += n * tr;
-
- if(!self.move_didgravity)
- self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
-
- for(i = 0; i < n; ++i)
- {
- _Movetype_Physics_Frame(movedt);
- if(wasfreed(self))
- return;
- }
-
- self.avelocity = self.move_avelocity;
-
- if(dt > 0 && self.move_movetype != MOVETYPE_NONE && !(self.move_flags & FL_ONGROUND))
- {
- // now continue the move from move_time to time
- self.velocity = self.move_velocity;
-
- if(self.move_didgravity > 0)
- {
- if(GRAVITY_UNAFFECTED_BY_TICRATE)
- {
- if(self.gravity)
- self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
- }
- else
- {
- if(self.gravity)
- self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- self.velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
- }
- }
-
- self.angles = self.move_angles + dt * self.avelocity;
-
- if(sloppy || self.movetype == MOVETYPE_NOCLIP)
- {
- setorigin(self, self.move_origin + dt * self.velocity);
- }
- else
- {
- _Movetype_PushEntityTrace(dt * self.velocity);
- if(!trace_startsolid)
- setorigin(self, trace_endpos);
- }
-
- if(self.move_didgravity > 0)
- {
- if(GRAVITY_UNAFFECTED_BY_TICRATE)
- {
- if(self.gravity)
- self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
- else
- self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
- }
- }
- }
- else
- {
- self.velocity = self.move_velocity;
- self.angles = self.move_angles;
- setorigin(self, self.move_origin);
- }
-}
+++ /dev/null
-#ifndef MOVETYPES_H
-#define MOVETYPES_H
-
-.float move_movetype;
-.float move_time;
-.vector move_origin;
-.vector move_angles;
-.vector move_velocity;
-.vector move_avelocity;
-.int move_flags;
-.int move_watertype;
-.int move_waterlevel;
-.void(void) move_touch;
-.void(float, float) contentstransition;
-.float move_bounce_factor;
-.float move_bounce_stopspeed;
-.float move_nomonsters; // -1 for MOVE_NORMAL, otherwise a MOVE_ constant
-
-// should match sv_gameplayfix_fixedcheckwatertransition
-float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1;
-
-void Movetype_Physics_MatchTicrate(float tr, bool sloppy);
-void Movetype_Physics_MatchServer(bool sloppy);
-void Movetype_Physics_NoMatchServer();
-
-const int MOVETYPE_NONE = 0;
-const int MOVETYPE_ANGLENOCLIP = 1;
-const int MOVETYPE_ANGLECLIP = 2;
-const int MOVETYPE_WALK = 3;
-const int MOVETYPE_STEP = 4;
-const int MOVETYPE_FLY = 5;
-const int MOVETYPE_TOSS = 6;
-const int MOVETYPE_PUSH = 7;
-const int MOVETYPE_NOCLIP = 8;
-const int MOVETYPE_FLYMISSILE = 9;
-const int MOVETYPE_BOUNCE = 10;
-const int MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on bouncing
-const int MOVETYPE_FOLLOW = 12;
-const int MOVETYPE_FAKEPUSH = 13;
-const int MOVETYPE_FLY_WORLDONLY = 33;
-
-const int FL_ITEM = 256;
-const int FL_ONGROUND = 512;
-#endif
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "noise.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "noise.qh"
+#include "_all.qh"
+
+entityclass(Noise);
+class(Noise) .float noise_baccum;
+class(Noise) .float noise_paccum;
+class(Noise) .float noise_paccum2;
+class(Noise) .float noise_paccum3;
+class(Noise) .float noise_bstate;
-.float noise_baccum;
-.float noise_paccum;
-.float noise_paccum2;
-.float noise_paccum3;
-.float noise_bstate;
float Noise_Brown(entity e, float dt)
{
e.noise_baccum += random() * sqrt(dt); // same stddev for all dt
#include "particles.qh"
+#include "_all.qh"
-void Draw_PointParticles()
-{
- float n, i, fail;
- vector p;
- vector sz;
- vector o;
- o = self.origin;
- sz = self.maxs - self.mins;
- n = BGMScript(self);
- if(self.absolute == 2)
- {
- if(n >= 0)
- n = self.just_toggled ? self.impulse : 0;
- else
- n = self.impulse * drawframetime;
- }
- else
- {
- n *= self.impulse * drawframetime;
- if(self.just_toggled)
- if(n < 1)
- n = 1;
- }
- if(n == 0)
- return;
- fail = 0;
- for(i = random(); i <= n && fail <= 64*n; ++i)
- {
- p = o + self.mins;
- p.x += random() * sz.x;
- p.y += random() * sz.y;
- p.z += random() * sz.z;
- if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
- {
- if(self.movedir != '0 0 0')
- {
- traceline(p, p + normalize(self.movedir) * 4096, 0, world);
- p = trace_endpos;
- pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
- }
- else
- {
- pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
- }
- if(self.noise != "")
- {
- setorigin(self, p);
- sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
- }
- self.just_toggled = 0;
- }
- else if(self.absolute)
- {
- ++fail;
- --i;
- }
- }
- setorigin(self, o);
-}
+#include "../common/stats.qh"
+#include "../common/util.qh"
-void Ent_PointParticles_Remove()
-{
- if(self.noise)
- strunzone(self.noise);
- self.noise = string_null;
- if(self.bgmscript)
- strunzone(self.bgmscript);
- self.bgmscript = string_null;
-}
-
-void Ent_PointParticles()
-{
- float i;
- vector v;
- int f = ReadByte();
- if(f & 2)
- {
- i = ReadCoord(); // density (<0: point, >0: volume)
- if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
- self.just_toggled = 1;
- self.impulse = i;
- }
- if(f & 4)
- {
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- }
- if(f & 1)
- {
- self.modelindex = ReadShort();
- if(f & 0x80)
- {
- if(self.modelindex)
- {
- self.mins_x = ReadCoord();
- self.mins_y = ReadCoord();
- self.mins_z = ReadCoord();
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- }
- else
- {
- self.mins = '0 0 0';
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- }
- }
- else
- {
- self.mins = self.maxs = '0 0 0';
- }
-
- self.cnt = ReadShort(); // effect number
-
- if(f & 0x20)
- {
- self.velocity = decompressShortVector(ReadShort());
- self.movedir = decompressShortVector(ReadShort());
- }
- else
- {
- self.velocity = self.movedir = '0 0 0';
- }
- if(f & 0x40)
- {
- self.waterlevel = ReadShort() / 16.0;
- self.count = ReadByte() / 16.0;
- }
- else
- {
- self.waterlevel = 0;
- self.count = 1;
- }
- if(self.noise)
- strunzone(self.noise);
- if(self.bgmscript)
- strunzone(self.bgmscript);
- self.noise = strzone(ReadString());
- if(self.noise != "")
- {
- self.atten = ReadByte() / 64.0;
- self.volume = ReadByte() / 255.0;
- }
- self.bgmscript = strzone(ReadString());
- if(self.bgmscript != "")
- {
- self.bgmscriptattack = ReadByte() / 64.0;
- self.bgmscriptdecay = ReadByte() / 64.0;
- self.bgmscriptsustain = ReadByte() / 255.0;
- self.bgmscriptrelease = ReadByte() / 64.0;
- }
- BGMScript_InitEntity(self);
- }
-
- if(f & 2)
- {
- self.absolute = (self.impulse >= 0);
- if(!self.absolute)
- {
- v = self.maxs - self.mins;
- self.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
- }
- }
-
- if(f & 0x10)
- self.absolute = 2;
-
- setorigin(self, self.origin);
- setsize(self, self.mins, self.maxs);
- self.solid = SOLID_NOT;
- self.draw = Draw_PointParticles;
- self.entremove = Ent_PointParticles_Remove;
-}
-
-void Draw_Rain()
-{
- te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
-}
-
-void Draw_Snow()
-{
- te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
-}
-
-void Ent_RainOrSnow()
-{
- self.impulse = ReadByte(); // Rain, Snow, or Whatever
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- self.velocity = decompressShortVector(ReadShort());
- self.count = ReadShort() * 10;
- self.glow_color = ReadByte(); // color
-
- self.mins = -0.5 * self.maxs;
- self.maxs = 0.5 * self.maxs;
- self.origin = self.origin - self.mins;
-
- setorigin(self, self.origin);
- setsize(self, self.mins, self.maxs);
- self.solid = SOLID_NOT;
- if(self.impulse)
- self.draw = Draw_Rain;
- else
- self.draw = Draw_Snow;
-}
+#include "../warpzonelib/common.qh"
void Net_ReadVortexBeamParticle()
{
#ifndef PARTICLES_H
#define PARTICLES_H
-
.int dphitcontentsmask;
-.int cnt; // effect number
-.vector velocity; // particle velocity
-.float waterlevel; // direction jitter
-.int count; // count multiplier
-.int impulse; // density
-.string noise; // sound
-.float atten;
-.float volume;
-.float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
-.vector movedir; // trace direction
+entityclass(PointParticles);
+class(PointParticles) .int cnt; // effect number
+class(PointParticles) .vector velocity; // particle velocity
+class(PointParticles) .float waterlevel; // direction jitter
+class(PointParticles) .int count; // count multiplier
+class(PointParticles) .int impulse; // density
+class(PointParticles) .string noise; // sound
+class(PointParticles) .float atten;
+class(PointParticles) .float volume;
+class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
+class(PointParticles) .vector movedir; // trace direction
void Draw_PointParticles();
void Ent_PointParticles();
-.float glow_color; // palette index
-
-void Draw_Rain();
-
-void Draw_Snow();
-
-void Ent_RainOrSnow();
+class(PointParticles) .float glow_color; // palette index
void Net_ReadVortexBeamParticle();
#endif
#include "player_skeleton.qh"
+#include "../common/csqcmodel_settings.qh"
+
#include "../warpzonelib/anglestransform.qh"
-.float skeleton_info_modelindex;
-.float skeleton_info_skin;
+class(Skeleton) .float skeleton_info_modelindex;
+class(Skeleton) .float skeleton_info_skin;
const int BONETYPE_LOWER = 0;
const int BONETYPE_UPPER = 1;
const int MAX_BONES = 128;
-.float skeleton_bonetype[MAX_BONES];
-.float skeleton_numbones;
+class(Skeleton) .float skeleton_bonetype[MAX_BONES];
+class(Skeleton) .float skeleton_numbones;
void skeleton_loadinfo(entity e)
{
if(!is_dead)
{
+ if(self == csqcplayer)
+ self.v_angle_x = input_angles_x;
int i;
for(i = 0; i < MAX_AIM_BONES; ++i)
{
#ifndef PLAYER_SKELETON
#define PLAYER_SKELETON
+#include "../common/util.qh"
+
void free_skeleton_from_frames(entity e);
void skeleton_from_frames(entity e, float is_dead);
void skeleton_loadinfo(entity e);
-.float bone_upperbody;
-.int bone_weapon;
-.float bone_aim[MAX_AIM_BONES];
-.float bone_aimweight[MAX_AIM_BONES];
-.float fixbone;
+entityclass(Skeleton);
+class(Skeleton) .float bone_upperbody;
+class(Skeleton) .int bone_weapon;
+class(Skeleton) .float bone_aim[MAX_AIM_BONES];
+class(Skeleton) .float bone_aimweight[MAX_AIM_BONES];
+class(Skeleton) .float fixbone;
#endif
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../warpzonelib/mathlib.qh"
- #include "prandom.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "prandom.qh"
+#include "_all.qh"
+
+#include "../warpzonelib/mathlib.qh"
// prandom - PREDICTABLE random number generator (not seeded yet)
effects.qc
gibs.qc
hook.qc
-hud_config.qc
hud.qc
-laser.qc
+hud_config.qc
main.qc
mapvoting.qc
miscfunctions.qc
modeleffects.qc
-movetypes.qc
+movelib.qc
noise.qc
particles.qc
player_skeleton.qc
scoreboard.qc
shownames.qc
sortlist.qc
-target_music.qc
teamradar.qc
tturrets.qc
tuba.qc
-vehicles/vehicles.qc
+t_items.qc
view.qc
wall.qc
waypointsprites.qc
-command/cl_cmd.qc
+command/all.qc
+
+vehicles/bumblebee.qc
+vehicles/all.qc
weapons/projectile.qc // TODO
../common/animdecide.qc
../common/buffs.qc
../common/mapinfo.qc
+../common/movetypes/include.qc
../common/nades.qc
../common/net_notice.qc
../common/notifications.qc
+../common/physics.qc
../common/playerstats.qc
../common/test.qc
../common/urllib.qc
../common/util.qc
-../common/command/generic.qc
-../common/command/markup.qc
-../common/command/rpn.qc
+../common/items/all.qc
+
+../common/monsters/all.qc
-../common/monsters/monsters.qc
+../common/weapons/all.qc // TODO
-../common/weapons/weapons.qc // TODO
+../common/triggers/include.qc
../csqcmodellib/cl_model.qc
../csqcmodellib/cl_player.qc
../csqcmodellib/interpolate.qc
-../server/movelib.qc
-../server/t_items.qc
-../server/vehicles/bumblebee.qc
+../server/mutators/mutator_multijump.qc
../warpzonelib/anglestransform.qc
../warpzonelib/client.qc
../warpzonelib/common.qc
../warpzonelib/mathlib.qc
+../warpzonelib/util_server.qc
-#if defined(CSQC)
- #include "rubble.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "rubble.qh"
// LordHavoc: rewrote this file, it was really bad code
#ifndef RUBBLE_H
#define RUBBLE_H
-.float creationtime;
+entityclass(Rubble);
+class(Rubble) .float creationtime;
void RubbleLimit(string cname, float limit, void() deleteproc);
entity RubbleNew(string cname);
#endif
#include "scoreboard.qh"
+#include "_all.qh"
+
+#include "hud.qh"
+#include "sortlist.qh"
+
+#include "../common/constants.qh"
+#include "../common/counting.qh"
+#include "../common/mapinfo.qh"
+#include "../common/stats.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
float scoreboard_alpha_bg;
float scoreboard_alpha_fg;
hud_fontsize = HUD_GetFontsize("hud_fontsize");
- draw_beginBoldFont();
for(i = 1; i < argc - 1; ++i)
{
float nocomplain;
}
hud_field[hud_num_fields] = SP_END;
- draw_endBoldFont();
}
// MOVEUP::
}
// print the strings of the columns headers and draw the columns
- draw_beginBoldFont();
int i;
for(i = 0; i < hud_num_fields; ++i)
{
pos.x -= hud_fontsize.x;
}
}
- draw_endBoldFont();
pos.x = xmin;
pos.y += 1.25 * hud_fontsize.y; // skip the header
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);
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "defs.qh"
- #include "../common/constants.qh"
- #include "../common/teams.qh"
- #include "../common/util.qh"
- #include "../common/mapinfo.qh"
- #include "autocvars.qh"
- #include "main.qh"
- #include "../csqcmodellib/cl_model.qh"
- #include "shownames.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "shownames.qh"
+#include "_all.qh"
+#include "hud.qh"
+
+#include "../common/constants.qh"
+#include "../common/mapinfo.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
+
+#include "../csqcmodellib/cl_model.qh"
// self.isactive = player is in range and coordinates/status (health and armor) are up to date
// self.origin = player origin TODO: should maybe move this so it's the origin of the shownames tag already in SSQC for culling?
#ifndef SHOWNAMES_H
#define SHOWNAMES_H
-.float healthvalue;
-.float armorvalue;
-.float sameteam;
-.float fadedelay;
-.float pointtime;
+entityclass(ShowNames);
+class(ShowNames) .float healthvalue;
+class(ShowNames) .float armorvalue;
+class(ShowNames) .float sameteam;
+class(ShowNames) .float fadedelay;
+class(ShowNames) .float pointtime;
+
+void Draw_ShowNames_All();
+
#endif
#ifndef SORTLIST_H
#define SORTLIST_H
+entityclass(Sort);
//.float(entity,entity) sort_cmp;
-.entity sort_next, sort_prev;
+class(Sort) .entity sort_next, sort_prev;
entity Sort_Spawn();
--- /dev/null
+#include "_all.qh"
+
+#include "../common/buffs.qh"
+#include "../common/movetypes/movetypes.qh"
+#include "../common/util.qh"
+#include "../common/weapons/all.qh"
+#include "../csqcmodellib/cl_model.qh"
+#include "../csqcmodellib/common.qh"
+
+#include "../server/t_items.qc"
--- /dev/null
+#include "../server/t_items.qh"
+++ /dev/null
-#include "target_music.qh"
-
-void TargetMusic_Advance()
-{
- // run AFTER all the thinks!
- entity best, e;
- float vol, vol0;
- best = music_default;
- if(music_target && time < music_target.lifetime)
- best = music_target;
- if(music_trigger)
- best = music_trigger;
- for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); ) if(e.noise)
- {
- vol0 = e.lastvol;
- if(getsoundtime(e, CH_BGM_SINGLE) < 0)
- {
- vol0 = -1;
- }
- if(e == best)
- {
- // increase volume
- if(e.fade_time > 0)
- e.state = bound(0, e.state + frametime / e.fade_time, 1);
- else
- e.state = 1;
- }
- else
- {
- // decrease volume
- if(e.fade_rate > 0)
- e.state = bound(0, e.state - frametime / e.fade_rate, 1);
- else
- e.state = 0;
- }
- vol = e.state * e.volume * autocvar_bgmvolume;
- if(vol != vol0)
- {
- if(vol0 < 0)
- sound(e, CH_BGM_SINGLE, e.noise, vol, ATTEN_NONE); // restart
- else
- sound(e, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
- e.lastvol = vol;
- }
- }
- music_trigger = world;
-
- if(best)
- bgmtime = getsoundtime(best, CH_BGM_SINGLE);
- else
- bgmtime = gettime(GETTIME_CDTRACK);
-}
-
-void Net_TargetMusic()
-{
- int id = ReadShort();
- float vol = ReadByte() / 255.0;
- float fai = ReadByte() / 16.0;
- float fao = ReadByte() / 16.0;
- float tim = ReadByte();
- string noi = ReadString();
-
- entity e;
- for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); )
- {
- if(e.count == id)
- break;
- }
- if(!e)
- {
- e = spawn();
- e.enttype = ENT_CLIENT_TRIGGER_MUSIC;
- e.count = id;
- }
- if(e.noise != noi)
- {
- if(e.noise)
- strunzone(e.noise);
- e.noise = strzone(noi);
- precache_sound(e.noise);
- sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
- if(getsoundtime(e, CH_BGM_SINGLE) < 0)
- {
- dprintf("Cannot initialize sound %s\n", e.noise);
- strunzone(e.noise);
- e.noise = string_null;
- }
- }
- e.volume = vol;
- e.fade_time = fai;
- e.fade_rate = fao;
- if(vol > 0)
- {
- if(tim == 0)
- {
- music_default = e;
- if(!music_disabled)
- {
- e.state = 2;
- cvar_settemp("music_playlist_index", "-1"); // don't use playlists
- localcmd("cd stop\n"); // just in case
- music_disabled = 1;
- }
- }
- else
- {
- music_target = e;
- e.lifetime = time + tim;
- }
- }
-}
-
-void Ent_TriggerMusic_Think()
-{
- if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, self, world))
- {
- music_trigger = self;
- }
- self.nextthink = time;
-}
-
-void Ent_TriggerMusic_Remove()
-{
- if(self.noise)
- strunzone(self.noise);
- self.noise = string_null;
-}
-
-void Ent_ReadTriggerMusic()
-{
- int f = ReadByte();
- if(f & 4)
- {
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- }
- if(f & 1)
- {
- self.modelindex = ReadShort();
- if(self.modelindex)
- {
- self.mins_x = ReadCoord();
- self.mins_y = ReadCoord();
- self.mins_z = ReadCoord();
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- }
- else
- {
- self.mins = '0 0 0';
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- }
-
- self.volume = ReadByte() / 255.0;
- self.fade_time = ReadByte() / 16.0;
- self.fade_rate = ReadByte() / 16.0;
- string s = self.noise;
- if(self.noise)
- strunzone(self.noise);
- self.noise = strzone(ReadString());
- if(self.noise != s)
- {
- precache_sound(self.noise);
- sound(self, CH_BGM_SINGLE, self.noise, 0, ATTEN_NONE);
- if(getsoundtime(self, CH_BGM_SINGLE) < 0)
- {
- dprintf("Cannot initialize sound %s\n", self.noise);
- strunzone(self.noise);
- self.noise = string_null;
- }
- }
- }
-
- setorigin(self, self.origin);
- setsize(self, self.mins, self.maxs);
- self.cnt = 1;
- self.think = Ent_TriggerMusic_Think;
- self.nextthink = time;
-}
+++ /dev/null
-#ifndef TARGET_MUSIC_H
-#define TARGET_MUSIC_H
-
-float music_disabled;
-entity music_default;
-entity music_target;
-entity music_trigger;
-// FIXME also control bgmvolume here, to not require a target_music for the default track.
-
-.int state;
-.float lastvol;
-
-void TargetMusic_Advance();
-
-void Net_TargetMusic();
-
-void Ent_TriggerMusic_Think();
-
-void Ent_TriggerMusic_Remove();
-
-void Ent_ReadTriggerMusic();
-#endif
-#if defined(CSQC)
- #include "teamradar.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "teamradar.qh"
+#include "_all.qh"
+
+#include "hud.qh"
+
+#include "../common/util.qh"
+
+#include "../csqcmodellib/interpolate.qh"
float vlen2d(vector v)
{
const int MAX_TEAMRADAR_TIMES = 32;
+entityclass(TeamRadar);
// to make entities have dots on the team radar
-.float teamradar_icon;
-.float teamradar_times[MAX_TEAMRADAR_TIMES];
-.int teamradar_time_index;
-.vector teamradar_color;
+class(TeamRadar) .float teamradar_icon;
+class(TeamRadar) .float teamradar_times[MAX_TEAMRADAR_TIMES];
+class(TeamRadar) .int teamradar_time_index;
+class(TeamRadar) .vector teamradar_color;
float teamradar_angle; // player yaw angle
vector teamradar_origin3d_in_texcoord; // player origin
#include "tturrets.qh"
+#include "_all.qh"
+
+#include "hud.qh"
+#include "movelib.qh"
+#include "prandom.qh"
+#include "teamradar.qh"
#include "waypointsprites.qh"
-#include "../server/movelib.qh"
+#include "../common/teams.qh"
+
+#include "../common/movetypes/movetypes.qh"
+
+#include "../server/tturrets/include/turrets_early.qh"
+
+#include "../warpzonelib/anglestransform.qh"
+#include "../warpzonelib/mathlib.qh"
+
+.vector colormod;
+.float cnt;
+.float alpha;
+.float gravity;
string tid2info_base;
string tid2info_head;
precache_model ("models/turrets/head-gib2.md3");
precache_model ("models/turrets/head-gib3.md3");
precache_model ("models/turrets/head-gib4.md3");
- precache_model ("models/turrets/terrainbase.md3");
precache_model ("models/turrets/base.md3");
precache_model ("models/turrets/rocket.md3");
}
self.tur_head = world;
}
-.vector glowmod;
+class(Turret) .vector glowmod;
void turret_changeteam()
{
switch(self.team - 1)
#ifndef TTURRETS_H
#define TTURRETS_H
-#include "../server/tturrets/include/turrets_early.qh"
-
void ent_turret();
void turrets_precache();
-.entity tur_head;
+entityclass(Turret);
+class(Turret) .entity tur_head;
#endif
#include "tuba.qh"
+#include "_all.qh"
+
+#include "../common/constants.qh"
+#include "../common/util.qh"
+
+#include "../warpzonelib/mathlib.qh"
#define TUBA_STARTNOTE(i, n) strcat("weapons/tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n), ".wav")
const int TUBA_MAX = 27;
const int TUBA_INSTRUMENTS = 3;
-.int note;
-.bool tuba_attenuate;
-.float tuba_volume;
-.float tuba_volume_initial;
-.int tuba_instrument;
+class(Tuba) .int note;
+class(Tuba) .bool tuba_attenuate;
+class(Tuba) .float tuba_volume;
+class(Tuba) .float tuba_volume_initial;
+class(Tuba) .int tuba_instrument;
int Tuba_PitchStep;
#define TUBA_H
void Ent_TubaNote(bool isNew);
void Tuba_Precache();
+
+entityclass(Tuba);
+
#endif
--- /dev/null
+#include "all.qh"
+#include "../_all.qh"
+
+#include "../../common/movetypes/movetypes.qh"
+#include "../prandom.qh"
+#include "../scoreboard.qh"
+#include "../t_items.qh"
+
+#include "../../common/buffs.qh"
+#include "../../common/constants.qh"
+#include "../../common/movetypes/movetypes.qh"
+#include "../../common/stats.qh"
+#include "../../common/util.qh"
+
+#include "../../csqcmodellib/cl_model.qh"
+
+.float cnt;
+
+const string hud_bg = "gfx/vehicles/frame.tga";
+const string hud_sh = "gfx/vehicles/vh-shield.tga";
+
+const string hud_hp_bar = "gfx/vehicles/bar_up_left.tga";
+const string hud_hp_ico = "gfx/vehicles/health.tga";
+const string hud_sh_bar = "gfx/vehicles/bar_dwn_left.tga";
+const string hud_sh_ico = "gfx/vehicles/shield.tga";
+
+const string hud_ammo1_bar = "gfx/vehicles/bar_up_right.tga";
+const string hud_ammo1_ico = "gfx/vehicles/bullets.tga";
+const string hud_ammo2_bar = "gfx/vehicles/bar_dwn_right.tga";
+const string hud_ammo2_ico = "gfx/vehicles/rocket.tga";
+const string hud_energy = "gfx/vehicles/energy.tga";
+
+const int SBRM_FIRST = 1;
+const int SBRM_VOLLY = 1;
+const int SBRM_GUIDE = 2;
+const int SBRM_ARTILLERY = 3;
+const int SBRM_LAST = 3;
+
+const int RSM_FIRST = 1;
+const int RSM_BOMB = 1;
+const int RSM_FLARE = 2;
+const int RSM_LAST = 2;
+
+entity dropmark;
+float autocvar_cl_vehicles_hudscale = 0.5;
+float autocvar_cl_vehicles_hudalpha = 0.75;
+
+const string raptor_ico = "gfx/vehicles/raptor.tga";
+const string raptor_gun = "gfx/vehicles/raptor_guns.tga";
+const string raptor_bomb = "gfx/vehicles/raptor_bombs.tga";
+const string raptor_drop = "gfx/vehicles/axh-dropcross.tga";
+string raptor_xhair;
+
+
+
+const int MAX_AXH = 4;
+entity AuxiliaryXhairs[MAX_AXH];
+
+entityclass(AuxiliaryXhair);
+class(AuxiliaryXhair) .string axh_image;
+class(AuxiliaryXhair) .float axh_fadetime;
+class(AuxiliaryXhair) .float axh_drawflag;
+class(AuxiliaryXhair) .float axh_scale;
+
+const string bumb_ico = "gfx/vehicles/bumb.tga";
+const string bumb_lgun = "gfx/vehicles/bumb_lgun.tga";
+const string bumb_rgun = "gfx/vehicles/bumb_rgun.tga";
+
+const string bumb_gun_ico = "gfx/vehicles/bumb_side.tga";
+const string bumb_gun_gun = "gfx/vehicles/bumb_side_gun.tga";
+
+const string spider_ico = "gfx/vehicles/sbot.tga";
+const string spider_rkt = "gfx/vehicles/sbot_rpods.tga";
+const string spider_mgun = "gfx/vehicles/sbot_mguns.tga";
+string spider_xhair; // = "gfx/vehicles/axh-special1.tga";
+
+const string waki_ico = "gfx/vehicles/waki.tga";
+const string waki_eng = "gfx/vehicles/waki_e.tga";
+const string waki_gun = "gfx/vehicles/waki_guns.tga";
+const string waki_rkt = "gfx/vehicles/waki_rockets.tga";
+const string waki_xhair = "gfx/vehicles/axh-special1.tga";
+
+float alarm1time;
+float alarm2time;
+int weapon2mode;
+
+void AuxiliaryXhair_Draw2D()
+{
+ vector loc, psize;
+
+ psize = self.axh_scale * draw_getimagesize(self.axh_image);
+ loc = project_3d_to_2d(self.move_origin) - 0.5 * psize;
+ if (!(loc.z < 0 || loc.x < 0 || loc.y < 0 || loc.x > vid_conwidth || loc.y > vid_conheight))
+ {
+ loc.z = 0;
+ psize.z = 0;
+ drawpic(loc, self.axh_image, psize, self.colormod, self.alpha, self.axh_drawflag);
+ }
+
+ if(time - self.cnt > self.axh_fadetime)
+ self.draw2d = func_null;
+}
+
+void Net_AuXair2(bool bIsNew)
+{
+ int axh_id = bound(0, ReadByte(), MAX_AXH);
+ entity axh = AuxiliaryXhairs[axh_id];
+
+ if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+ {
+ axh = spawn();
+ axh.draw2d = func_null;
+ axh.drawmask = MASK_NORMAL;
+ axh.axh_drawflag = DRAWFLAG_ADDITIVE;
+ axh.axh_fadetime = 0.1;
+ axh.axh_image = "gfx/vehicles/axh-ring.tga";
+ axh.axh_scale = 1;
+ axh.alpha = 1;
+ AuxiliaryXhairs[axh_id] = axh;
+ }
+
+ axh.move_origin_x = ReadCoord();
+ axh.move_origin_y = ReadCoord();
+ axh.move_origin_z = ReadCoord();
+ axh.colormod_x = ReadByte() / 255;
+ axh.colormod_y = ReadByte() / 255;
+ axh.colormod_z = ReadByte() / 255;
+ axh.cnt = time;
+ axh.draw2d = AuxiliaryXhair_Draw2D;
+}
+
+void Net_VehicleSetup()
+{
+ int hud_id = ReadByte();
+
+ // Weapon update?
+ if(hud_id > HUD_VEHICLE_LAST)
+ {
+ weapon2mode = hud_id - HUD_VEHICLE_LAST;
+ return;
+ }
+
+ // hud_id == 0 means we exited a vehicle, so stop alarm sound/s
+ if(hud_id == 0)
+ {
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ return;
+ }
+
+ hud_id = bound(HUD_VEHICLE_FIRST, hud_id, HUD_VEHICLE_LAST);
+
+ // Init auxiliary crosshairs
+ int i;
+ for(i = 0; i < MAX_AXH; ++i)
+ {
+ entity axh = AuxiliaryXhairs[i];
+ if(axh != world && !wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+ remove(axh);
+
+ axh = spawn();
+ axh.draw2d = func_null;
+ axh.drawmask = MASK_NORMAL;
+ axh.axh_drawflag = DRAWFLAG_NORMAL;
+ axh.axh_fadetime = 0.1;
+ axh.axh_image = "gfx/vehicles/axh-ring.tga";
+ axh.axh_scale = 1;
+ axh.alpha = 1;
+ AuxiliaryXhairs[i] = axh;
+ }
+
+ switch(hud_id)
+ {
+ case HUD_SPIDERBOT:
+ // Minigun1
+ AuxiliaryXhairs[0].axh_image = "gfx/vehicles/axh-ring.tga";
+ AuxiliaryXhairs[0].axh_scale = 0.25;
+ // Minigun2
+ AuxiliaryXhairs[1].axh_image = "gfx/vehicles/axh-ring.tga";
+ AuxiliaryXhairs[1].axh_scale = 0.25;
+ // Rocket
+ AuxiliaryXhairs[2].axh_image = "gfx/vehicles/axh-special1.tga";
+ AuxiliaryXhairs[2].axh_scale = 0.5;
+ break;
+
+ case HUD_WAKIZASHI:
+ AuxiliaryXhairs[0].axh_image = "gfx/vehicles/axh-bracket.tga";
+ AuxiliaryXhairs[0].axh_scale = 0.25;
+ break;
+
+ case HUD_RAPTOR:
+ AuxiliaryXhairs[0].axh_image = "gfx/vehicles/axh-special2.tga";
+ AuxiliaryXhairs[0].axh_scale = 0.5;
+ //AuxiliaryXhair[0].alpha = 0.5;
+
+ AuxiliaryXhairs[1].axh_image = "gfx/vehicles/axh-bracket.tga";
+ AuxiliaryXhairs[1].axh_scale = 0.25;
+ //AuxiliaryXhair[1].alpha = 0.75;
+ //AuxiliaryXhair[1].axh_drawflag = DRAWFLAG_NORMAL;
+ break;
+
+ case HUD_BUMBLEBEE:
+ // Raygun-locked
+ AuxiliaryXhairs[0].axh_image = "gfx/vehicles/axh-bracket.tga";
+ AuxiliaryXhairs[0].axh_scale = 0.5;
+
+ // Gunner1
+ AuxiliaryXhairs[1].axh_image = "gfx/vehicles/axh-target.tga";
+ AuxiliaryXhairs[1].axh_scale = 0.75;
+
+ // Gunner2
+ AuxiliaryXhairs[2].axh_image = "gfx/vehicles/axh-target.tga";
+ AuxiliaryXhairs[2].axh_scale = 0.75;
+ break;
+ case HUD_BUMBLEBEE_GUN:
+ // Plasma cannons
+ AuxiliaryXhairs[0].axh_image = "gfx/vehicles/axh-bracket.tga";
+ AuxiliaryXhairs[0].axh_scale = 0.25;
+ // Raygun
+ AuxiliaryXhairs[1].axh_image = "gfx/vehicles/axh-bracket.tga";
+ AuxiliaryXhairs[1].axh_scale = 0.25;
+ break;
+ }
+}
+#define HUD_GETSTATS \
+ int vh_health = getstati(STAT_VEHICLESTAT_HEALTH); \
+ float shield = getstati(STAT_VEHICLESTAT_SHIELD); \
+ noref int energy = getstati(STAT_VEHICLESTAT_ENERGY); \
+ noref float ammo1 = getstati(STAT_VEHICLESTAT_AMMO1); \
+ noref float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1); \
+ noref int ammo2 = getstati(STAT_VEHICLESTAT_AMMO2); \
+ noref int reload2 = getstati(STAT_VEHICLESTAT_RELOAD2);
+
+void CSQC_BUMBLE_HUD()
+{
+/*
+ drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
+ drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0' * (1 - health), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc, waki_r, picsize, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+*/
+ if(autocvar_r_letterbox)
+ return;
+
+ vector picsize, hudloc = '0 0 0', pic2size, picloc;
+
+ // Fetch health & ammo stats
+ HUD_GETSTATS
+
+ picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+ hudloc.y = vid_conheight - picsize.y;
+ hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+
+ drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+
+ shield *= 0.01;
+ vh_health *= 0.01;
+ energy *= 0.01;
+ reload1 *= 0.01;
+
+ pic2size = draw_getimagesize(bumb_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+ picloc = picsize * 0.5 - pic2size * 0.5;
+
+ if(vh_health < 0.25)
+ drawpic(hudloc + picloc, bumb_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, bumb_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
+
+ drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
+
+// Health bar
+ picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+ if(vh_health < 0.25)
+ {
+ if(alarm1time < time)
+ {
+ alarm1time = time + 2;
+ sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm1time)
+ {
+ sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm1time = 0;
+ }
+ }
+
+// Shield bar
+ picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+ picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+ if(shield < 0.25)
+ {
+ if(alarm2time < time)
+ {
+ alarm2time = time + 1;
+ sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm2time)
+ {
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm2time = 0;
+ }
+ }
+
+ ammo1 *= 0.01;
+ ammo2 *= 0.01;
+
+// Gunner1 bar
+ picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo1, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+
+// Right gunner slot occupied?
+ if(!AuxiliaryXhairs[1].draw2d)
+ {
+ shield = (picsize.x * 0.5) - (0.5 * stringwidth(_("No right gunner!"), false, '1 0 0' * picsize.y + '0 1 0' * picsize.y));
+ drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
+ drawstring(hudloc + picloc + '1 0 0' * shield, _("No right gunner!"), '1 0 0' * picsize.y + '0 1 0' * picsize.y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
+ }
+
+// .. and icon
+ picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+ if(ammo1 < 0.2)
+ drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+// Gunner2 bar
+ picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo2, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// Left gunner slot occupied?
+ if(!AuxiliaryXhairs[2].draw2d)
+ {
+ shield = (picsize.x * 0.5) - (0.5 * stringwidth(_("No left gunner!"), false, '1 0 0' * picsize.y + '0 1 0' * picsize.y));
+ drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
+ drawstring(hudloc + picloc + '1 0 0' * shield, _("No left gunner!"), '1 0 0' * picsize.y + '0 1 0' * picsize.y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
+ }
+
+// .. and icon
+ picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+ if(ammo2 < 0.2)
+ drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+ if (scoreboard_showscores)
+ HUD_DrawScoreboard();
+ else
+ {
+ picsize = draw_getimagesize(waki_xhair);
+ picsize.x *= 0.5;
+ picsize.y *= 0.5;
+ drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ }
+
+}
+
+void CSQC_BUMBLE_GUN_HUD()
+{
+
+ if(autocvar_r_letterbox)
+ return;
+
+ vector picsize, hudloc = '0 0 0', pic2size, picloc;
+
+ // Fetch health & ammo stats
+ HUD_GETSTATS
+
+ picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+ hudloc.y = vid_conheight - picsize.y;
+ hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+
+ drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+
+ shield *= 0.01;
+ vh_health *= 0.01;
+ energy *= 0.01;
+ reload1 *= 0.01;
+
+ pic2size = draw_getimagesize(bumb_gun_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+ picloc = picsize * 0.5 - pic2size * 0.5;
+
+ if(vh_health < 0.25)
+ drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
+
+ drawpic(hudloc + picloc, bumb_gun_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
+
+// Health bar
+ picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+ if(vh_health < 0.25)
+ {
+ if(alarm1time < time)
+ {
+ alarm1time = time + 2;
+ sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm1time)
+ {
+ sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm1time = 0;
+ }
+ }
+
+// Shield bar
+ picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+ picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+ if(shield < 0.25)
+ {
+ if(alarm2time < time)
+ {
+ alarm2time = time + 1;
+ sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm2time)
+ {
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm2time = 0;
+ }
+ }
+
+// Gun bar
+ picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+
+// .. and icon
+ picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+ if(energy < 0.2)
+ drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+ if (scoreboard_showscores)
+ HUD_DrawScoreboard();
+ /*
+ else
+ {
+ picsize = draw_getimagesize(waki_xhair);
+ picsize_x *= 0.5;
+ picsize_y *= 0.5;
+
+
+ drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ }
+ */
+}
+
+
+
+void CSQC_SPIDER_HUD()
+{
+ if(autocvar_r_letterbox)
+ return;
+
+ vector picsize, hudloc = '0 0 0', pic2size, picloc;
+ int i;
+
+ // Fetch health & ammo stats
+ HUD_GETSTATS
+
+ picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+ hudloc.y = vid_conheight - picsize.y;
+ hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+
+ drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+
+ ammo1 *= 0.01;
+ shield *= 0.01;
+ vh_health *= 0.01;
+ reload2 *= 0.01;
+
+ pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+ picloc = picsize * 0.5 - pic2size * 0.5;
+ if(vh_health < 0.25)
+ drawpic(hudloc + picloc, spider_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, spider_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, spider_rkt, pic2size, '1 1 1' * reload2 + '1 0 0' * (1 - reload2), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, spider_mgun, pic2size, '1 1 1' * ammo1 + '1 0 0' * (1 - ammo1), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
+
+// Health bar
+ picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+ if(vh_health < 0.25)
+ {
+ if(alarm1time < time)
+ {
+ alarm1time = time + 2;
+ sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm1time)
+ {
+ sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm1time = 0;
+ }
+ }
+// Shield bar
+ picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+ picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+ if(shield < 0.25)
+ {
+ if(alarm2time < time)
+ {
+ alarm2time = time + 1;
+ sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm2time)
+ {
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm2time = 0;
+ }
+ }
+
+// Minigun bar
+ picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo1, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+ if(ammo1 < 0.2)
+ drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+// Rocket ammo bar
+ picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+ ammo1 = picsize.x / 8;
+ picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload2, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+
+// .. and icons
+ pic2size = 0.35 * draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+ picloc.x -= pic2size.x;
+ picloc.y += pic2size.y * 2.25;
+ if(ammo2 == 9)
+ {
+ for(i = 1; i < 9; ++i)
+ {
+ picloc.x += ammo1;
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((8 * reload2 <= i) ? '0 0 0' : '1 1 1'), 0.75, DRAWFLAG_NORMAL);
+ }
+ }
+ else
+ {
+ for(i = 1; i < 9; ++i)
+ {
+ picloc.x += ammo1;
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((i >= ammo2) ? '1 1 1' : '0 0 0'), 0.75, DRAWFLAG_NORMAL);
+ }
+ }
+ pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+ if(ammo2 == 9)
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+ if (scoreboard_showscores)
+ HUD_DrawScoreboard();
+ else
+ {
+ switch(weapon2mode)
+ {
+ case SBRM_VOLLY:
+ spider_xhair = "gfx/vehicles/axh-bracket.tga";
+ break;
+ case SBRM_GUIDE:
+ spider_xhair = "gfx/vehicles/axh-cross.tga";
+ break;
+ case SBRM_ARTILLERY:
+ spider_xhair = "gfx/vehicles/axh-tag.tga";
+ break;
+ default:
+ spider_xhair= "gfx/vehicles/axh-tag.tga";
+ }
+
+ picsize = draw_getimagesize(spider_xhair);
+ picsize.x *= autocvar_cl_vehicle_spiderbot_cross_size;
+ picsize.y *= autocvar_cl_vehicle_spiderbot_cross_size;
+
+ drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), spider_xhair, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_ADDITIVE);
+ }
+}
+
+void CSQC_RAPTOR_HUD()
+{
+ if(autocvar_r_letterbox)
+ return;
+
+ vector picsize, hudloc = '0 0 0', pic2size, picloc;
+
+ // Fetch health & ammo stats
+ HUD_GETSTATS
+
+ picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+ hudloc.y = vid_conheight - picsize.y;
+ hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+
+ drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+
+ ammo1 *= 0.01;
+ ammo2 *= 0.01;
+ shield *= 0.01;
+ vh_health *= 0.01;
+ energy *= 0.01;
+ reload1 = reload2 * 0.01;
+ //reload2 *= 0.01;
+
+ pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+ picloc = picsize * 0.5 - pic2size * 0.5;
+ if(vh_health < 0.25)
+ drawpic(hudloc + picloc, raptor_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, raptor_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, raptor_bomb, pic2size, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, raptor_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
+
+// Health bar
+ picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+ if(vh_health < 0.25)
+ {
+ if(alarm1time < time)
+ {
+ alarm1time = time + 2;
+ sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm1time)
+ {
+ sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm1time = 0;
+ }
+ }
+
+// Shield bar
+ picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+ picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+ if(shield < 0.25)
+ {
+ if(alarm2time < time)
+ {
+ alarm2time = time + 1;
+ sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm2time)
+ {
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm2time = 0;
+ }
+ }
+
+// Gun bar
+ picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+ if(energy < 0.2)
+ drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+// Bomb bar
+ picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload1, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+ if(reload1 != 1)
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+ if(weapon2mode == RSM_FLARE)
+ {
+ raptor_xhair = "gfx/vehicles/axh-bracket.tga";
+ }
+ else
+ {
+ raptor_xhair = "gfx/vehicles/axh-ring.tga";
+
+ // Bombing crosshair
+ if(!dropmark)
+ {
+ dropmark = spawn();
+ dropmark.owner = self;
+ dropmark.gravity = 1;
+ }
+
+ if(reload2 == 100)
+ {
+ vector where;
+
+ setorigin(dropmark, pmove_org);
+ dropmark.velocity = pmove_vel;
+ tracetoss(dropmark, self);
+
+ where = project_3d_to_2d(trace_endpos);
+
+ setorigin(dropmark, trace_endpos);
+ picsize = draw_getimagesize(raptor_drop) * 0.2;
+
+ if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
+ {
+ where.x -= picsize.x * 0.5;
+ where.y -= picsize.y * 0.5;
+ where.z = 0;
+ drawpic(where, raptor_drop, picsize, '0 2 0', 1, DRAWFLAG_ADDITIVE);
+ }
+ dropmark.cnt = time + 5;
+ }
+ else
+ {
+ vector where;
+ if(dropmark.cnt > time)
+ {
+ where = project_3d_to_2d(dropmark.origin);
+ picsize = draw_getimagesize(raptor_drop) * 0.25;
+
+ if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
+ {
+ where.x -= picsize.x * 0.5;
+ where.y -= picsize.y * 0.5;
+ where.z = 0;
+ drawpic(where, raptor_drop, picsize, '2 0 0', 1, DRAWFLAG_ADDITIVE);
+ }
+ }
+ }
+ }
+
+ if (scoreboard_showscores)
+ HUD_DrawScoreboard();
+ else
+ {
+ picsize = draw_getimagesize(raptor_xhair);
+ picsize.x *= 0.5;
+ picsize.y *= 0.5;
+
+ drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), raptor_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ }
+}
+
+void CSQC_WAKIZASHI_HUD()
+{
+/*
+ drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
+ drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0' * (1 - health), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc, waki_r, picsize, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+*/
+ if(autocvar_r_letterbox)
+ return;
+
+ vector picsize, hudloc = '0 0 0', pic2size, picloc;
+
+ // Fetch health & ammo stats
+ HUD_GETSTATS
+
+ picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+ hudloc.y = vid_conheight - picsize.y;
+ hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+
+ drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+
+ shield *= 0.01;
+ vh_health *= 0.01;
+ energy *= 0.01;
+ reload1 *= 0.01;
+
+ pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+ picloc = picsize * 0.5 - pic2size * 0.5;
+ if(vh_health < 0.25)
+ drawpic(hudloc + picloc, waki_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, waki_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, waki_eng, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, waki_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, waki_rkt, pic2size, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+ drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
+
+// Health bar
+ picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+ if(vh_health < 0.25)
+ {
+ if(alarm1time < time)
+ {
+ alarm1time = time + 2;
+ sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm1time)
+ {
+ sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm1time = 0;
+ }
+ }
+
+
+// Shield bar
+ picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+ drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+ picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+ if(shield < 0.25)
+ {
+ if(alarm2time < time)
+ {
+ alarm2time = time + 1;
+ sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+ }
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ }
+ else
+ {
+ drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ if(alarm2time)
+ {
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+ alarm2time = 0;
+ }
+ }
+
+// Gun bar
+ picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+ if(energy < 0.2)
+ drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+// Bomb bar
+ picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+ picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+ drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload1, vid_conheight);
+ drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+// .. and icon
+ pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+ picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+ if(reload1 != 1)
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+ else
+ drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
+
+ if (scoreboard_showscores)
+ HUD_DrawScoreboard();
+ else
+ {
+ picsize = draw_getimagesize(waki_xhair);
+ picsize.x *= 0.5;
+ picsize.y *= 0.5;
+
+
+ drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ }
+}
+
+void Vehicles_Precache()
+{
+ precache_model("models/vehicles/bomblet.md3");
+ precache_model("models/vehicles/clusterbomb.md3");
+ precache_model("models/vehicles/clusterbomb_fragment.md3");
+ precache_model("models/vehicles/rocket01.md3");
+ precache_model("models/vehicles/rocket02.md3");
+
+ precache_sound ("vehicles/alarm.wav");
+ precache_sound ("vehicles/alarm_shield.wav");
+}
+
+void RaptorCBShellfragDraw()
+{
+ if(wasfreed(self))
+ return;
+
+ Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
+ self.move_avelocity += randomvec() * 15;
+ self.renderflags = 0;
+
+ if(self.cnt < time)
+ self.alpha = bound(0, self.nextthink - time, 1);
+
+ if(self.alpha < ALPHA_MIN_VISIBLE)
+ remove(self);
+}
+
+void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
+{
+ entity sfrag;
+
+ sfrag = spawn();
+ setmodel(sfrag, "models/vehicles/clusterbomb_fragment.md3");
+ setorigin(sfrag, _org);
+
+ sfrag.move_movetype = MOVETYPE_BOUNCE;
+ sfrag.gravity = 0.15;
+ sfrag.solid = SOLID_CORPSE;
+
+ sfrag.draw = RaptorCBShellfragDraw;
+
+ sfrag.move_origin = sfrag.origin = _org;
+ sfrag.move_velocity = _vel;
+ sfrag.move_avelocity = prandomvec() * vlen(sfrag.move_velocity);
+ sfrag.angles = self.move_angles = _ang;
+
+ sfrag.move_time = time;
+ sfrag.damageforcescale = 4;
+
+ sfrag.nextthink = time + 3;
+ sfrag.cnt = time + 2;
+ sfrag.alpha = 1;
+ sfrag.drawmask = MASK_NORMAL;
+}
--- /dev/null
+#ifndef VEHICLES_ALL_H
+#define VEHICLES_ALL_H
+
+void RaptorCBShellfragDraw();
+void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang);
+void Vehicles_Precache();
+void Net_AuXair2(bool bIsNew);
+void Net_VehicleSetup();
+
+void CSQC_WAKIZASHI_HUD();
+void CSQC_SPIDER_HUD();
+void CSQC_RAPTOR_HUD();
+void CSQC_BUMBLE_HUD();
+void CSQC_BUMBLE_GUN_HUD();
+
+#endif
--- /dev/null
+#include "../damage.qh"
+#include "../defs.qh"
+#include "../gibs.qh"
+#include "../hook.qh"
+#include "../main.qh"
+#include "../wall.qh"
+
+#include "../weapons/projectile.qh"
+
+#include "../../common/movetypes/movetypes.qh"
+
+#include "../../server/vehicles/bumblebee.qc"
--- /dev/null
+#include "../../server/vehicles/bumblebee.qh"
+++ /dev/null
-#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
- #include "../defs.qh"
- #include "../../common/constants.qh"
- #include "../../common/stats.qh"
- #include "../../common/util.qh"
- #include "../../common/buffs.qh"
- #include "../autocvars.qh"
- #include "../movetypes.qh"
- #include "../prandom.qh"
- #include "../main.qh"
- #include "vehicles.qh"
- #include "../../csqcmodellib/cl_model.qh"
- #include "../../server/t_items.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-const string hud_bg = "gfx/vehicles/frame.tga";
-const string hud_sh = "gfx/vehicles/vh-shield.tga";
-
-const string hud_hp_bar = "gfx/vehicles/bar_up_left.tga";
-const string hud_hp_ico = "gfx/vehicles/health.tga";
-const string hud_sh_bar = "gfx/vehicles/bar_dwn_left.tga";
-const string hud_sh_ico = "gfx/vehicles/shield.tga";
-
-const string hud_ammo1_bar = "gfx/vehicles/bar_up_right.tga";
-const string hud_ammo1_ico = "gfx/vehicles/bullets.tga";
-const string hud_ammo2_bar = "gfx/vehicles/bar_dwn_right.tga";
-const string hud_ammo2_ico = "gfx/vehicles/rocket.tga";
-const string hud_energy = "gfx/vehicles/energy.tga";
-
-const int SBRM_FIRST = 1;
-const int SBRM_VOLLY = 1;
-const int SBRM_GUIDE = 2;
-const int SBRM_ARTILLERY = 3;
-const int SBRM_LAST = 3;
-
-const int RSM_FIRST = 1;
-const int RSM_BOMB = 1;
-const int RSM_FLARE = 2;
-const int RSM_LAST = 2;
-
-entity dropmark;
-float autocvar_cl_vehicles_hudscale = 0.5;
-float autocvar_cl_vehicles_hudalpha = 0.75;
-
-const string raptor_ico = "gfx/vehicles/raptor.tga";
-const string raptor_gun = "gfx/vehicles/raptor_guns.tga";
-const string raptor_bomb = "gfx/vehicles/raptor_bombs.tga";
-const string raptor_drop = "gfx/vehicles/axh-dropcross.tga";
-string raptor_xhair;
-
-void CSQC_WAKIZASHI_HUD();
-void CSQC_SPIDER_HUD();
-void CSQC_RAPTOR_HUD();
-void CSQC_BUMBLE_HUD();
-void CSQC_BUMBLE_GUN_HUD();
-
-const int MAX_AXH = 4;
-entity AuxiliaryXhair[MAX_AXH];
-
-.string axh_image;
-.float axh_fadetime;
-.float axh_drawflag;
-.float axh_scale;
-
-const string bumb_ico = "gfx/vehicles/bumb.tga";
-const string bumb_lgun = "gfx/vehicles/bumb_lgun.tga";
-const string bumb_rgun = "gfx/vehicles/bumb_rgun.tga";
-
-const string bumb_gun_ico = "gfx/vehicles/bumb_side.tga";
-const string bumb_gun_gun = "gfx/vehicles/bumb_side_gun.tga";
-
-const string spider_ico = "gfx/vehicles/sbot.tga";
-const string spider_rkt = "gfx/vehicles/sbot_rpods.tga";
-const string spider_mgun = "gfx/vehicles/sbot_mguns.tga";
-string spider_xhair; // = "gfx/vehicles/axh-special1.tga";
-
-const string waki_ico = "gfx/vehicles/waki.tga";
-const string waki_eng = "gfx/vehicles/waki_e.tga";
-const string waki_gun = "gfx/vehicles/waki_guns.tga";
-const string waki_rkt = "gfx/vehicles/waki_rockets.tga";
-const string waki_xhair = "gfx/vehicles/axh-special1.tga";
-
-float alarm1time;
-float alarm2time;
-int weapon2mode;
-
-void AuxiliaryXhair_Draw2D()
-{
- vector loc, psize;
-
- psize = self.axh_scale * draw_getimagesize(self.axh_image);
- loc = project_3d_to_2d(self.move_origin) - 0.5 * psize;
- if (!(loc.z < 0 || loc.x < 0 || loc.y < 0 || loc.x > vid_conwidth || loc.y > vid_conheight))
- {
- loc.z = 0;
- psize.z = 0;
- drawpic(loc, self.axh_image, psize, self.colormod, self.alpha, self.axh_drawflag);
- }
-
- if(time - self.cnt > self.axh_fadetime)
- self.draw2d = func_null;
-}
-
-void Net_AuXair2(bool bIsNew)
-{
- int axh_id = bound(0, ReadByte(), MAX_AXH);
- entity axh = AuxiliaryXhair[axh_id];
-
- if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
- {
- axh = spawn();
- axh.draw2d = func_null;
- axh.drawmask = MASK_NORMAL;
- axh.axh_drawflag = DRAWFLAG_ADDITIVE;
- axh.axh_fadetime = 0.1;
- axh.axh_image = "gfx/vehicles/axh-ring.tga";
- axh.axh_scale = 1;
- axh.alpha = 1;
- AuxiliaryXhair[axh_id] = axh;
- }
-
- axh.move_origin_x = ReadCoord();
- axh.move_origin_y = ReadCoord();
- axh.move_origin_z = ReadCoord();
- axh.colormod_x = ReadByte() / 255;
- axh.colormod_y = ReadByte() / 255;
- axh.colormod_z = ReadByte() / 255;
- axh.cnt = time;
- axh.draw2d = AuxiliaryXhair_Draw2D;
-}
-
-void Net_VehicleSetup()
-{
- int hud_id = ReadByte();
-
- // Weapon update?
- if(hud_id > HUD_VEHICLE_LAST)
- {
- weapon2mode = hud_id - HUD_VEHICLE_LAST;
- return;
- }
-
- // hud_id == 0 means we exited a vehicle, so stop alarm sound/s
- if(hud_id == 0)
- {
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- return;
- }
-
- hud_id = bound(HUD_VEHICLE_FIRST, hud_id, HUD_VEHICLE_LAST);
-
- // Init auxiliary crosshairs
- int i;
- for(i = 0; i < MAX_AXH; ++i)
- {
- entity axh = AuxiliaryXhair[i];
- if(axh != world && !wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
- remove(axh);
-
- axh = spawn();
- axh.draw2d = func_null;
- axh.drawmask = MASK_NORMAL;
- axh.axh_drawflag = DRAWFLAG_NORMAL;
- axh.axh_fadetime = 0.1;
- axh.axh_image = "gfx/vehicles/axh-ring.tga";
- axh.axh_scale = 1;
- axh.alpha = 1;
- AuxiliaryXhair[i] = axh;
- }
-
- switch(hud_id)
- {
- case HUD_SPIDERBOT:
- // Minigun1
- AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-ring.tga";
- AuxiliaryXhair[0].axh_scale = 0.25;
- // Minigun2
- AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-ring.tga";
- AuxiliaryXhair[1].axh_scale = 0.25;
- // Rocket
- AuxiliaryXhair[2].axh_image = "gfx/vehicles/axh-special1.tga";
- AuxiliaryXhair[2].axh_scale = 0.5;
- break;
-
- case HUD_WAKIZASHI:
- AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga";
- AuxiliaryXhair[0].axh_scale = 0.25;
- break;
-
- case HUD_RAPTOR:
- AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-special2.tga";
- AuxiliaryXhair[0].axh_scale = 0.5;
- //AuxiliaryXhair[0].alpha = 0.5;
-
- AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-bracket.tga";
- AuxiliaryXhair[1].axh_scale = 0.25;
- //AuxiliaryXhair[1].alpha = 0.75;
- //AuxiliaryXhair[1].axh_drawflag = DRAWFLAG_NORMAL;
- break;
-
- case HUD_BUMBLEBEE:
- // Raygun-locked
- AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga";
- AuxiliaryXhair[0].axh_scale = 0.5;
-
- // Gunner1
- AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-target.tga";
- AuxiliaryXhair[1].axh_scale = 0.75;
-
- // Gunner2
- AuxiliaryXhair[2].axh_image = "gfx/vehicles/axh-target.tga";
- AuxiliaryXhair[2].axh_scale = 0.75;
- break;
- case HUD_BUMBLEBEE_GUN:
- // Plasma cannons
- AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga";
- AuxiliaryXhair[0].axh_scale = 0.25;
- // Raygun
- AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-bracket.tga";
- AuxiliaryXhair[1].axh_scale = 0.25;
- break;
- }
-}
-#define HUD_GETSTATS \
- int vh_health = getstati(STAT_VEHICLESTAT_HEALTH); \
- float shield = getstati(STAT_VEHICLESTAT_SHIELD); \
- noref int energy = getstati(STAT_VEHICLESTAT_ENERGY); \
- noref float ammo1 = getstati(STAT_VEHICLESTAT_AMMO1); \
- noref float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1); \
- noref int ammo2 = getstati(STAT_VEHICLESTAT_AMMO2); \
- noref int reload2 = getstati(STAT_VEHICLESTAT_RELOAD2);
-
-void CSQC_BUMBLE_HUD()
-{
-/*
- drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
- drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0' * (1 - health), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc, waki_r, picsize, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
-*/
- if(autocvar_r_letterbox)
- return;
-
- vector picsize, hudloc = '0 0 0', pic2size, picloc;
-
- // Fetch health & ammo stats
- HUD_GETSTATS
-
- picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
- hudloc.y = vid_conheight - picsize.y;
- hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
-
- drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
-
- shield *= 0.01;
- vh_health *= 0.01;
- energy *= 0.01;
- reload1 *= 0.01;
-
- pic2size = draw_getimagesize(bumb_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
- picloc = picsize * 0.5 - pic2size * 0.5;
-
- if(vh_health < 0.25)
- drawpic(hudloc + picloc, bumb_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, bumb_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
-
- drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
-
-// Health bar
- picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
- if(vh_health < 0.25)
- {
- if(alarm1time < time)
- {
- alarm1time = time + 2;
- sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
-
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm1time)
- {
- sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm1time = 0;
- }
- }
-
-// Shield bar
- picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
- picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
- if(shield < 0.25)
- {
- if(alarm2time < time)
- {
- alarm2time = time + 1;
- sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm2time)
- {
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm2time = 0;
- }
- }
-
- ammo1 *= 0.01;
- ammo2 *= 0.01;
-
-// Gunner1 bar
- picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo1, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-
-// Right gunner slot occupied?
- if(!AuxiliaryXhair[1].draw2d)
- {
- shield = (picsize.x * 0.5) - (0.5 * stringwidth(_("No right gunner!"), false, '1 0 0' * picsize.y + '0 1 0' * picsize.y));
- drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
- drawstring(hudloc + picloc + '1 0 0' * shield, _("No right gunner!"), '1 0 0' * picsize.y + '0 1 0' * picsize.y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
- }
-
-// .. and icon
- picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
- picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
- if(ammo1 < 0.2)
- drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-
-// Gunner2 bar
- picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo2, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// Left gunner slot occupied?
- if(!AuxiliaryXhair[2].draw2d)
- {
- shield = (picsize.x * 0.5) - (0.5 * stringwidth(_("No left gunner!"), false, '1 0 0' * picsize.y + '0 1 0' * picsize.y));
- drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
- drawstring(hudloc + picloc + '1 0 0' * shield, _("No left gunner!"), '1 0 0' * picsize.y + '0 1 0' * picsize.y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
- }
-
-// .. and icon
- picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
- picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
- if(ammo2 < 0.2)
- drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-
- if (scoreboard_showscores)
- HUD_DrawScoreboard();
- else
- {
- picsize = draw_getimagesize(waki_xhair);
- picsize.x *= 0.5;
- picsize.y *= 0.5;
- drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- }
-
-}
-
-void CSQC_BUMBLE_GUN_HUD()
-{
-
- if(autocvar_r_letterbox)
- return;
-
- vector picsize, hudloc = '0 0 0', pic2size, picloc;
-
- // Fetch health & ammo stats
- HUD_GETSTATS
-
- picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
- hudloc.y = vid_conheight - picsize.y;
- hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
-
- drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
-
- shield *= 0.01;
- vh_health *= 0.01;
- energy *= 0.01;
- reload1 *= 0.01;
-
- pic2size = draw_getimagesize(bumb_gun_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
- picloc = picsize * 0.5 - pic2size * 0.5;
-
- if(vh_health < 0.25)
- drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
-
- drawpic(hudloc + picloc, bumb_gun_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
-
-// Health bar
- picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
- if(vh_health < 0.25)
- {
- if(alarm1time < time)
- {
- alarm1time = time + 2;
- sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
-
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm1time)
- {
- sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm1time = 0;
- }
- }
-
-// Shield bar
- picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
- picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
- if(shield < 0.25)
- {
- if(alarm2time < time)
- {
- alarm2time = time + 1;
- sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm2time)
- {
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm2time = 0;
- }
- }
-
-// Gun bar
- picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-
-// .. and icon
- picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
- picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
- if(energy < 0.2)
- drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-
- if (scoreboard_showscores)
- HUD_DrawScoreboard();
- /*
- else
- {
- picsize = draw_getimagesize(waki_xhair);
- picsize_x *= 0.5;
- picsize_y *= 0.5;
-
-
- drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- }
- */
-}
-
-
-
-void CSQC_SPIDER_HUD()
-{
- if(autocvar_r_letterbox)
- return;
-
- vector picsize, hudloc = '0 0 0', pic2size, picloc;
- int i;
-
- // Fetch health & ammo stats
- HUD_GETSTATS
-
- picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
- hudloc.y = vid_conheight - picsize.y;
- hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
-
- drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
-
- ammo1 *= 0.01;
- shield *= 0.01;
- vh_health *= 0.01;
- reload2 *= 0.01;
-
- pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
- picloc = picsize * 0.5 - pic2size * 0.5;
- if(vh_health < 0.25)
- drawpic(hudloc + picloc, spider_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, spider_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, spider_rkt, pic2size, '1 1 1' * reload2 + '1 0 0' * (1 - reload2), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, spider_mgun, pic2size, '1 1 1' * ammo1 + '1 0 0' * (1 - ammo1), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
-
-// Health bar
- picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
- if(vh_health < 0.25)
- {
- if(alarm1time < time)
- {
- alarm1time = time + 2;
- sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm1time)
- {
- sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm1time = 0;
- }
- }
-// Shield bar
- picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
- picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
- if(shield < 0.25)
- {
- if(alarm2time < time)
- {
- alarm2time = time + 1;
- sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm2time)
- {
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm2time = 0;
- }
- }
-
-// Minigun bar
- picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo1, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
- if(ammo1 < 0.2)
- drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-
-// Rocket ammo bar
- picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
- ammo1 = picsize.x / 8;
- picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload2, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-
-// .. and icons
- pic2size = 0.35 * draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
- picloc.x -= pic2size.x;
- picloc.y += pic2size.y * 2.25;
- if(ammo2 == 9)
- {
- for(i = 1; i < 9; ++i)
- {
- picloc.x += ammo1;
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((8 * reload2 <= i) ? '0 0 0' : '1 1 1'), 0.75, DRAWFLAG_NORMAL);
- }
- }
- else
- {
- for(i = 1; i < 9; ++i)
- {
- picloc.x += ammo1;
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((i >= ammo2) ? '1 1 1' : '0 0 0'), 0.75, DRAWFLAG_NORMAL);
- }
- }
- pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
- if(ammo2 == 9)
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
-
- if (scoreboard_showscores)
- HUD_DrawScoreboard();
- else
- {
- switch(weapon2mode)
- {
- case SBRM_VOLLY:
- spider_xhair = "gfx/vehicles/axh-bracket.tga";
- break;
- case SBRM_GUIDE:
- spider_xhair = "gfx/vehicles/axh-cross.tga";
- break;
- case SBRM_ARTILLERY:
- spider_xhair = "gfx/vehicles/axh-tag.tga";
- break;
- default:
- spider_xhair= "gfx/vehicles/axh-tag.tga";
- }
-
- picsize = draw_getimagesize(spider_xhair);
- picsize.x *= autocvar_cl_vehicle_spiderbot_cross_size;
- picsize.y *= autocvar_cl_vehicle_spiderbot_cross_size;
-
- drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), spider_xhair, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_ADDITIVE);
- }
-}
-
-void CSQC_RAPTOR_HUD()
-{
- if(autocvar_r_letterbox)
- return;
-
- vector picsize, hudloc = '0 0 0', pic2size, picloc;
-
- // Fetch health & ammo stats
- HUD_GETSTATS
-
- picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
- hudloc.y = vid_conheight - picsize.y;
- hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
-
- drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
-
- ammo1 *= 0.01;
- ammo2 *= 0.01;
- shield *= 0.01;
- vh_health *= 0.01;
- energy *= 0.01;
- reload1 = reload2 * 0.01;
- //reload2 *= 0.01;
-
- pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
- picloc = picsize * 0.5 - pic2size * 0.5;
- if(vh_health < 0.25)
- drawpic(hudloc + picloc, raptor_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, raptor_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, raptor_bomb, pic2size, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, raptor_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
-
-// Health bar
- picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
- if(vh_health < 0.25)
- {
- if(alarm1time < time)
- {
- alarm1time = time + 2;
- sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
-
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm1time)
- {
- sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm1time = 0;
- }
- }
-
-// Shield bar
- picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
- picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
- if(shield < 0.25)
- {
- if(alarm2time < time)
- {
- alarm2time = time + 1;
- sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm2time)
- {
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm2time = 0;
- }
- }
-
-// Gun bar
- picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
- if(energy < 0.2)
- drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-
-// Bomb bar
- picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload1, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
- if(reload1 != 1)
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
-
- if(weapon2mode == RSM_FLARE)
- {
- raptor_xhair = "gfx/vehicles/axh-bracket.tga";
- }
- else
- {
- raptor_xhair = "gfx/vehicles/axh-ring.tga";
-
- // Bombing crosshair
- if(!dropmark)
- {
- dropmark = spawn();
- dropmark.owner = self;
- dropmark.gravity = 1;
- }
-
- if(reload2 == 100)
- {
- vector where;
-
- setorigin(dropmark, pmove_org);
- dropmark.velocity = pmove_vel;
- tracetoss(dropmark, self);
-
- where = project_3d_to_2d(trace_endpos);
-
- setorigin(dropmark, trace_endpos);
- picsize = draw_getimagesize(raptor_drop) * 0.2;
-
- if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
- {
- where.x -= picsize.x * 0.5;
- where.y -= picsize.y * 0.5;
- where.z = 0;
- drawpic(where, raptor_drop, picsize, '0 2 0', 1, DRAWFLAG_ADDITIVE);
- }
- dropmark.cnt = time + 5;
- }
- else
- {
- vector where;
- if(dropmark.cnt > time)
- {
- where = project_3d_to_2d(dropmark.origin);
- picsize = draw_getimagesize(raptor_drop) * 0.25;
-
- if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
- {
- where.x -= picsize.x * 0.5;
- where.y -= picsize.y * 0.5;
- where.z = 0;
- drawpic(where, raptor_drop, picsize, '2 0 0', 1, DRAWFLAG_ADDITIVE);
- }
- }
- }
- }
-
- if (scoreboard_showscores)
- HUD_DrawScoreboard();
- else
- {
- picsize = draw_getimagesize(raptor_xhair);
- picsize.x *= 0.5;
- picsize.y *= 0.5;
-
- drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), raptor_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- }
-}
-
-void CSQC_WAKIZASHI_HUD()
-{
-/*
- drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
- drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0' * (1 - health), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc, waki_r, picsize, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
-*/
- if(autocvar_r_letterbox)
- return;
-
- vector picsize, hudloc = '0 0 0', pic2size, picloc;
-
- // Fetch health & ammo stats
- HUD_GETSTATS
-
- picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
- hudloc.y = vid_conheight - picsize.y;
- hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
-
- drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
-
- shield *= 0.01;
- vh_health *= 0.01;
- energy *= 0.01;
- reload1 *= 0.01;
-
- pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
- picloc = picsize * 0.5 - pic2size * 0.5;
- if(vh_health < 0.25)
- drawpic(hudloc + picloc, waki_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, waki_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, waki_eng, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, waki_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, waki_rkt, pic2size, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
- drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL);
-
-// Health bar
- picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
- if(vh_health < 0.25)
- {
- if(alarm1time < time)
- {
- alarm1time = time + 2;
- sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
-
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm1time)
- {
- sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm1time = 0;
- }
- }
-
-
-// Shield bar
- picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
- drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
- picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
- if(shield < 0.25)
- {
- if(alarm2time < time)
- {
- alarm2time = time + 1;
- sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
- }
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- }
- else
- {
- drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- if(alarm2time)
- {
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
- alarm2time = 0;
- }
- }
-
-// Gun bar
- picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
- if(energy < 0.2)
- drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-
-// Bomb bar
- picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
- picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
- drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload1, vid_conheight);
- drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- drawresetcliparea();
-// .. and icon
- pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
- picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
- if(reload1 != 1)
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
- else
- drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
-
- if (scoreboard_showscores)
- HUD_DrawScoreboard();
- else
- {
- picsize = draw_getimagesize(waki_xhair);
- picsize.x *= 0.5;
- picsize.y *= 0.5;
-
-
- drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
- }
-}
-
-void Vehicles_Precache()
-{
- precache_model("models/vehicles/bomblet.md3");
- precache_model("models/vehicles/clusterbomb.md3");
- precache_model("models/vehicles/clusterbomb_fragment.md3");
- precache_model("models/vehicles/rocket01.md3");
- precache_model("models/vehicles/rocket02.md3");
-
- precache_sound ("vehicles/alarm.wav");
- precache_sound ("vehicles/alarm_shield.wav");
-}
-
-void RaptorCBShellfragDraw()
-{
- if(wasfreed(self))
- return;
-
- Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
- self.move_avelocity += randomvec() * 15;
- self.renderflags = 0;
-
- if(self.cnt < time)
- self.alpha = bound(0, self.nextthink - time, 1);
-
- if(self.alpha < ALPHA_MIN_VISIBLE)
- remove(self);
-}
-
-void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
-{
- entity sfrag;
-
- sfrag = spawn();
- setmodel(sfrag, "models/vehicles/clusterbomb_fragment.md3");
- setorigin(sfrag, _org);
-
- sfrag.move_movetype = MOVETYPE_BOUNCE;
- sfrag.gravity = 0.15;
- sfrag.solid = SOLID_CORPSE;
-
- sfrag.draw = RaptorCBShellfragDraw;
-
- sfrag.move_origin = sfrag.origin = _org;
- sfrag.move_velocity = _vel;
- sfrag.move_avelocity = prandomvec() * vlen(sfrag.move_velocity);
- sfrag.angles = self.move_angles = _ang;
-
- sfrag.move_time = time;
- sfrag.damageforcescale = 4;
-
- sfrag.nextthink = time + 3;
- sfrag.cnt = time + 2;
- sfrag.alpha = 1;
- sfrag.drawmask = MASK_NORMAL;
-}
+++ /dev/null
-#ifndef VEHICLES_H
-#define VEHICLES_H
-
-void RaptorCBShellfragDraw();
-void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang);
-void Vehicles_Precache();
-void Net_AuXair2(bool bIsNew);
-void Net_VehicleSetup();
-#endif
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "defs.qh"
- #include "../common/constants.qh"
- #include "../common/stats.qh"
- #include "../warpzonelib/mathlib.qh"
- #include "../warpzonelib/common.qh"
- #include "../warpzonelib/client.qh"
- #include "../common/teams.qh"
- #include "../common/util.qh"
- #include "../common/nades.qh"
- #include "../common/weapons/weapons.qh"
- #include "../common/mapinfo.qh"
- #include "autocvars.qh"
- #include "hud.qh"
- #include "scoreboard.qh"
- #include "noise.qh"
- #include "main.qh"
- #include "../csqcmodellib/cl_player.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "_all.qh"
+
+#include "announcer.qh"
+#include "hook.qh"
+#include "hud.qh"
+#include "hud_config.qh"
+#include "mapvoting.qh"
+#include "noise.qh"
+#include "scoreboard.qh"
+#include "shownames.qh"
+#include "vehicles/all.qh"
+#include "waypointsprites.qh"
+
+#include "../common/constants.qh"
+#include "../common/mapinfo.qh"
+#include "../common/nades.qh"
+#include "../common/stats.qh"
+#include "../common/triggers/target/music.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
+
+#include "../common/weapons/all.qh"
+
+#include "../csqcmodellib/cl_player.qh"
+
+#include "../warpzonelib/client.qh"
+#include "../warpzonelib/common.qh"
+#include "../warpzonelib/mathlib.qh"
entity porto;
vector polyline[16];
#include "wall.qh"
+#include "_all.qh"
+
+#include "bgmscript.qh"
+
+#include "../common/util.qh"
+
+#include "../csqcmodellib/interpolate.qh"
+
+.float alpha;
+.float scale;
+.vector movedir;
+
+void Ent_Wall_PreDraw()
+{
+ if (self.inactive)
+ {
+ self.alpha = 0;
+ }
+ else
+ {
+ vector org = getpropertyvec(VF_ORIGIN);
+ if(!checkpvs(org, self))
+ self.alpha = 0;
+ else if(self.fade_start || self.fade_end) {
+ vector offset = '0 0 0';
+ offset_z = self.fade_vertical_offset;
+ float player_dist = vlen(org - self.origin - 0.5 * (self.mins + self.maxs) + offset);
+ if (self.fade_end == self.fade_start)
+ {
+ if (player_dist >= self.fade_start)
+ self.alpha = 0;
+ else
+ self.alpha = 1;
+ }
+ else
+ {
+ self.alpha = (self.alpha_min + self.alpha_max * bound(0,
+ (self.fade_end - player_dist)
+ / (self.fade_end - self.fade_start), 1)) / 100.0;
+ }
+ }
+ else
+ {
+ self.alpha = 1;
+ }
+ }
+ if(self.alpha <= 0)
+ self.drawmask = 0;
+ else
+ self.drawmask = MASK_NORMAL;
+}
void Ent_Wall_Draw()
{
fld = angles;
else
fld = origin;
- self.fld = self.saved;
+ self.(fld) = self.saved;
if(self.lodmodelindex1)
{
InterpolateOrigin_Do();
- self.saved = self.fld;
+ self.saved = self.(fld);
- f = BGMScript(self);
+ f = doBGMScript(self);
if(f >= 0)
{
if(self.lip < 0) // < 0: alpha goes from 1 to 1-|lip| when toggled (toggling subtracts lip)
self.alpha = 1 + self.lip * f;
else // > 0: alpha goes from 1-|lip| to 1 when toggled (toggling adds lip)
self.alpha = 1 - self.lip * (1 - f);
- self.fld = self.fld + self.movedir * f;
+ self.(fld) = self.(fld) + self.movedir * f;
}
else
self.alpha = 1;
fld = angles;
else
fld = origin;
- self.fld = self.saved;
+ self.(fld) = self.saved;
f = ReadByte();
self.movedir_z = ReadCoord();
self.lip = ReadByte() / 255.0;
}
+ self.fade_start = ReadShort();
+ self.fade_end = ReadShort();
+ self.alpha_max = ReadShort();
+ self.alpha_min = ReadShort();
+ self.inactive = ReadShort();
+ self.fade_vertical_offset = ReadShort();
BGMScript_InitEntity(self);
}
InterpolateOrigin_Note();
- self.saved = self.fld;
+ self.saved = self.(fld);
self.entremove = Ent_Wall_Remove;
self.draw = Ent_Wall_Draw;
+ self.predraw = Ent_Wall_PreDraw;
}
#ifndef WALL_H
#define WALL_H
-.float lip;
-.float bgmscriptangular;
-.int lodmodelindex0, lodmodelindex1, lodmodelindex2;
-.float loddistance1, loddistance2;
-.vector saved;
+entityclass(Wall);
+class(Wall) .float lip;
+class(Wall) .float bgmscriptangular;
+class(Wall) .int lodmodelindex0, lodmodelindex1, lodmodelindex2;
+class(Wall) .float loddistance1, loddistance2;
+class(Wall) .vector saved;
+
+// Needed for interactive clientwalls
+.float inactive; // Clientwall disappears when inactive
+.float alpha_max, alpha_min;
+// If fade_start > fade_end, fadeout will be inverted
+// fade_vertical_offset is a vertival offset for player position
+.float fade_start, fade_end, fade_vertical_offset;
+.float default_solid;
void Ent_Wall_Draw();
#include "waypointsprites.qh"
+#include "_all.qh"
+
+#include "hud.qh"
+#include "teamradar.qh"
+
+#include "../common/buffs.qh"
+#include "../common/constants.qh"
+#include "../common/teams.qh"
+
+#include "../common/weapons/all.qh"
+
+#include "../csqcmodellib/interpolate.qh"
+
+#include "../warpzonelib/mathlib.qh"
+
+.float alpha;
void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
{
R_EndPolygon();
}
-void drawhealthbar(vector org, float rot, float h, vector sz, vector hotspot, float width, float height, float margin, float border, float align, vector rgb, float a, vector hrgb, float ha, float f)
+void drawhealthbar(vector org, float rot, float h, vector sz, vector hotspot, float width, float theheight, float margin, float border, float align, vector rgb, float a, vector hrgb, float ha, float f)
{
vector o, ri, up;
float owidth; // outer width
up = rotate(up, rot);
owidth = width + 2 * border;
- o = o - up * (margin + border + height) + ri * (sz.x - owidth) * 0.5;
+ o = o - up * (margin + border + theheight) + ri * (sz.x - owidth) * 0.5;
drawquad(o - up * border, ri * owidth, up * border, "", rgb, a, f);
- drawquad(o + up * height, ri * owidth, up * border, "", rgb, a, f);
- drawquad(o, ri * border, up * height, "", rgb, a, f);
- drawquad(o + ri * (owidth - border), ri * border, up * height, "", rgb, a, f);
- drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * height, "", hrgb, ha, f);
+ drawquad(o + up * theheight, ri * owidth, up * border, "", rgb, a, f);
+ drawquad(o, ri * border, up * theheight, "", rgb, a, f);
+ drawquad(o + ri * (owidth - border), ri * border, up * theheight, "", rgb, a, f);
+ drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * theheight, "", hrgb, ha, f);
}
// returns location of sprite text
float waypointsprite_distancefadedistance;
float waypointsprite_alpha;
-.float helpme;
-.float rule;
-.string netname; // primary picture
-.string netname2; // secondary picture
-.string netname3; // tertiary picture
-.float team; // team that gets netname2
-.float lifetime;
-.float fadetime;
-.float maxdistance;
-.int hideflags;
-.float spawntime;
-.float health;
-.float build_started;
-.float build_starthealth;
-.float build_finished;
+entityclass(WaypointSprite);
+class(WaypointSprite) .float helpme;
+class(WaypointSprite) .float rule;
+class(WaypointSprite) .string netname; // primary picture
+class(WaypointSprite) .string netname2; // secondary picture
+class(WaypointSprite) .string netname3; // tertiary picture
+class(WaypointSprite) .int team; // team that gets netname2
+class(WaypointSprite) .float lifetime;
+class(WaypointSprite) .float fadetime;
+class(WaypointSprite) .float maxdistance;
+class(WaypointSprite) .int hideflags;
+class(WaypointSprite) .float spawntime;
+class(WaypointSprite) .float health;
+class(WaypointSprite) .float build_started;
+class(WaypointSprite) .float build_starthealth;
+class(WaypointSprite) .float build_finished;
const float SPRITE_HEALTHBAR_WIDTH = 144;
const float SPRITE_HEALTHBAR_HEIGHT = 9;
#include "projectile.qh"
+#include "../autocvars.qh"
+#include "../defs.qh"
+#include "../main.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/nades.qh"
+#include "../../common/movetypes/movetypes.qh"
+#include "../../common/util.qh"
+
+#include "../../csqcmodellib/interpolate.qh"
+
+#include "../../warpzonelib/anglestransform.qh"
+
+.float alpha;
+.float scale;
+.vector colormod;
+
void SUB_Stop()
{
self.move_velocity = self.move_avelocity = '0 0 0';
if(!(self.count & 0x80))
InterpolateOrigin_Note();
+ self.classname = "csqcprojectile";
self.draw = Projectile_Draw;
self.entremove = Ent_RemoveProjectile;
}
#ifndef PROJECTILE_H
#define PROJECTILE_H
-.int traileffect;
-
-.vector iorigin1, iorigin2;
-.float spawntime;
-.vector trail_oldorigin;
-.float trail_oldtime;
-.float fade_time, fade_rate;
-
-.float alphamod;
-.int count; // set if clientside projectile
-.int cnt; // sound index
-.float gravity;
-.int snd_looping;
-.bool silent;
+entityclass(Projectile);
+class(Projectile) .int traileffect;
+
+class(Projectile) .vector iorigin1, iorigin2;
+class(Projectile) .float spawntime;
+class(Projectile) .vector trail_oldorigin;
+class(Projectile) .float trail_oldtime;
+class(Projectile) .float fade_time, fade_rate;
+
+class(Projectile) .float alphamod;
+class(Projectile) .int count; // set if clientside projectile
+class(Projectile) .int cnt; // sound index
+class(Projectile) .float gravity;
+class(Projectile) .int snd_looping;
+class(Projectile) .bool silent;
void SUB_Stop();
upper = lower;
if(e.frame1time != upper.y || e.frame2time != lower.y)
BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
- e.fld_frame = upper.x;
- e.fld_frame1time = upper.y;
- e.fld_frame2 = lower.x;
- e.fld_frame2time = lower.y;
+ e.(fld_frame) = upper.x;
+ e.(fld_frame1time) = upper.y;
+ e.(fld_frame2) = lower.x;
+ e.(fld_frame2time) = lower.y;
}
else
{
upper = lower;
if(e.frame1time != upper.y)
BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
- e.fld_frame = upper.x;
- e.fld_frame1time = upper.y;
+ e.(fld_frame) = upper.x;
+ e.(fld_frame1time) = upper.y;
}
}
// Add new buffs here!
// Note: Buffs also need spawnfuncs, which are set below
+#include "teams.qh"
+#include "util.qh"
+
entity Buff_Type_first;
entity Buff_Type_last;
.entity enemy; // internal next pointer
--- /dev/null
+#include "generic.qc"
+#include "markup.qc"
+#include "rpn.qc"
--- /dev/null
+#ifndef COMMON_COMMANDS_ALL_H
+#define COMMON_COMMANDS_ALL_H
+
+#include "generic.qh"
+#include "markup.qh"
+#include "rpn.qh"
+
+#endif
--- /dev/null
+#ifndef COMMAND_H
+#define COMMAND_H
+
+// =========================================================
+// Shared declarations for all commands, written by Samual
+// Last updated: December 13th, 2011
+// =========================================================
+
+// identifiers for subfunction requests by the command code structure
+const int CMD_REQUEST_COMMAND = 1;
+const int CMD_REQUEST_USAGE = 2;
+#endif
+#include "command.qh"
#include "generic.qh"
-#include "shared_defs.qh"
+
+#include "markup.qh"
+#include "rpn.qh"
+
+#include "../mapinfo.qh"
+#include "../test.qh"
+
+#ifndef MENUQC
+ #include "../notifications.qh"
+#endif
+
+#ifdef CSQC
+ #include "../../client/command/cl_cmd.qh"
+#endif
+
+#ifdef SVQC
+ #include "../../server/command/banning.qh"
+ #include "../../server/command/cmd.qh"
+ #include "../../server/command/common.qh"
+ #include "../../server/command/sv_cmd.qh"
+
+ #include "../../common/weapons/config.qh"
+#endif
// =========================================================
// Generic program common command code, written by Samual
}
}
+void GenericCommand_dumpitems(float request)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ Dump_Items();
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ printf("\nUsage:^3 %s dumpitems", GetProgramCommandPrefix());
+ return;
+ }
+ }
+}
+
void GenericCommand_dumpnotifs(float request)
{
switch(request)
#define GENERIC_COMMANDS(request,arguments,command) \
GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar") \
GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \
+ GENERIC_COMMAND("dumpitems", GenericCommand_dumpitems(request), "Dump all items to the console") \
GENERIC_COMMAND("dumpnotifs", GenericCommand_dumpnotifs(request), "Dump all notifications into notifications_dump.txt") \
GENERIC_COMMAND("dumpweapons", GenericCommand_dumpweapons(request), "Dump all weapons into weapons_dump.txt") \
GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \
-#ifndef GENERIC_H
-#define GENERIC_H
+#ifndef COMMAND_GENERIC_H
+#define COMMAND_GENERIC_H
-#include "markup.qh"
-#include "rpn.qh"
+#include "../constants.qh"
// =========================================================
// Declarations for common command code, written by Samual
+#include "command.qh"
#include "markup.qh"
// =========================================================
-#ifndef MARKUP_H
-#define MARKUP_H
+#ifndef COMMAND_MARKUP_H
+#define COMMAND_MARKUP_H
// ==========================================================
// Declarations for markup command code, reworked by Samual
+#include "command.qh"
#include "rpn.qh"
+#include "../../warpzonelib/mathlib.qh"
+
// ========================================
// RPN command code, written by divVerent
// Last updated: December 28th, 2011
-#ifndef RPN_H
-#define RPN_H
+#ifndef COMMAND_RPN_H
+#define COMMAND_RPN_H
// =========================================================
// Declarations for RPN command code, written by divVerent
+++ /dev/null
-#ifndef SHARED_DEFS_H
-#define SHARED_DEFS_H
-
-// =========================================================
-// Shared declarations for all commands, written by Samual
-// Last updated: December 13th, 2011
-// =========================================================
-
-// identifiers for subfunction requests by the command code structure
-const int CMD_REQUEST_COMMAND = 1;
-const int CMD_REQUEST_USAGE = 2;
-#endif
#ifndef CONSTANTS_H
#define CONSTANTS_H
+// COMMIT-TODO: Update if necessary before committing
+// Revision 1: additional statistics sent (flag caps, returns, deaths)
+// Revision 2: Mapvote preview pictures
+// Revision 3: optimized map vote protocol
+// Revision 4: CSQC config var system
+// Revision 5: mapvote time fix
+// Revision 6: more robust against packet loss/delays, also show not yet connected clients
+// Revision 7: packet loss column
+// Revision 8: race
+// Revision 9: race delta
+// Revision 10: scoreboard force
+// Revision 11: scoreboard unforce; spectator support beginning
+// Revision 12: smaller scores updates (SERVER: requires new engine)
+// Revision 13: pointparticles
+// Revision 14: laser
+// Revision 15: zoom
+// Revision 16: multi-weapons
+// Revision 17: multi-weaponimpulses
+// Revision 18: warmup
+// Revision 19: fog
+// Revision 20: naggers
+// Revision 21: entcs for players optimized (position data down from 12 to 7 bytes); waypointsprites in csqc for team radar
+// Revision 22: hook shot origin
+#define CSQC_REVISION 22
+
const int AS_STRING = 1;
const int AS_INT = 2;
const int AS_FLOAT_TRUNCATED = 2;
const int ENT_CLIENT_WARPZONE_CAMERA = 25;
const int ENT_CLIENT_TRIGGER_MUSIC = 26;
const int ENT_CLIENT_HOOK = 27;
+const int ENT_CLIENT_INVENTORY = 28;
const int ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
const int ENT_CLIENT_ACCURACY = 30;
const int ENT_CLIENT_SHOWNAMES = 31;
const int ENT_CLIENT_TURRET = 40;
const int ENT_CLIENT_AUXILIARYXHAIR = 50;
const int ENT_CLIENT_VEHICLE = 60;
+const int ENT_CLIENT_LADDER = 61;
+const int ENT_CLIENT_TRIGGER_PUSH = 62;
+const int ENT_CLIENT_TARGET_PUSH = 63;
+const int ENT_CLIENT_CONVEYOR = 64;
+const int ENT_CLIENT_DOOR = 65;
+const int ENT_CLIENT_TRAIN = 66;
+const int ENT_CLIENT_PLAT = 67;
+const int ENT_CLIENT_TRIGGER_IMPULSE = 68;
+const int ENT_CLIENT_SWAMP = 69;
+const int ENT_CLIENT_CORNER = 70;
+const int ENT_CLIENT_KEYLOCK = 71;
const int ENT_CLIENT_HEALING_ORB = 80;
const int SERVERFLAG_TEAMPLAY = 2;
const int SERVERFLAG_PLAYERSTATS = 4;
-// FIXME/EXPLAINME: why?
+// FIXME/EXPLAINME: why? Mario: because
vector autocvar_sv_player_maxs = '16 16 45';
vector autocvar_sv_player_mins = '-16 -16 -24';
vector autocvar_sv_player_viewoffset = '0 0 20';
vector autocvar_sv_player_crouch_viewoffset = '0 0 20';
vector autocvar_sv_player_headsize = '24 24 12';
+
+// not so constant
+#ifdef SVQC
#define PL_VIEW_OFS autocvar_sv_player_viewoffset
#define PL_MIN autocvar_sv_player_mins
#define PL_MAX autocvar_sv_player_maxs
#define PL_CROUCH_MIN autocvar_sv_player_crouch_mins
#define PL_CROUCH_MAX autocvar_sv_player_crouch_maxs
#define PL_HEAD autocvar_sv_player_headsize
+#elif defined(CSQC)
+#define PL_VIEW_OFS vec3(getstatf(STAT_PL_VIEW_OFS1), getstatf(STAT_PL_VIEW_OFS2), getstatf(STAT_PL_VIEW_OFS3))
+#define PL_MIN vec3(getstatf(STAT_PL_MIN1), getstatf(STAT_PL_MIN2), getstatf(STAT_PL_MIN3))
+#define PL_MAX vec3(getstatf(STAT_PL_MAX1), getstatf(STAT_PL_MAX2), getstatf(STAT_PL_MAX3))
+#define PL_CROUCH_VIEW_OFS vec3(getstatf(STAT_PL_CROUCH_VIEW_OFS1), getstatf(STAT_PL_CROUCH_VIEW_OFS2), getstatf(STAT_PL_CROUCH_VIEW_OFS3))
+#define PL_CROUCH_MIN vec3(getstatf(STAT_PL_CROUCH_MIN1), getstatf(STAT_PL_CROUCH_MIN2), getstatf(STAT_PL_CROUCH_MIN3))
+#define PL_CROUCH_MAX vec3(getstatf(STAT_PL_CROUCH_MAX1), getstatf(STAT_PL_CROUCH_MAX2), getstatf(STAT_PL_CROUCH_MAX3))
+#endif
-// helpers
-#define PL_VIEW_OFS_z autocvar_sv_player_viewoffset.z
-#define PL_MIN_z autocvar_sv_player_mins.z
-#define PL_MAX_z autocvar_sv_player_maxs.z
-#define PL_CROUCH_VIEW_OFS_z autocvar_sv_player_crouch_viewoffset.z
-#define PL_CROUCH_MIN_z autocvar_sv_player_mins.z
-#define PL_HEAD_x autocvar_sv_player_headsize.x
-#define PL_HEAD_y autocvar_sv_player_headsize.y
-#define PL_HEAD_z autocvar_sv_player_headsize.z
+// a bit more constant
+const vector PL_MAX_CONST = '16 16 45';
+const vector PL_MIN_CONST = '-16 -16 -24';
// spawnpoint prios
const int SPAWN_PRIO_NEAR_TEAMMATE_FOUND = 200;
const int URI_GET_URLLIB = 128;
const int URI_GET_URLLIB_END = 191;
-// gametype votes
-const int GTV_AVAILABLE = 0;
-// for later use in per-map gametype filtering
-const int GTV_FORBIDDEN = 2;
+// gametype vote flags
+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 COUNTING_H
#define COUNTING_H
+#include "util.qh"
+
// ===============================================
// Time processing and counting functions/macros
// ===============================================
//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
// server decides crouching, this lags, but so be it
-#define CSQCMODEL_SERVERSIDE_CROUCH
+//#define CSQCMODEL_SERVERSIDE_CROUCH
// a hack for Xonotic
#ifdef CSQC
CSQCMODEL_PROPERTY(512, float, ReadApproxPastTime, WriteApproxPastTime, anim_upper_time) \
CSQCMODEL_ENDIF \
CSQCMODEL_PROPERTY(1024, float, ReadAngle, WriteAngle, v_angle_x) \
- CSQCMODEL_PROPERTY_SCALED(4096, float, ReadByte, WriteByte, scale, 16, 0, 255)
+ CSQCMODEL_PROPERTY_SCALED(4096, float, ReadByte, WriteByte, scale, 16, 0, 255) \
+ CSQCMODEL_PROPERTY(8192, int, ReadInt24_t, WriteInt24_t, dphitcontentsmask)
// TODO get rid of colormod/glowmod here, find good solution for vortex charge glowmod hack; also get rid of some useless properties on non-players that only exist for CopyBody
// add hook function calls here
--- /dev/null
+/** If you register a new item, make sure to add it to this list */
+#include "item/ammo.qc"
+#include "item/armor.qc"
+#include "item/buff.qc"
+#include "item/health.qc"
+#include "item/jetpack.qc"
+#include "item/pickup.qc"
+#include "item/powerup.qc"
+#include "../../server/mutators/mutator_instagib_items.qc"
--- /dev/null
+#ifndef ALL_C
+#define ALL_C
+#include "all.qh"
+
+#include "all.inc"
+
+void Dump_Items()
+{
+ ITEMS_FOREACH(true, LAMBDA({
+ ITEM_HANDLE(Show, it);
+ }));
+}
+
+#endif
--- /dev/null
+#ifndef ALL_H
+#define ALL_H
+
+const int MAX_ITEMS = 24;
+entity ITEMS[MAX_ITEMS];
+
+#define ITEMS_FOREACH(pred, body) do { \
+ for (int i = 0; i < ITEM_COUNT; i++) { \
+ const noref entity it = ITEMS[i]; \
+ if (pred) { body } \
+ } \
+} while(0)
+
+void RegisterItems();
+void Dump_Items();
+
+#endif
+
+#include "inventory.qh"
--- /dev/null
+#ifndef INVENTORY_H
+#define INVENTORY_H
+
+#include "all.qh"
+#include "item/pickup.qh"
+
+entityclass(Inventory);
+/** Stores counts of items, the id being the index */
+class(Inventory) .int inv_items[MAX_ITEMS];
+
+/** Player inventory; Inventories also have one inventory for storing the previous state */
+.Inventory inventory;
+
+#ifdef CSQC
+void Inventory_Read(Inventory data)
+{
+ const int bits = ReadInt24_t();
+ ITEMS_FOREACH(bits & BIT(i), LAMBDA({
+ .int fld = inv_items[i];
+ int prev = data.(fld);
+ int next = data.(fld) = ReadByte();
+ dprintf("%s: %.0f -> %.0f\n", ITEMS[i].m_name, prev, next);
+ }));
+}
+#endif
+
+#ifdef SVQC
+void Inventory_Write(Inventory data)
+{
+ int bits = 0;
+ ITEMS_FOREACH(true, LAMBDA({
+ .int fld = inv_items[i];
+ bits = BITSET(bits, BIT(i), data.inventory.(fld) != (data.inventory.(fld) = data.(fld)));
+ }));
+ WriteInt24_t(MSG_ENTITY, bits);
+ ITEMS_FOREACH(bits & BIT(i), LAMBDA({
+ WriteByte(MSG_ENTITY, data.inv_items[i]);
+ }));
+}
+#endif
+
+#ifdef SVQC
+bool Inventory_Send(entity to, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_INVENTORY);
+ entity e = self.owner;
+ if (IS_SPEC(e)) e = e.enemy;
+ Inventory data = e.inventory;
+ Inventory_Write(data);
+ return true;
+}
+
+void Inventory_new(entity e)
+{
+ Inventory inv = new(Inventory), bak = new(Inventory);
+ inv.classname = "inventory", bak.classname = "inventory";
+ inv.inventory = bak;
+ 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_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
+#endif
+
+#endif
--- /dev/null
+#ifndef GAMEITEM_H
+#define GAMEITEM_H
+#include "../oo.qh"
+#define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
+CLASS(GameItem, Object)
+ ATTRIB(GameItem, m_id, int, 0)
+ METHOD(GameItem, show, void(entity this))
+ void GameItem_show(entity this) { print("A game item\n"); }
+ void ITEM_HANDLE(Show, entity this) { this.show(this); }
+ENDCLASS(GameItem)
+
+
+int ITEM_COUNT;
+/** If you register a new item, make sure to add it to all.inc */
+#define REGISTER_ITEM(id, class, body) \
+ entity ITEM_##id; \
+ void RegisterItems_##id() { \
+ const entity this = NEW(class); \
+ ITEM_##id = this; \
+ this.m_id = ITEM_COUNT; \
+ ITEMS[ITEM_COUNT++] = this; \
+ body \
+ } \
+ ACCUMULATE_FUNCTION(RegisterItems, RegisterItems_##id)
+
+#endif
--- /dev/null
+#include "ammo.qh"
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) \
+ REGISTER_ITEM(id, Ammo, LAMBDA( \
+ IF(SV, CONFIGURE \
+ , respawntime = GET(g_pickup_respawntime_ammo) \
+ , respawntimejitter = GET(g_pickup_respawntimejitter_ammo) \
+ ) \
+ UNWORDS(__VA_ARGS__) \
+ ))
+
+DEFINE(Bullets
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_bullets.mdl"
+ , name = "bullets"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 2000
+ , itemid = IT_NAILS
+ )
+)
+DEFINE(Cells
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_cells.md3"
+ , name = "cells"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 2000
+ , itemid = IT_CELLS
+ )
+)
+DEFINE(Plasma
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_cells.md3"
+ , name = "plasma"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 2000
+ , itemid = IT_PLASMA
+ )
+)
+DEFINE(Rockets
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_rockets.md3"
+ , name = "rockets"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 3000
+ , itemid = IT_ROCKETS
+ )
+)
+DEFINE(Shells
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_shells.md3"
+ , name = "shells"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 500
+ , itemid = IT_SHELLS
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef AMMO_H
+#define AMMO_H
+#include "pickup.qh"
+CLASS(Ammo, Pickup)
+#ifdef SVQC
+ ATTRIB(Ammo, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+#endif
+ENDCLASS(Ammo)
+#endif
--- /dev/null
+#include "armor.qh"
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) REGISTER_ITEM(id, Armor, UNWORDS(__VA_ARGS__))
+
+DEFINE(ArmorSmall
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_small.md3"
+ , sound = "misc/armor1.wav"
+ , name = "5 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemid = IT_ARMOR_SHARD
+ , respawntime = GET(g_pickup_respawntime_short)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_short)
+ )
+)
+
+DEFINE(ArmorMedium
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_medium.md3"
+ , sound = "misc/armor10.wav"
+ , name = "25 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_MID
+ , itemid = IT_ARMOR
+ , respawntime = GET(g_pickup_respawntime_medium)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_medium)
+ )
+)
+
+DEFINE(ArmorBig
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_big.md3"
+ , sound = "misc/armor17_5.wav"
+ , name = "50 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 20000 // FIXME: higher than BOT_PICKUP_RATING_HIGH?
+ , itemid = IT_ARMOR
+ , respawntime = GET(g_pickup_respawntime_long)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_long)
+ )
+)
+
+DEFINE(ArmorLarge
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_large.md3"
+ , sound = "misc/armor25.wav"
+ , name = "100 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_HIGH
+ , itemid = IT_ARMOR
+ , respawntime = GET(g_pickup_respawntime_long)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_long)
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef ARMOR_H
+#define ARMOR_H
+#include "pickup.qh"
+CLASS(Armor, Pickup)
+#ifdef SVQC
+ ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+#endif
+ENDCLASS(Armor)
+#endif
--- /dev/null
+#include "buff.qh"
+
+REGISTER_ITEM(DefaultBuff, Buff, LAMBDA())
--- /dev/null
+#ifndef BUFF_H
+#define BUFF_H
+#include "pickup.qh"
+CLASS(Buff, Pickup)
+ ATTRIB(Buff, m_name, string, "Buff")
+ENDCLASS(Buff)
+#endif
--- /dev/null
+#include "health.qh"
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) REGISTER_ITEM(id, Health, UNWORDS(__VA_ARGS__))
+
+DEFINE(HealthSmall
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h1.md3"
+ , sound = "misc/minihealth.wav"
+ , name = "5 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemid = IT_5HP
+ , respawntime = GET(g_pickup_respawntime_short)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_short)
+ )
+)
+
+DEFINE(HealthMedium
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h25.md3"
+ , sound = "misc/mediumhealth.wav"
+ , name = "25 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_MID
+ , itemid = IT_25HP
+ , respawntime = GET(g_pickup_respawntime_short)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_short)
+ )
+)
+
+DEFINE(HealthLarge
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h50.md3"
+ , sound = "misc/mediumhealth.wav"
+ , name = "50 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_MID
+ , itemid = IT_25HP
+ , respawntime = GET(g_pickup_respawntime_medium)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_medium)
+ )
+)
+
+DEFINE(HealthMega
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h100.md3"
+ , sound = "misc/megahealth.wav"
+ , name = "100 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_HIGH
+ , itemid = IT_HEALTH
+ , respawntime = GET(g_pickup_respawntime_long)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_long)
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef HEALTH_H
+#define HEALTH_H
+#include "pickup.qh"
+CLASS(Health, Pickup)
+#ifdef SVQC
+ ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+#endif
+ENDCLASS(Health)
+#endif
--- /dev/null
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+ #include "../../../server/constants.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) REGISTER_ITEM(id, Pickup, UNWORDS(__VA_ARGS__))
+
+DEFINE(Jetpack
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_jetpack.md3"
+ , name = "Jet pack"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemflags = FL_POWERUP
+ , itemid = IT_JETPACK
+ , pickupevalfunc = commodity_pickupevalfunc
+ , respawntime = GET(g_pickup_respawntime_powerup)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
+ )
+)
+
+DEFINE(JetpackFuel
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_fuel.md3"
+ , name = "Fuel"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemid = IT_FUEL
+ , pickupevalfunc = commodity_pickupevalfunc
+ , respawntime = GET(g_pickup_respawntime_ammo)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_ammo)
+ )
+)
+
+DEFINE(JetpackRegen
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_fuelregen.md3"
+ , name = "Fuel regenerator"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemflags = FL_POWERUP
+ , itemid = IT_FUEL_REGEN
+ , pickupevalfunc = commodity_pickupevalfunc
+ , respawntime = GET(g_pickup_respawntime_powerup)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#include "pickup.qh"
+
+#ifdef SVQC
+bool ITEM_HANDLE(Pickup, entity this, entity item, entity player) {
+ bool b = this.giveTo(this, item, player);
+ if (b) {
+ dprintf("entity %i picked up %s\n", player, this.m_name);
+ player.inventory.inv_items[this.m_id]++;
+ Inventory_update(player);
+ }
+ return b;
+}
+#endif
--- /dev/null
+#ifndef PICKUP_H
+#define PICKUP_H
+#include "../item.qh"
+CLASS(Pickup, GameItem)
+ ATTRIB(Pickup, m_model, string, string_null)
+ ATTRIB(Pickup, m_sound, string, "misc/itempickup.wav")
+ ATTRIB(Pickup, m_name, string, string_null)
+ METHOD(Pickup, show, void(entity this))
+ void Pickup_show(entity this) { printf("%s: %s\n", etos(this), this.m_name); }
+#ifdef SVQC
+ ATTRIB(Pickup, m_botvalue, int, 0)
+ ATTRIB(Pickup, m_itemflags, int, 0)
+ ATTRIB(Pickup, m_itemid, int, 0)
+ 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)
+ METHOD(Pickup, giveTo, bool(entity this, entity item, entity player))
+ bool Pickup_giveTo(entity this, entity item, entity player) { return Item_GiveTo(item, player); }
+ bool ITEM_HANDLE(Pickup, entity this, entity item, entity player);
+#endif
+ENDCLASS(Pickup)
+
+#ifdef SVQC
+// For g_pickup_respawntime
+#include "../../../server/defs.qh"
+// Getters to dynamically retrieve the values of g_pickup_respawntime*
+GETTER(float, g_pickup_respawntime_weapon)
+GETTER(float, g_pickup_respawntime_superweapon)
+GETTER(float, g_pickup_respawntime_ammo)
+GETTER(float, g_pickup_respawntime_short)
+GETTER(float, g_pickup_respawntime_medium)
+GETTER(float, g_pickup_respawntime_long)
+GETTER(float, g_pickup_respawntime_powerup)
+GETTER(float, g_pickup_respawntimejitter_weapon)
+GETTER(float, g_pickup_respawntimejitter_superweapon)
+GETTER(float, g_pickup_respawntimejitter_ammo)
+GETTER(float, g_pickup_respawntimejitter_short)
+GETTER(float, g_pickup_respawntimejitter_medium)
+GETTER(float, g_pickup_respawntimejitter_long)
+GETTER(float, g_pickup_respawntimejitter_powerup)
+
+#endif
+
+#endif
--- /dev/null
+#include "powerup.qh"
+#include "../../../server/t_items.qh"
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) \
+ REGISTER_ITEM(id, Ammo, LAMBDA( \
+ IF(SV, CONFIGURE \
+ , botvalue = 100000 \
+ , itemflags = FL_POWERUP \
+ , respawntime = GET(g_pickup_respawntime_powerup) \
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup) \
+ ) \
+ UNWORDS(__VA_ARGS__) \
+ ))
+
+DEFINE(Strength
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_strength.md3"
+ , sound = "misc/powerup.wav"
+ , name = "Strength Powerup"
+ )
+ ,IF(SV, CONFIGURE
+ , itemid = IT_STRENGTH
+ )
+)
+DEFINE(Shield
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_invincible.md3"
+ , sound = "misc/powerup_shield.wav"
+ , name = "Shield"
+ )
+ ,IF(SV, CONFIGURE
+ , itemid = IT_INVINCIBLE
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef POWERUP_H
+#define POWERUP_H
+#include "pickup.qh"
+CLASS(Powerup, Pickup)
+ENDCLASS(Powerup)
+
+#ifdef SVQC
+// For FL_POWERUP
+#include "../../../server/constants.qh"
+#endif
+
+#endif
#include "../client/defs.qh"
#include "util.qh"
#include "buffs.qh"
- #include "weapons/weapons.qh"
+ #include "weapons/all.qh"
#include "mapinfo.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#include "../dpdefs/dpextensions.qh"
#include "util.qh"
#include "buffs.qh"
- #include "monsters/monsters.qh"
+ #include "monsters/all.qh"
#include "mapinfo.qh"
#endif
#ifndef MAPINFO_H
#define MAPINFO_H
+#include "util.qh"
+
int MAPINFO_TYPE_ALL;
entity MapInfo_Type_first;
entity MapInfo_Type_last;
.string netname; // game type name as in cvar (with g_ prefix)
.string mdl; // game type short name
.string message; // human readable name
-.float team; // does this gametype support teamplay?
+.int team; // does this gametype support teamplay?
.string model2; // game type defaults
.string gametype_description; // game type description
--- /dev/null
+#include "monster/zombie.qc"
+#include "monster/spider.qc"
+#include "monster/mage.qc"
+#include "monster/wyvern.qc"
+#include "monster/shambler.qc"
--- /dev/null
+#include "all.qh"
+
+#include "all.inc"
+
+// MONSTER PLUGIN SYSTEM
+entity monster_info[MON_MAXCOUNT];
+entity dummy_monster_info;
+
+void register_monster(int id, float(float) func, int monsterflags, vector min_s, vector max_s, string modelname, string shortname, string mname)
+{
+ entity e;
+ monster_info[id - 1] = e = spawn();
+ e.classname = "monster_info";
+ e.monsterid = id;
+ e.netname = shortname;
+ e.monster_name = mname;
+ e.monster_func = func;
+ e.mdl = modelname;
+ e.spawnflags = monsterflags;
+ e.mins = min_s;
+ e.maxs = max_s;
+ e.model = strzone(strcat("models/monsters/", modelname));
+}
+float m_null(float dummy) { return 0; }
+void register_monsters_done()
+{
+ dummy_monster_info = spawn();
+ dummy_monster_info.classname = "monster_info";
+ dummy_monster_info.monsterid = 0; // you can recognize dummies by this
+ dummy_monster_info.netname = "";
+ dummy_monster_info.monster_name = "Monster";
+ dummy_monster_info.monster_func = m_null;
+ dummy_monster_info.mdl = "";
+ dummy_monster_info.mins = '-0 -0 -0';
+ dummy_monster_info.maxs = '0 0 0';
+ dummy_monster_info.model = "";
+}
+entity get_monsterinfo(int id)
+{
+ entity m;
+ if(id < MON_FIRST || id > MON_LAST)
+ return dummy_monster_info;
+ m = monster_info[id - 1];
+ if(m)
+ return m;
+ return dummy_monster_info;
+}
-// TODO: include once
-//#ifndef MONSTERS_ALL_H
-//#define MONSTERS_ALL_H
+#ifndef MONSTERS_ALL_H
+#define MONSTERS_ALL_H
-#include "monster/zombie.qc"
-#include "monster/spider.qc"
-#include "monster/mage.qc"
-#include "monster/wyvern.qc"
-#include "monster/shambler.qc"
+#include "../util.qh"
-//#endif
+// monster requests
+const int MR_SETUP = 1; // (SERVER) setup monster data
+const int MR_THINK = 2; // (SERVER) logic to run every frame
+const int MR_DEATH = 3; // (SERVER) called when monster dies
+const int MR_PRECACHE = 4; // (BOTH) precaches models/sounds used by this monster
+
+// functions:
+entity get_monsterinfo(float id);
+
+// special spawn flags
+const int MONSTER_RESPAWN_DEATHPOINT = 16; // re-spawn where we died
+const int MONSTER_TYPE_FLY = 32;
+const int MONSTER_TYPE_SWIM = 64;
+const int MONSTER_SIZE_BROKEN = 128; // TODO: remove when bad models are replaced
+const int MON_FLAG_SUPERMONSTER = 256; // incredibly powerful monster
+const int MON_FLAG_RANGED = 512; // monster shoots projectiles
+const int MON_FLAG_MELEE = 1024;
+
+// entity properties of monsterinfo:
+.float monsterid; // MON_...
+.string netname; // short name
+.string monster_name; // human readable name
+.float(float) monster_func; // m_...
+.string mdl; // currently a copy of the model
+.string model; // full name of model
+.int spawnflags;
+.vector mins, maxs; // monster hitbox size
+
+// other useful macros
+#define MON_ACTION(monstertype,mrequest) (get_monsterinfo(monstertype)).monster_func(mrequest)
+#define M_NAME(monstertype) (get_monsterinfo(monstertype)).monster_name
+
+// =====================
+// Monster Registration
+// =====================
+
+float m_null(float dummy);
+void register_monster(float id, float(float) func, float monsterflags, vector min_s, vector max_s, string modelname, string shortname, string mname);
+void register_monsters_done();
+
+const int MON_MAXCOUNT = 24;
+const int MON_FIRST = 1;
+int MON_COUNT;
+int MON_LAST;
+
+#define REGISTER_MONSTER_2(id,func,monsterflags,min_s,max_s,modelname,shortname,mname) \
+ int id; \
+ float func(float); \
+ void RegisterMonsters_##id() \
+ { \
+ MON_LAST = (id = MON_FIRST + MON_COUNT); \
+ ++MON_COUNT; \
+ register_monster(id,func,monsterflags,min_s,max_s,modelname,shortname,mname); \
+ } \
+ ACCUMULATE_FUNCTION(RegisterMonsters, RegisterMonsters_##id)
+#ifdef MENUQC
+#define REGISTER_MONSTER(id,func,monsterflags,min_s,max_s,modelname,shortname,mname) \
+ REGISTER_MONSTER_2(MON_##id,m_null,monsterflags,min_s,max_s,modelname,shortname,mname)
+#else
+#define REGISTER_MONSTER(id,func,monsterflags,min_s,max_s,modelname,shortname,mname) \
+ REGISTER_MONSTER_2(MON_##id,func,monsterflags,min_s,max_s,modelname,shortname,mname)
+#endif
+
+#include "all.inc"
+
+#undef REGISTER_MONSTER
+ACCUMULATE_FUNCTION(RegisterMonsters, register_monsters_done);
+#endif
self.nextthink = time + 0.2;
}
-void shambler_lightning_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void shambler_lightning_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if (self.health <= 0)
return;
+++ /dev/null
-#include "monsters.qh"
-
-#include "all.qh"
-
-// MONSTER PLUGIN SYSTEM
-entity monster_info[MON_MAXCOUNT];
-entity dummy_monster_info;
-
-void register_monster(int id, float(float) func, int monsterflags, vector min_s, vector max_s, string modelname, string shortname, string mname)
-{
- entity e;
- monster_info[id - 1] = e = spawn();
- e.classname = "monster_info";
- e.monsterid = id;
- e.netname = shortname;
- e.monster_name = mname;
- e.monster_func = func;
- e.mdl = modelname;
- e.spawnflags = monsterflags;
- e.mins = min_s;
- e.maxs = max_s;
- e.model = strzone(strcat("models/monsters/", modelname));
-}
-float m_null(float dummy) { return 0; }
-void register_monsters_done()
-{
- dummy_monster_info = spawn();
- dummy_monster_info.classname = "monster_info";
- dummy_monster_info.monsterid = 0; // you can recognize dummies by this
- dummy_monster_info.netname = "";
- dummy_monster_info.monster_name = "Monster";
- dummy_monster_info.monster_func = m_null;
- dummy_monster_info.mdl = "";
- dummy_monster_info.mins = '-0 -0 -0';
- dummy_monster_info.maxs = '0 0 0';
- dummy_monster_info.model = "";
-}
-entity get_monsterinfo(int id)
-{
- entity m;
- if(id < MON_FIRST || id > MON_LAST)
- return dummy_monster_info;
- m = monster_info[id - 1];
- if(m)
- return m;
- return dummy_monster_info;
-}
+++ /dev/null
-#ifndef MONSTERS_H
-#define MONSTERS_H
-
-// monster requests
-const int MR_SETUP = 1; // (SERVER) setup monster data
-const int MR_THINK = 2; // (SERVER) logic to run every frame
-const int MR_DEATH = 3; // (SERVER) called when monster dies
-const int MR_PRECACHE = 4; // (BOTH) precaches models/sounds used by this monster
-
-// functions:
-entity get_monsterinfo(float id);
-
-// special spawn flags
-const int MONSTER_RESPAWN_DEATHPOINT = 16; // re-spawn where we died
-const int MONSTER_TYPE_FLY = 32;
-const int MONSTER_TYPE_SWIM = 64;
-const int MONSTER_SIZE_BROKEN = 128; // TODO: remove when bad models are replaced
-const int MON_FLAG_SUPERMONSTER = 256; // incredibly powerful monster
-const int MON_FLAG_RANGED = 512; // monster shoots projectiles
-const int MON_FLAG_MELEE = 1024;
-
-// entity properties of monsterinfo:
-.float monsterid; // MON_...
-.string netname; // short name
-.string monster_name; // human readable name
-.float(float) monster_func; // m_...
-.string mdl; // currently a copy of the model
-.string model; // full name of model
-.int spawnflags;
-.vector mins, maxs; // monster hitbox size
-
-// other useful macros
-#define MON_ACTION(monstertype,mrequest) (get_monsterinfo(monstertype)).monster_func(mrequest)
-#define M_NAME(monstertype) (get_monsterinfo(monstertype)).monster_name
-
-// =====================
-// Monster Registration
-// =====================
-
-float m_null(float dummy);
-void register_monster(float id, float(float) func, float monsterflags, vector min_s, vector max_s, string modelname, string shortname, string mname);
-void register_monsters_done();
-
-const int MON_MAXCOUNT = 24;
-const int MON_FIRST = 1;
-int MON_COUNT;
-int MON_LAST;
-
-#define REGISTER_MONSTER_2(id,func,monsterflags,min_s,max_s,modelname,shortname,mname) \
- int id; \
- float func(float); \
- void RegisterMonsters_##id() \
- { \
- MON_LAST = (id = MON_FIRST + MON_COUNT); \
- ++MON_COUNT; \
- register_monster(id,func,monsterflags,min_s,max_s,modelname,shortname,mname); \
- } \
- ACCUMULATE_FUNCTION(RegisterMonsters, RegisterMonsters_##id)
-#ifdef MENUQC
-#define REGISTER_MONSTER(id,func,monsterflags,min_s,max_s,modelname,shortname,mname) \
- REGISTER_MONSTER_2(MON_##id,m_null,monsterflags,min_s,max_s,modelname,shortname,mname)
-#else
-#define REGISTER_MONSTER(id,func,monsterflags,min_s,max_s,modelname,shortname,mname) \
- REGISTER_MONSTER_2(MON_##id,func,monsterflags,min_s,max_s,modelname,shortname,mname)
-#endif
-
-#include "all.qh"
-
-#undef REGISTER_MONSTER
-ACCUMULATE_FUNCTION(RegisterMonsters, register_monsters_done);
-#endif
#elif defined(SVQC)
#include "../../dpdefs/progsdefs.qh"
#include "../util.qh"
- #include "monsters.qh"
+ #include "all.qh"
#include "sv_monsters.qh"
#include "spawn.qh"
#include "../../server/autocvars.qh"
#include "../constants.qh"
#include "../teams.qh"
#include "../util.qh"
- #include "monsters.qh"
+ #include "all.qh"
#include "sv_monsters.qh"
- #include "../weapons/weapons.qh"
+ #include "../weapons/all.qh"
#include "../../server/autocvars.qh"
#include "../../server/defs.qh"
#include "../deathtypes.qh"
#include "../../server/mutators/mutators_include.qh"
#include "../../server/tturrets/include/turrets_early.qh"
- #include "../../server/vehicles/vehicles_def.qh"
+ #include "../../server/vehicles/vehicle.qh"
#include "../../server/campaign.qh"
#include "../../server/command/common.qh"
#include "../../server/command/cmd.qh"
+ #include "../triggers/triggers.qh"
#include "../../csqcmodellib/sv_model.qh"
#include "../../server/round_handler.qh"
#include "../../server/tturrets/include/turrets.qh"
field = GetMonsterSoundSampleField(argv(0));
if(GetMonsterSoundSampleField_notFound)
continue;
- if(self.field)
- strunzone(self.field);
- self.field = strzone(strcat(argv(1), " ", argv(2)));
+ if (self.(field))
+ strunzone(self.(field));
+ self.(field) = strzone(strcat(argv(1), " ", argv(2)));
}
fclose(fh);
return 1;
if(delaytoo)
if(time < self.msound_delay)
return; // too early
- GlobalSound(self.samplefield, chan, VOICETYPE_PLAYERSOUND);
+ GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND);
self.msound_delay = time + sound_delay;
}
makevectors(self.v_angle);
}
-float monster_melee(entity targ, float damg, float anim, float er, float anim_finished, float deathtype, float dostop)
+float monster_melee(entity targ, float damg, float anim, float er, float anim_finished, int deathtype, float dostop)
{
if (self.health <= 0)
return false; // attacking while dead?!
self.moveto = self.origin;
}
-void monsters_corpse_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void monsters_corpse_damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
self.health -= damage;
MON_ACTION(self.monsterid, MR_DEATH);
}
-void monsters_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void monsters_damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.frozen && deathtype != DEATH_KILL && deathtype != DEATH_NADE_ICE_FREEZE)
return;
float monster_initialize(float mon_id);
float monster_leap (float anm, void() touchfunc, vector vel, float anim_finished);
void monster_makevectors(entity e);
-float monster_melee(entity targ, float damg, float anim, float er, float anim_finished, float deathtype, float dostop);
+float monster_melee(entity targ, float damg, float anim, float er, float anim_finished, int deathtype, float dostop);
void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_run, float manim_walk, float manim_idle);
void monster_setupcolors(entity mon);
float Monster_SkillModifier();
--- /dev/null
+void _Movetype_Physics_Follow() // SV_Physics_Follow
+{
+ entity e = self.move_aiment; // TODO: networking?
+
+ // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
+ if(self.move_angles == self.move_punchangle)
+ {
+ self.move_origin = e.move_origin + self.view_ofs;
+ }
+ else
+ {
+ vector ang, v;
+ ang_x = -self.move_punchangle_x;
+ ang_y = self.move_punchangle_y;
+ ang_z = self.move_punchangle_z;
+ makevectors(ang);
+ v_x = self.view_ofs_x * v_forward_x + self.view_ofs_y * v_right_x + self.view_ofs_z * v_up_x;
+ v_y = self.view_ofs_x * v_forward_y + self.view_ofs_y * v_right_y + self.view_ofs_z * v_up_y;
+ v_z = self.view_ofs_x * v_forward_z + self.view_ofs_y * v_right_z + self.view_ofs_z * v_up_z;
+ ang_x = -e.move_angles_x;
+ ang_y = e.move_angles_y;
+ ang_z = e.move_angles_z;
+ makevectors(ang);
+ self.move_origin_x = v_x * v_forward_x + v_y * v_forward_y + v_z * v_forward_z + e.move_origin_x;
+ self.move_origin_x = v_x * v_right_x + v_y * v_right_y + v_z * v_right_z + e.move_origin_y;
+ self.move_origin_x = v_x * v_up_x + v_y * v_up_y + v_z * v_up_z + e.move_origin_z;
+ }
+
+ self.move_angles = e.move_angles + self.v_angle;
+ _Movetype_LinkEdict(false);
+}
--- /dev/null
+#include "push.qc"
+#include "toss.qc"
+#include "walk.qc"
+#include "step.qc"
+#include "follow.qc"
+
+#include "movetypes.qc"
--- /dev/null
+#ifndef MOVETYPES_INCLUDE_H
+#define MOVETYPES_INCLUDE_H
+
+#include "push.qh"
+#include "toss.qh"
+#include "walk.qh"
+
+#endif
--- /dev/null
+#include "include.qh"
+#include "../physics.qh"
+
+#if defined(CSQC)
+ #include "../../dpdefs/csprogsdefs.qh"
+ #include "../../client/defs.qh"
+ #include "../stats.qh"
+ #include "../util.qh"
+ #include "movetypes.qh"
+ #include "../../csqcmodellib/common.qh"
+ #include "../../server/t_items.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../server/autocvars.qh"
+#endif
+
+void _Movetype_WallFriction(vector stepnormal) // SV_WallFriction
+{
+ /*float d, i;
+ vector into, side;
+ makevectors(self.v_angle);
+ d = (stepnormal * v_forward) + 0.5;
+
+ if(d < 0)
+ {
+ i = (stepnormal * self.move_velocity);
+ into = i * stepnormal;
+ side = self.move_velocity - into;
+ self.move_velocity_x = side.x * (1 * d);
+ self.move_velocity_y = side.y * (1 * d);
+ }*/
+}
+
+vector planes[MAX_CLIP_PLANES];
+int _Movetype_FlyMove(float dt, bool applygravity, vector stepnormal, float stepheight) // SV_FlyMove
+{
+ int blocked = 0, bumpcount;
+ int i, j, numplanes = 0;
+ float time_left = dt, grav = 0;
+ vector push;
+ vector primal_velocity, original_velocity, new_velocity = '0 0 0', restore_velocity;
+
+ for(i = 0; i <= MAX_CLIP_PLANES; ++i)
+ planes[i] = '0 0 0';
+
+ grav = 0;
+
+ restore_velocity = self.move_velocity;
+
+ if(applygravity)
+ {
+ self.move_didgravity = 1;
+ grav = dt * (PHYS_ENTGRAVITY(self) ? PHYS_ENTGRAVITY(self) : 1) * PHYS_GRAVITY;
+
+ if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(self.move_flags & FL_ONGROUND))
+ {
+ if(GRAVITY_UNAFFECTED_BY_TICRATE)
+ self.move_velocity_z -= grav * 0.5;
+ else
+ self.move_velocity_z -= grav;
+ }
+ }
+
+ original_velocity = primal_velocity = self.move_velocity;
+
+ for(bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
+ {
+ if(!self.move_velocity_x && !self.move_velocity_y && !self.move_velocity_z)
+ break;
+
+ push = self.move_velocity * time_left;
+ if(!_Movetype_PushEntity(push, false))
+ {
+ // we got teleported by a touch function
+ // let's abort the move
+ blocked |= 8;
+ break;
+ }
+
+ // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
+ // abort move if we're stuck in the world (and didn't make it out)
+ if(trace_startsolid && trace_allsolid)
+ {
+ self.move_velocity = restore_velocity;
+ return 3;
+ }
+
+ if(trace_fraction == 1)
+ break;
+ if(trace_plane_normal_z)
+ {
+ if(trace_plane_normal_z > 0.7)
+ {
+ // floor
+ blocked |= 1;
+
+ if(!trace_ent)
+ {
+ //dprint("_Movetype_FlyMove: !trace_ent\n");
+ trace_ent = world;
+ }
+
+ self.move_flags |= FL_ONGROUND;
+ self.move_groundentity = trace_ent;
+ }
+ }
+ else if(stepheight)
+ {
+ // step - handle it immediately
+ vector org;
+ vector steppush;
+ //Con_Printf("step %f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+ steppush = '0 0 1' * stepheight;
+ org = self.move_origin;
+ if(!_Movetype_PushEntity(steppush, false))
+ {
+ blocked |= 8;
+ break;
+ }
+ //Con_Printf("%f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+ if(!_Movetype_PushEntity(push, false))
+ {
+ blocked |= 8;
+ break;
+ }
+ float trace2_fraction = trace_fraction;
+ //Con_Printf("%f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+ steppush = '0 0 1' * (org_z - self.move_origin_z);
+ if(!_Movetype_PushEntity(steppush, false))
+ {
+ blocked |= 8;
+ break;
+ }
+ //Con_Printf("%f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+ // accept the new position if it made some progress...
+ if(fabs(self.move_origin_x - org_x) >= 0.03125 || fabs(self.move_origin_y - org_y) >= 0.03125)
+ {
+ //Con_Printf("accepted (delta %f %f %f)\n", self.move_origin_x - org_x, PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
+ trace_endpos = self.move_origin;
+ time_left *= 1 - trace2_fraction;
+ numplanes = 0;
+ continue;
+ }
+ else
+ {
+ //Con_Printf("REJECTED (delta %f %f %f)\n", self.move_origin_x - org_x, PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
+ self.move_origin = org;
+ }
+ }
+ else
+ {
+ // step - return it to caller
+ blocked |= 2;
+ // save the trace for player extrafriction
+ if(stepnormal)
+ stepnormal = trace_plane_normal;
+ }
+ if(trace_fraction >= 0.001)
+ {
+ // actually covered some distance
+ original_velocity = self.move_velocity;
+ numplanes = 0;
+ }
+
+ time_left *= 1 - trace_fraction;
+
+ // clipped to another plane
+ if(numplanes >= MAX_CLIP_PLANES)
+ {
+ // this shouldn't really happen
+ self.move_velocity = '0 0 0';
+ blocked = 3;
+ break;
+ }
+
+ planes[numplanes] = trace_plane_normal;
+ numplanes++;
+
+ // modify original_velocity so it parallels all of the clip planes
+ for (i = 0;i < numplanes;i++)
+ {
+ new_velocity = _Movetype_ClipVelocity(original_velocity, planes[i], 1);
+ for (j = 0;j < numplanes;j++)
+ {
+ if(j != i)
+ {
+ // not ok
+ if((new_velocity * planes[j]) < 0)
+ break;
+ }
+ }
+ if(j == numplanes)
+ break;
+ }
+
+ if(i != numplanes)
+ {
+ // go along this plane
+ self.move_velocity = new_velocity;
+ }
+ else
+ {
+ // go along the crease
+ if(numplanes != 2)
+ {
+ self.move_velocity = '0 0 0';
+ blocked = 7;
+ break;
+ }
+ vector dir;
+ dir.x = planes[0].y * planes[1].z - planes[0].z * planes[1].y;
+ dir.y = planes[0].z * planes[1].x - planes[0].x * planes[1].z;
+ dir.z = planes[0].x * planes[1].y - planes[0].y * planes[1].x;
+ // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
+ float ilength = sqrt((dir * dir));
+ if(ilength)
+ ilength = 1.0 / ilength;
+ dir.x *= ilength;
+ dir.y *= ilength;
+ dir.z *= ilength;
+ float d = (dir * self.move_velocity);
+ self.move_velocity = dir * d;
+ }
+
+ // if current velocity is against the original velocity,
+ // stop dead to avoid tiny occilations in sloping corners
+ if((self.move_velocity * primal_velocity) <= 0)
+ {
+ self.move_velocity = '0 0 0';
+ break;
+ }
+ }
+
+ // LordHavoc: this came from QW and allows you to get out of water more easily
+ if(GAMEPLAYFIX_EASIERWATERJUMP && (self.move_flags & FL_WATERJUMP) && !(blocked & 8))
+ self.move_velocity = primal_velocity;
+
+ if(applygravity)
+ {
+ if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(self.move_flags & FL_ONGROUND))
+ {
+ if(GRAVITY_UNAFFECTED_BY_TICRATE)
+ self.move_velocity_z -= grav * 0.5f;
+ }
+ }
+
+ return blocked;
+}
+
+void _Movetype_CheckVelocity() // SV_CheckVelocity
+{
+ // if(vlen(self.move_velocity) < 0.0001)
+ // self.move_velocity = '0 0 0';
+}
+
+bool _Movetype_CheckWater(entity ent) // SV_CheckWater
+{
+ vector point = ent.move_origin;
+ point.z += (ent.mins.z + 1);
+
+ int nativecontents = pointcontents(point);
+ if(ent.move_watertype && ent.move_watertype != nativecontents)
+ {
+ // dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", ent.move_watertype, nativecontents);
+ if(ent.contentstransition)
+ ent.contentstransition(ent.move_watertype, nativecontents);
+ }
+
+ ent.move_waterlevel = 0;
+ ent.move_watertype = CONTENT_EMPTY;
+
+ int supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
+ if(supercontents & DPCONTENTS_LIQUIDSMASK)
+ {
+ ent.move_watertype = nativecontents;
+ ent.move_waterlevel = 1;
+ point.y = (ent.origin.y + ((ent.mins.z + ent.maxs.y) * 0.5));
+ if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
+ {
+ ent.move_waterlevel = 2;
+ point.y = ent.origin.y + ent.view_ofs.y;
+ if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
+ ent.move_waterlevel = 3;
+ }
+ }
+
+ return ent.move_waterlevel > 1;
+}
+
+void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
+{
+ int contents = pointcontents(ent.move_origin);
+
+ if(!ent.move_watertype)
+ {
+ // just spawned here
+ if(!autocvar_cl_gameplayfix_fixedcheckwatertransition)
+ {
+ ent.move_watertype = contents;
+ ent.move_waterlevel = 1;
+ return;
+ }
+ }
+ else if(ent.move_watertype != contents)
+ {
+ // dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents);
+ if(ent.contentstransition)
+ ent.contentstransition(ent.move_watertype, contents);
+ }
+
+ if(contents <= CONTENT_WATER)
+ {
+ ent.move_watertype = contents;
+ ent.move_waterlevel = 1;
+ }
+ else
+ {
+ ent.move_watertype = CONTENT_EMPTY;
+ ent.move_waterlevel = (autocvar_cl_gameplayfix_fixedcheckwatertransition ? 0 : contents);
+ }
+}
+
+void _Movetype_Impact(entity oth) // SV_Impact
+{
+ entity oldself = self;
+ entity oldother = other;
+
+ if(self.move_touch)
+ {
+ other = oth;
+
+ self.move_touch();
+
+ other = oldother;
+ }
+
+ if(oth.move_touch)
+ {
+ other = self;
+ self = oth;
+
+ self.move_touch();
+
+ self = oldself;
+ other = oldother;
+ }
+}
+
+void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
+{
+ entity oldself = self;
+ entity oldother = other;
+
+ for (entity e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
+ {
+ if(e.move_touch && boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
+ {
+ self = e;
+ other = oldself;
+
+ trace_allsolid = false;
+ trace_startsolid = false;
+ trace_fraction = 1;
+ trace_inwater = false;
+ trace_inopen = true;
+ trace_endpos = e.origin;
+ trace_plane_normal = '0 0 1';
+ trace_plane_dist = 0;
+ trace_ent = oldself;
+
+ e.move_touch();
+ }
+ }
+
+ other = oldother;
+ self = oldself;
+}
+
+void _Movetype_LinkEdict(bool touch_triggers) // SV_LinkEdict
+{
+ vector mi, ma;
+ if(self.solid == SOLID_BSP)
+ {
+ // TODO set the absolute bbox
+ mi = self.mins;
+ ma = self.maxs;
+ }
+ else
+ {
+ mi = self.mins;
+ ma = self.maxs;
+ }
+ mi += self.move_origin;
+ ma += self.move_origin;
+
+ if(self.move_flags & FL_ITEM)
+ {
+ mi.x -= 15;
+ mi.y -= 15;
+ mi.z -= 1;
+ ma.x += 15;
+ ma.y += 15;
+ ma.z += 1;
+ }
+ else
+ {
+ mi.x -= 1;
+ mi.y -= 1;
+ mi.z -= 1;
+ ma.x += 1;
+ ma.y += 1;
+ ma.z += 1;
+ }
+
+ self.absmin = mi;
+ self.absmax = ma;
+
+ if(touch_triggers)
+ _Movetype_LinkEdict_TouchAreaGrid();
+}
+
+bool _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
+{
+// vector org = self.move_origin + ofs;
+
+ int cont = self.dphitcontentsmask;
+ self.dphitcontentsmask = DPCONTENTS_SOLID;
+ tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
+ self.dphitcontentsmask = cont;
+
+ if(trace_startsolid)
+ return true;
+
+ if(vlen(trace_endpos - self.move_origin) > 0.0001)
+ self.move_origin = trace_endpos;
+ return false;
+}
+
+bool _Movetype_UnstickEntity() // SV_UnstickEntity
+{
+ if(!_Movetype_TestEntityPosition('0 0 0')) return true;
+ if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
+ if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
+ if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
+ if(!_Movetype_TestEntityPosition('0 1 0')) goto success;
+ if(!_Movetype_TestEntityPosition('-1 -1 0')) goto success;
+ if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
+ if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
+ if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
+ for (int i = 1; i <= 17; ++i)
+ {
+ if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
+ if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
+ }
+ dprintf("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n",
+ num_for_edict(self), self.classname, vtos(self.move_origin));
+ return false;
+ : success;
+ dprintf("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n",
+ num_for_edict(self), self.classname, vtos(self.move_origin));
+ _Movetype_LinkEdict(true);
+ return true;
+}
+
+vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
+{
+ vel -= ((vel * norm) * norm) * f;
+
+ if(vel.x > -0.1 && vel.x < 0.1) vel.x = 0;
+ if(vel.y > -0.1 && vel.y < 0.1) vel.y = 0;
+ if(vel.z > -0.1 && vel.z < 0.1) vel.z = 0;
+
+ return vel;
+}
+
+void _Movetype_PushEntityTrace(vector push)
+{
+ vector end = self.move_origin + push;
+ int type;
+ if(self.move_nomonsters)
+ type = max(0, self.move_nomonsters);
+ else if(self.move_movetype == MOVETYPE_FLYMISSILE)
+ type = MOVE_MISSILE;
+ else if(self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
+ type = MOVE_NOMONSTERS;
+ else
+ type = MOVE_NORMAL;
+
+ tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
+}
+
+float _Movetype_PushEntity(vector push, bool failonstartsolid) // SV_PushEntity
+{
+ _Movetype_PushEntityTrace(push);
+
+ if(trace_startsolid && failonstartsolid)
+ return trace_fraction;
+
+ self.move_origin = trace_endpos;
+
+ if(trace_fraction < 1)
+ if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent)))
+ _Movetype_Impact(trace_ent);
+
+ return trace_fraction;
+}
+
+
+.float ltime;
+.void() blocked;
+// matrix version of makevectors, sets v_forward, v_right and v_up
+void makevectors_matrix(vector myangles) // AngleVectorsFLU
+{
+ v_forward = v_right = v_up = '0 0 0';
+
+ float y = myangles.y * (M_PI * 2 / 360);
+ float sy = sin(y);
+ float cy = cos(y);
+ float p = myangles.x * (M_PI * 2 / 360);
+ float sp = sin(p);
+ float cp = cos(p);
+ if(v_forward)
+ {
+ v_forward.x = cp * cy;
+ v_forward.y = cp * sy;
+ v_forward.z = -sp;
+ }
+ if(v_right || v_up)
+ {
+ if(myangles.z)
+ {
+ float r = myangles.z * (M_PI * 2 / 360);
+ float sr = sin(r);
+ float cr = cos(r);
+ if(v_right)
+ {
+ v_right.x = sr * sp * cy + cr * -sy;
+ v_right.y = sr * sp * sy + cr * cy;
+ v_right.z = sr * cp;
+ }
+ if(v_up)
+ {
+ v_up.x = cr * sp * cy + -sr * -sy;
+ v_up.y = cr * sp * sy + -sr * cy;
+ v_up.z = cr * cp;
+ }
+ }
+ else
+ {
+ if(v_right)
+ {
+ v_right.x = -sy;
+ v_right.y = cy;
+ v_right.z = 0;
+ }
+ if(v_up)
+ {
+ v_up.x = sp * cy;
+ v_up.y = sp * sy;
+ v_up.z = cp;
+ }
+ }
+ }
+}
+
+void _Movetype_Physics_Frame(float movedt)
+{
+ self.move_didgravity = -1;
+ switch (self.move_movetype)
+ {
+ case MOVETYPE_PUSH:
+ case MOVETYPE_FAKEPUSH:
+ _Movetype_Physics_Pusher(movedt);
+ break;
+ case MOVETYPE_NONE:
+ break;
+ case MOVETYPE_FOLLOW:
+ _Movetype_Physics_Follow();
+ break;
+ case MOVETYPE_NOCLIP:
+ _Movetype_CheckWater(self);
+ self.move_origin = self.move_origin + TICRATE * self.move_velocity;
+ self.move_angles = self.move_angles + TICRATE * self.move_avelocity;
+ _Movetype_LinkEdict(false);
+ break;
+ case MOVETYPE_STEP:
+ _Movetype_Physics_Step(movedt);
+ break;
+ case MOVETYPE_WALK:
+ _Movetype_Physics_Walk(movedt);
+ break;
+ case MOVETYPE_TOSS:
+ case MOVETYPE_BOUNCE:
+ case MOVETYPE_BOUNCEMISSILE:
+ case MOVETYPE_FLYMISSILE:
+ case MOVETYPE_FLY:
+ _Movetype_Physics_Toss(movedt);
+ break;
+ }
+}
+
+void Movetype_Physics_NoMatchServer() // optimized
+{
+ float movedt = time - self.move_time;
+ self.move_time = time;
+
+ _Movetype_Physics_Frame(movedt);
+ if(wasfreed(self))
+ return;
+
+ self.avelocity = self.move_avelocity;
+ self.velocity = self.move_velocity;
+ self.angles = self.move_angles;
+ setorigin(self, self.move_origin);
+}
+
+void Movetype_Physics_MatchServer(bool sloppy)
+{
+ Movetype_Physics_MatchTicrate(TICRATE, sloppy);
+}
+
+void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
+{
+ if(tr <= 0)
+ {
+ Movetype_Physics_NoMatchServer();
+ return;
+ }
+
+ float dt = time - self.move_time;
+
+ int n = max(0, floor(dt / tr));
+ dt -= n * tr;
+ self.move_time += n * tr;
+
+ if(!self.move_didgravity)
+ self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
+
+ for (int i = 0; i < n; ++i)
+ {
+ _Movetype_Physics_Frame(tr);
+ if(wasfreed(self))
+ return;
+ }
+
+ self.avelocity = self.move_avelocity;
+
+ if(dt > 0 && self.move_movetype != MOVETYPE_NONE && !(self.move_flags & FL_ONGROUND))
+ {
+ // now continue the move from move_time to time
+ self.velocity = self.move_velocity;
+
+ if(self.move_didgravity > 0)
+ {
+ self.velocity_z -= (GRAVITY_UNAFFECTED_BY_TICRATE ? 0.5 : 1)
+ * dt
+ * (self.gravity ? self.gravity : 1)
+ * PHYS_GRAVITY;
+ }
+
+ self.angles = self.move_angles + dt * self.avelocity;
+
+ if(sloppy || self.move_movetype == MOVETYPE_NOCLIP)
+ {
+ setorigin(self, self.move_origin + dt * self.velocity);
+ }
+ else
+ {
+ _Movetype_PushEntityTrace(dt * self.velocity);
+ if(!trace_startsolid)
+ setorigin(self, trace_endpos);
+ }
+
+ if(self.move_didgravity > 0 && GRAVITY_UNAFFECTED_BY_TICRATE)
+ self.velocity_z -= 0.5 * dt * (self.gravity ? self.gravity : 1) * PHYS_GRAVITY;
+ }
+ else
+ {
+ self.velocity = self.move_velocity;
+ self.angles = self.move_angles;
+ setorigin(self, self.move_origin);
+ }
+}
--- /dev/null
+#ifndef MOVETYPES_H
+#define MOVETYPES_H
+
+.float move_ltime;
+.void(void)move_think;
+.float move_nextthink;
+.void(void)move_blocked;
+
+.float move_movetype;
+.float move_time;
+.vector move_origin;
+.vector move_angles;
+.vector move_velocity;
+.vector move_avelocity;
+.int move_flags;
+.int move_watertype;
+.int move_waterlevel;
+.void(void)move_touch;
+.void(float, float)contentstransition;
+.float move_bounce_factor;
+.float move_bounce_stopspeed;
+.float move_nomonsters; // -1 for MOVE_NORMAL, otherwise a MOVE_ constant
+
+.entity move_aiment;
+.vector move_punchangle;
+
+// should match sv_gameplayfix_fixedcheckwatertransition
+float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1;
+
+#ifdef SVQC
+.int stat_gameplayfix_upvelocityclearsonground;
+
+#define GRAVITY_UNAFFECTED_BY_TICRATE autocvar_sv_gameplayfix_gravityunaffectedbyticrate
+#define UPWARD_VELOCITY_CLEARS_ONGROUND autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag
+
+#define TICRATE sys_frametime
+#elif defined(CSQC)
+#define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
+#define UPWARD_VELOCITY_CLEARS_ONGROUND getstati(STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND)
+
+#define TICRATE ticrate
+#endif
+
+.entity move_groundentity; // FIXME add move_groundnetworkentity?
+.float move_suspendedinair;
+.float move_didgravity;
+
+void _Movetype_WallFriction(vector stepnormal);
+int _Movetype_FlyMove(float dt, bool applygravity, vector stepnormal, float stepheight);
+void _Movetype_CheckVelocity();
+void _Movetype_CheckWaterTransition(entity ent);
+float _Movetype_CheckWater(entity ent);
+void _Movetype_LinkEdict_TouchAreaGrid();
+void _Movetype_LinkEdict(float touch_triggers);
+float _Movetype_TestEntityPosition(vector ofs);
+float _Movetype_UnstickEntity();
+vector _Movetype_ClipVelocity(vector vel, vector norm, float f);
+void _Movetype_PushEntityTrace(vector push);
+float _Movetype_PushEntity(vector push, float failonstartsolid);
+void makevectors_matrix(vector myangles);
+
+void Movetype_Physics_MatchTicrate(float tr, bool sloppy);
+void Movetype_Physics_MatchServer(bool sloppy);
+void Movetype_Physics_NoMatchServer();
+void _Movetype_LinkEdict(float touch_triggers);
+void _Movetype_LinkEdict_TouchAreaGrid();
+
+float _Movetype_UnstickEntity();
+
+const int MAX_CLIP_PLANES = 5;
+
+#ifdef CSQC
+const int MOVETYPE_NONE = 0;
+const int MOVETYPE_ANGLENOCLIP = 1;
+const int MOVETYPE_ANGLECLIP = 2;
+const int MOVETYPE_WALK = 3;
+const int MOVETYPE_STEP = 4;
+const int MOVETYPE_FLY = 5;
+const int MOVETYPE_TOSS = 6;
+const int MOVETYPE_PUSH = 7;
+const int MOVETYPE_NOCLIP = 8;
+const int MOVETYPE_FLYMISSILE = 9;
+const int MOVETYPE_BOUNCE = 10;
+const int MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on bouncing
+const int MOVETYPE_FOLLOW = 12;
+const int MOVETYPE_FLY_WORLDONLY = 33;
+
+const int FL_ITEM = 256;
+const int FL_ONGROUND = 512;
+#endif
+
+const int MOVETYPE_FAKEPUSH = 13;
+
+const float MOVEFLAG_Q2AIRACCELERATE = 1;
+const float MOVEFLAG_NOGRAVITYONGROUND = 2;
+const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
+
+#ifdef CSQC
+// TODO: figure out server's version of this
+#define moveflags (getstati(STAT_MOVEFLAGS))
+#endif
+
+#endif
--- /dev/null
+void _Movetype_PushMove(float dt) // SV_PushMove
+{
+ if (self.move_velocity == '0 0 0' && self.move_avelocity == '0 0 0')
+ {
+ self.move_ltime += dt;
+ return;
+ }
+
+ switch (self.solid)
+ {
+ // LordHavoc: valid pusher types
+ case SOLID_BSP:
+ case SOLID_BBOX:
+ case SOLID_SLIDEBOX:
+ case SOLID_CORPSE: // LordHavoc: this would be weird...
+ break;
+ // LordHavoc: no collisions
+ case SOLID_NOT:
+ case SOLID_TRIGGER:
+ self.move_origin = self.move_origin + dt * self.move_velocity;
+ self.move_angles = self.move_angles + dt * self.move_avelocity;
+ self.move_angles_x -= 360.0 * floor(self.move_angles.x * (1.0 / 360.0));
+ self.move_angles_y -= 360.0 * floor(self.move_angles.y * (1.0 / 360.0));
+ self.move_angles_z -= 360.0 * floor(self.move_angles.z * (1.0 / 360.0));
+ self.move_ltime += dt;
+ _Movetype_LinkEdict(true);
+ return;
+ default:
+ dprintf("_Movetype_PushMove: entity %e, unrecognized solid type %d\n", self, self.solid);
+ return;
+ }
+
+ bool rotated = (self.move_angles * self.move_angles) + (self.move_avelocity * self.move_avelocity) > 0;
+
+ vector move1 = self.move_velocity * dt;
+ vector moveangle = self.move_avelocity * dt;
+
+ makevectors_matrix(-moveangle);
+
+// vector pushorig = self.move_origin;
+// vector pushang = self.move_angles;
+// float pushltime = self.move_ltime;
+
+// move the pusher to its final position
+
+ self.move_origin = self.move_origin + dt * self.move_velocity;
+ self.move_angles = self.move_angles + dt * self.move_avelocity;
+
+ self.move_ltime += dt;
+ _Movetype_LinkEdict(true);
+
+ int savesolid = self.solid;
+
+ if (self.move_movetype != MOVETYPE_FAKEPUSH)
+ {
+ for (entity check = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); check; check = check.chain)
+ {
+ switch (check.move_movetype)
+ {
+ case MOVETYPE_NONE:
+ case MOVETYPE_PUSH:
+ case MOVETYPE_FOLLOW:
+ case MOVETYPE_NOCLIP:
+ case MOVETYPE_FLY_WORLDONLY:
+ continue;
+ default:
+ break;
+ }
+
+ if (check.owner == self)
+ continue;
+
+ if (self.owner == check)
+ continue;
+
+ vector pivot = check.mins + 0.5 * (check.maxs - check.mins);
+ vector move;
+ if (rotated)
+ {
+ vector org = (check.move_origin - self.move_origin) + pivot;
+ vector org2;
+ org2.x = org * v_forward;
+ org2.y = org * v_right;
+ org2.z = org * v_up;
+ move = (org2 - org) + move1;
+ }
+ else
+ {
+ move = move1;
+ }
+
+ // physics objects need better collisions than this code can do
+ if (check.move_movetype == 32) // MOVETYPE_PHYSICS
+ {
+ check.move_origin = check.move_origin + move;
+ entity oldself = self;
+ self = check;
+ _Movetype_LinkEdict(true);
+ self = oldself;
+ continue;
+ }
+
+ // try moving the contacted entity
+ self.solid = SOLID_NOT;
+ entity oldself = self;
+ self = check;
+ if (!_Movetype_PushEntity(move, true))
+ {
+ self = oldself;
+ // entity "check" got teleported
+ check.move_angles_y += trace_fraction * moveangle.y;
+ self.solid = savesolid;
+ continue; // pushed enough
+ }
+ self = oldself;
+ // FIXME: turn players specially
+ check.move_angles_y += trace_fraction * moveangle.y;
+ self.solid = savesolid;
+
+ // this trace.fraction < 1 check causes items to fall off of pushers
+ // if they pass under or through a wall
+ // the groundentity check causes items to fall off of ledges
+ if (check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.move_groundentity != self))
+ check.move_flags &= ~FL_ONGROUND;
+ }
+ }
+
+ self.move_angles_x -= 360.0 * floor(self.move_angles.x * (1.0 / 360.0));
+ self.move_angles_y -= 360.0 * floor(self.move_angles.y * (1.0 / 360.0));
+ self.move_angles_z -= 360.0 * floor(self.move_angles.z * (1.0 / 360.0));
+}
+
+void _Movetype_Physics_Pusher(float dt) // SV_Physics_Pusher
+{
+ float oldltime = self.move_ltime;
+ float thinktime = self.move_nextthink;
+ float movetime;
+ if (thinktime < self.move_ltime + dt)
+ {
+ movetime = thinktime - self.move_ltime;
+ if (movetime < 0)
+ movetime = 0;
+ }
+ else
+ {
+ movetime = dt;
+ }
+
+ if (movetime)
+ // advances self.move_ltime if not blocked
+ _Movetype_PushMove(movetime);
+
+ if (thinktime > oldltime && thinktime <= self.move_ltime)
+ {
+ self.move_nextthink = 0;
+ self.move_time = time;
+ other = world;
+ if (self.move_think)
+ self.move_think();
+ }
+}
--- /dev/null
+#ifndef MOVETYPE_PUSH_H
+#define MOVETYPE_PUSH_H
+
+void _Movetype_Physics_Pusher(float dt);
+
+#endif
\ No newline at end of file
--- /dev/null
+void _Movetype_Physics_Step(float dt) // SV_Physics_Step
+{
+ if(self.move_flags & FL_ONGROUND)
+ {
+ if(self.velocity_z >= (1.0 / 32.0) && UPWARD_VELOCITY_CLEARS_ONGROUND)
+ {
+ self.move_flags &= ~FL_ONGROUND;
+ _Movetype_CheckVelocity();
+ _Movetype_FlyMove(dt, true, '0 0 0', 0);
+ _Movetype_LinkEdict(true);
+ }
+ }
+ else
+ {
+ _Movetype_CheckVelocity();
+ _Movetype_FlyMove(dt, true, '0 0 0', 0);
+ _Movetype_LinkEdict(true);
+
+ // TODO? movetypesteplandevent
+ }
+
+ _Movetype_CheckWaterTransition(self);
+}
--- /dev/null
+#include "../physics.qh"
+
+void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
+{
+ if (self.move_flags & FL_ONGROUND)
+ {
+ if (self.move_velocity.z >= 1 / 32)
+ {
+ self.move_flags &= ~FL_ONGROUND;
+ }
+ else if (!self.move_groundentity)
+ {
+ return;
+ }
+ else if (self.move_suspendedinair && wasfreed(self.move_groundentity))
+ {
+ self.move_groundentity = world;
+ return;
+ }
+ }
+
+ self.move_suspendedinair = false;
+
+ _Movetype_CheckVelocity();
+
+ if (self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
+ {
+ self.move_didgravity = 1;
+ self.move_velocity_z -= (GRAVITY_UNAFFECTED_BY_TICRATE ? 0.5 : 1)
+ * dt
+ * (self.gravity ? self.gravity : 1)
+ * PHYS_GRAVITY;
+ }
+
+ self.move_angles = self.move_angles + self.move_avelocity * dt;
+
+ float movetime = dt;
+ for (int bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
+ {
+ vector move = self.move_velocity * movetime;
+ _Movetype_PushEntity(move, true);
+ if (wasfreed(self))
+ return;
+
+ if (trace_startsolid)
+ {
+ _Movetype_UnstickEntity();
+ _Movetype_PushEntity(move, false);
+ if (wasfreed(self))
+ return;
+ }
+
+ if (trace_fraction == 1)
+ break;
+
+ movetime *= 1 - min(1, trace_fraction);
+
+ if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+ {
+ self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
+ self.move_flags &= ~FL_ONGROUND;
+ }
+ else if (self.move_movetype == MOVETYPE_BOUNCE)
+ {
+ float bouncefac = self.move_bounce_factor; if (!bouncefac) bouncefac = 0.5;
+ float bouncestop = self.move_bounce_stopspeed; if (!bouncestop) bouncestop = 60 / 800;
+ bouncestop *= (self.gravity ? self.gravity : 1) * PHYS_GRAVITY;
+
+ self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
+
+ float d = trace_plane_normal * self.move_velocity;
+ if (trace_plane_normal.z > 0.7 && d < bouncestop && d > -bouncestop)
+ {
+ self.move_flags |= FL_ONGROUND;
+ self.move_groundentity = trace_ent;
+ self.move_velocity = '0 0 0';
+ self.move_avelocity = '0 0 0';
+ }
+ else
+ {
+ self.move_flags &= ~FL_ONGROUND;
+ }
+ }
+ else
+ {
+ self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
+ if (trace_plane_normal.z > 0.7)
+ {
+ self.move_flags |= FL_ONGROUND;
+ self.move_groundentity = trace_ent;
+ if (trace_ent.solid == SOLID_BSP)
+ self.move_suspendedinair = true;
+ self.move_velocity = '0 0 0';
+ self.move_avelocity = '0 0 0';
+ }
+ else
+ {
+ self.move_flags &= ~FL_ONGROUND;
+ }
+ }
+
+ // DP revision 8905 (just, WHY...)
+ if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+ break;
+
+ // DP revision 8918 (WHY...)
+ if (self.move_flags & FL_ONGROUND)
+ break;
+ }
+
+ if (GRAVITY_UNAFFECTED_BY_TICRATE && self.move_didgravity > 0 && !(self.move_flags & FL_ONGROUND))
+ self.move_velocity_z -= 0.5 * dt * (self.gravity ? self.gravity : 1) * PHYS_GRAVITY;
+
+ _Movetype_CheckWaterTransition(self);
+}
--- /dev/null
+#ifndef MOVETYPE_TOSS_H
+#define MOVETYPE_TOSS_H
+
+void _Movetype_Physics_Toss(float dt);
+
+#endif
\ No newline at end of file
--- /dev/null
+void _Movetype_Physics_Walk(float dt) // SV_WalkMove
+{
+ vector stepnormal = '0 0 0';
+
+ // if frametime is 0 (due to client sending the same timestamp twice), don't move
+ if (dt <= 0)
+ return;
+
+ if (GAMEPLAYFIX_UNSTICKPLAYERS)
+ _Movetype_UnstickEntity();
+
+ bool applygravity = (!_Movetype_CheckWater(self) && self.move_movetype == MOVETYPE_WALK && !(self.move_flags & FL_WATERJUMP));
+
+ _Movetype_CheckVelocity();
+
+ // do a regular slide move unless it looks like you ran into a step
+ bool oldonground = (self.move_flags & FL_ONGROUND);
+
+ vector start_origin = self.move_origin;
+ vector start_velocity = self.move_velocity;
+
+ int clip = _Movetype_FlyMove(dt, applygravity, stepnormal, GAMEPLAYFIX_STEPMULTIPLETIMES ? PHYS_STEPHEIGHT : 0);
+
+ if (GAMEPLAYFIX_DOWNTRACEONGROUND && !(clip & 1))
+ {
+ // only try this if there was no floor in the way in the trace (no,
+ // this check seems to be not REALLY necessary, because if clip & 1,
+ // our trace will hit that thing too)
+ vector upmove = self.move_origin + '0 0 1';
+ vector downmove = self.move_origin - '0 0 1';
+ int type;
+ if (self.move_movetype == MOVETYPE_FLYMISSILE)
+ type = MOVE_MISSILE;
+ else if (self.move_movetype == MOVETYPE_FLY_WORLDONLY)
+ type = MOVE_WORLDONLY;
+ else if (self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
+ type = MOVE_NOMONSTERS;
+ else type = MOVE_NORMAL;
+ tracebox(upmove, self.mins, self.maxs, downmove, type, self);
+ if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
+ clip |= 1; // but we HAVE found a floor
+ }
+
+ // if the move did not hit the ground at any point, we're not on ground
+ if (!(clip & 1))
+ self.move_flags &= ~FL_ONGROUND;
+
+ _Movetype_CheckVelocity();
+ _Movetype_LinkEdict(true);
+
+ if (clip & 8) // teleport
+ return;
+
+ if (self.move_flags & FL_WATERJUMP)
+ return;
+
+ if (PHYS_NOSTEP)
+ return;
+
+ vector originalmove_origin = self.move_origin;
+ vector originalmove_velocity = self.move_velocity;
+ // originalmove_clip = clip;
+ int originalmove_flags = self.move_flags;
+ entity originalmove_groundentity = self.move_groundentity;
+
+ // if move didn't block on a step, return
+ if (clip & 2)
+ {
+ // if move was not trying to move into the step, return
+ if (fabs(start_velocity.x) < 0.03125 && fabs(start_velocity.y) < 0.03125)
+ return;
+
+ if (self.move_movetype != MOVETYPE_FLY)
+ {
+ // return if gibbed by a trigger
+ if (self.move_movetype != MOVETYPE_WALK)
+ return;
+
+ // return if attempting to jump while airborn (unless sv_jumpstep)
+ if (!PHYS_JUMPSTEP)
+ if (!oldonground && self.move_waterlevel == 0)
+ return;
+ }
+
+ // try moving up and forward to go up a step
+ // back to start pos
+ self.move_origin = start_origin;
+ self.move_velocity = start_velocity;
+
+ // move up
+ vector upmove = '0 0 1' * PHYS_STEPHEIGHT;
+ if (!_Movetype_PushEntity(upmove, true))
+ {
+ // we got teleported when upstepping... must abort the move
+ return;
+ }
+
+ // move forward
+ self.move_velocity_z = 0;
+ clip = _Movetype_FlyMove(dt, applygravity, stepnormal, 0);
+ self.move_velocity_z += start_velocity.z;
+ if (clip & 8)
+ {
+ // we got teleported when upstepping... must abort the move
+ // note that z velocity handling may not be what QC expects here, but we cannot help it
+ return;
+ }
+
+ _Movetype_CheckVelocity();
+ _Movetype_LinkEdict(true);
+
+ // check for stuckness, possibly due to the limited precision of floats
+ // in the clipping hulls
+ if (clip
+ && fabs(originalmove_origin.y - self.move_origin.y) < 0.03125
+ && fabs(originalmove_origin.x - self.move_origin.x) < 0.03125)
+ {
+ // Con_Printf("wall\n");
+ // stepping up didn't make any progress, revert to original move
+ self.move_origin = originalmove_origin;
+ self.move_velocity = originalmove_velocity;
+ // clip = originalmove_clip;
+ self.move_flags = originalmove_flags;
+ self.move_groundentity = originalmove_groundentity;
+ // now try to unstick if needed
+ // clip = SV_TryUnstick (ent, oldvel);
+ return;
+ }
+
+ // Con_Printf("step - ");
+
+ // extra friction based on view angle
+ if (clip & 2 && PHYS_WALLFRICTION)
+ _Movetype_WallFriction(stepnormal);
+ }
+ // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
+ else if (!GAMEPLAYFIX_STEPDOWN || self.move_waterlevel >= 3 || start_velocity.z >= (1.0 / 32.0) || !oldonground || (self.move_flags & FL_ONGROUND))
+ {
+ return;
+ }
+
+ // move down
+ vector downmove = '0 0 1' * (-PHYS_STEPHEIGHT + start_velocity.z * dt);
+ if (!_Movetype_PushEntity(downmove, true))
+ {
+ // we got teleported when downstepping... must abort the move
+ return;
+ }
+
+ if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
+ {
+ // this has been disabled so that you can't jump when you are stepping
+ // up while already jumping (also known as the Quake2 double jump bug)
+ }
+ else
+ {
+ // Con_Printf("slope\n");
+ // if the push down didn't end up on good ground, use the move without
+ // the step up. This happens near wall / slope combinations, and can
+ // cause the player to hop up higher on a slope too steep to climb
+ self.move_origin = originalmove_origin;
+ self.move_velocity = originalmove_velocity;
+ self.move_flags = originalmove_flags;
+ self.move_groundentity = originalmove_groundentity;
+ }
+
+ _Movetype_CheckVelocity();
+ _Movetype_LinkEdict(true);
+}
--- /dev/null
+#ifndef MOVETYPE_WALK_H
+#define MOVETYPE_WALK_H
+
+void _Movetype_Physics_Walk(float dt);
+
+#endif
#include "../client/defs.qh"
#include "nades.qh"
#include "buffs.qh"
- #include "../client/movetypes.qh"
+ #include "../common/movetypes/movetypes.qh"
#include "../server/tturrets/include/turrets_early.qh"
#include "../client/main.qh"
#include "../csqcmodellib/cl_model.qh"
#ifndef NADES_H
#define NADES_H
+#include "teams.qh"
+
.float healer_lifetime;
.float healer_radius;
}
#ifdef SVQC
-float healer_send(entity to, float sf);
+float healer_send(entity to, int sf);
#endif
#ifdef CSQC
#endif // SVQC
#ifdef CSQC
-void SUB_Remove()
-{ remove(self); }
-
void cl_notice_read()
{
entity _notice;
#ifdef SVQC
void Notification_GetCvars(void)
{
- float i;
- for(i = 0; i <= NOTIF_CHOICE_COUNT; ++i)
+ for(int i = 0; i <= NOTIF_CHOICE_COUNT; ++i)
{
GetCvars_handleFloat(
get_cvars_s,
if(notif.nent_challow_var && (warmup_stage || (notif.nent_challow_var == 2)))
{
- switch(cvar_string(sprintf("notification_%s", notif.nent_name)))
+ switch(cvar(sprintf("notification_%s", notif.nent_name)))
{
case 1: found_choice = notif.nent_optiona; break;
case 2: found_choice = notif.nent_optionb; break;
));
#endif
- float i;
- for(i = 0; i < 4; ++i) { if(self.nent_strings[i]) { strunzone(self.nent_strings[i]); } }
+ for(int i = 0; i < 4; ++i) { if(self.nent_strings[i]) { strunzone(self.nent_strings[i]); } }
remove(self);
}
-float Net_Write_Notification(entity client, float sf)
+float Net_Write_Notification(entity client, int sf)
{
if(Notification_ShouldSend(self.nent_broadcast, client, self.nent_client))
{
- float i;
WriteByte(MSG_ENTITY, ENT_CLIENT_NOTIFICATION);
WriteByte(MSG_ENTITY, self.nent_net_type);
WriteShort(MSG_ENTITY, self.nent_net_name);
- for(i = 0; i < self.nent_stringcount; ++i) { WriteString(MSG_ENTITY, self.nent_strings[i]); }
- for(i = 0; i < self.nent_floatcount; ++i) { WriteLong(MSG_ENTITY, self.nent_floats[i]); }
+ for(int i = 0; i < self.nent_stringcount; ++i) { WriteString(MSG_ENTITY, self.nent_strings[i]); }
+ for(int i = 0; i < self.nent_floatcount; ++i) { WriteLong(MSG_ENTITY, self.nent_floats[i]); }
return true;
}
else { return false; }
net_notif.nent_stringcount = notif.nent_stringcount;
net_notif.nent_floatcount = notif.nent_floatcount;
- float i;
- for(i = 0; i < net_notif.nent_stringcount; ++i)
+ for(int i = 0; i < net_notif.nent_stringcount; ++i)
{ net_notif.nent_strings[i] = strzone(...(i, string)); }
- for(i = 0; i < net_notif.nent_floatcount; ++i)
+ for(int i = 0; i < net_notif.nent_floatcount; ++i)
{ net_notif.nent_floats[i] = ...((net_notif.nent_stringcount + i), float); }
net_notif.think = Net_Notification_Remove;
#include "constants.qh"
#include "teams.qh"
+#include "util.qh"
// ================================================
// Unified notification system, written by Samual
--- /dev/null
+#ifndef OO_H
+#define OO_H
+
+#ifdef MENUQC
+ #define NULL (null_entity)
+#else
+ #define NULL (world)
+#endif
+
+.string classname;
+.string vtblname;
+.entity vtblbase;
+entity spawnVtbl(entity this, entity base)
+{
+ entity vtbl = spawn();
+ copyentity(this, vtbl);
+ vtbl.vtblname = vtbl.classname;
+ vtbl.classname = "vtbl";
+ vtbl.vtblbase = base ? base : vtbl; // Top level objects use vtbl as base
+ return vtbl;
+}
+
+entity Object_vtbl;
+entity spawnObject(entity this, entity)
+{
+ this = spawn();
+ this.classname = "Object";
+ if (!Object_vtbl) Object_vtbl = spawnVtbl(this, NULL);
+ return this;
+}
+
+// Classes have a `spawn##cname(entity, entity)` constructor
+// The parameters are used as locals for [[accumulate]]
+
+// Macro to hide this implementation detail
+#define NEW(cname) (spawn##cname(NULL, NULL))
+
+#define CLASS(cname, base) \
+entity spawn##cname(entity this, entity basevtbl) { \
+ this = NEW(base); basevtbl = base##_vtbl; \
+}
+
+#define METHOD(cname, name, prototype) \
+prototype cname##_##name; \
+.prototype name; \
+[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \
+ this.name = cname##_##name; \
+}
+
+#define ATTRIB(cname, name, type, val) \
+.type name; \
+[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \
+ this.name = val; \
+}
+
+#define ATTRIBARRAY(cname, name, type, cnt) \
+.type name[cnt];
+
+#define ENDCLASS(cname) \
+.bool instanceOf##cname; \
+entity cname##_vtbl; \
+[[accumulate]] [[last]] entity spawn##cname(entity this, entity basevtbl) { \
+ this.instanceOf##cname = true; \
+ this.classname = #cname; \
+ if (!cname##_vtbl) cname##_vtbl = spawnVtbl(this, basevtbl); \
+ return this; \
+}
+
+#define SUPER(cname) (cname##_vtbl.vtblbase)
+
+#endif
--- /dev/null
+#include "physics.qh"
+#include "triggers/trigger/swamp.qh"
+#include "triggers/trigger/jumppads.qh"
+
+#ifdef SVQC
+
+#include "../server/miscfunctions.qh"
+
+// client side physics
+bool Physics_Valid(string thecvar)
+{
+ if(!autocvar_g_physics_clientselect) { return false; }
+
+ string l = strcat(" ", autocvar_g_physics_clientselect_options, " ");
+
+ if(strstrofs(l, strcat(" ", thecvar, " "), 0) >= 0)
+ return true;
+
+ return false;
+}
+
+float Physics_ClientOption(entity pl, string option)
+{
+ if(Physics_Valid(pl.cvar_cl_physics))
+ {
+ string var = sprintf("g_physics_%s_%s", pl.cvar_cl_physics, option);
+ if(cvar_type(var) & CVAR_TYPEFLAG_EXISTS)
+ return cvar(var);
+ }
+ if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default)
+ {
+ string var = sprintf("g_physics_%s_%s", autocvar_g_physics_clientselect_default, option);
+ if(cvar_type(var) & CVAR_TYPEFLAG_EXISTS)
+ return cvar(var);
+ }
+ return cvar(strcat("sv_", option));
+}
+
+void Physics_AddStats()
+{
+ // static view offset and hitbox vectors
+ // networked for all you bandwidth pigs out there
+ addstat(STAT_PL_VIEW_OFS1, AS_FLOAT, stat_pl_view_ofs_x);
+ addstat(STAT_PL_VIEW_OFS2, AS_FLOAT, stat_pl_view_ofs_y);
+ addstat(STAT_PL_VIEW_OFS3, AS_FLOAT, stat_pl_view_ofs_z);
+ addstat(STAT_PL_CROUCH_VIEW_OFS1, AS_FLOAT, stat_pl_crouch_view_ofs_x);
+ addstat(STAT_PL_CROUCH_VIEW_OFS2, AS_FLOAT, stat_pl_crouch_view_ofs_y);
+ addstat(STAT_PL_CROUCH_VIEW_OFS3, AS_FLOAT, stat_pl_crouch_view_ofs_z);
+
+ addstat(STAT_PL_MIN1, AS_FLOAT, stat_pl_min_x);
+ addstat(STAT_PL_MIN2, AS_FLOAT, stat_pl_min_y);
+ addstat(STAT_PL_MIN3, AS_FLOAT, stat_pl_min_z);
+ addstat(STAT_PL_MAX1, AS_FLOAT, stat_pl_max_x);
+ addstat(STAT_PL_MAX2, AS_FLOAT, stat_pl_max_y);
+ addstat(STAT_PL_MAX3, AS_FLOAT, stat_pl_max_z);
+ addstat(STAT_PL_CROUCH_MIN1, AS_FLOAT, stat_pl_crouch_min_x);
+ addstat(STAT_PL_CROUCH_MIN2, AS_FLOAT, stat_pl_crouch_min_y);
+ addstat(STAT_PL_CROUCH_MIN3, AS_FLOAT, stat_pl_crouch_min_z);
+ addstat(STAT_PL_CROUCH_MAX1, AS_FLOAT, stat_pl_crouch_max_x);
+ addstat(STAT_PL_CROUCH_MAX2, AS_FLOAT, stat_pl_crouch_max_y);
+ addstat(STAT_PL_CROUCH_MAX3, AS_FLOAT, stat_pl_crouch_max_z);
+
+ // g_movementspeed hack
+ addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
+ addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
+ addstat(STAT_MOVEVARS_AIRACCEL_QW, AS_FLOAT, stat_sv_airaccel_qw);
+ addstat(STAT_MOVEVARS_AIRSTRAFEACCEL_QW, AS_FLOAT, stat_sv_airstrafeaccel_qw);
+ addstat(STAT_MOVEVARS_HIGHSPEED, AS_FLOAT, stat_movement_highspeed);
+
+ // jet pack
+ addstat(STAT_JETPACK_ACCEL_SIDE, AS_FLOAT, stat_jetpack_accel_side);
+ addstat(STAT_JETPACK_ACCEL_UP, AS_FLOAT, stat_jetpack_accel_up);
+ addstat(STAT_JETPACK_ANTIGRAVITY, AS_FLOAT, stat_jetpack_antigravity);
+ addstat(STAT_JETPACK_FUEL, AS_FLOAT, stat_jetpack_fuel);
+ addstat(STAT_JETPACK_MAXSPEED_UP, AS_FLOAT, stat_jetpack_maxspeed_up);
+ addstat(STAT_JETPACK_MAXSPEED_SIDE, AS_FLOAT, stat_jetpack_maxspeed_side);
+
+ // hack to fix track_canjump
+ addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
+
+ // double jump
+ addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump);
+
+ // jump speed caps
+ addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min);
+ addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min);
+ addstat(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, AS_INT, stat_jumpspeedcap_disable_onramps);
+
+ // hacks
+ addstat(STAT_MOVEVARS_FRICTION_ONLAND, AS_FLOAT, stat_sv_friction_on_land);
+ addstat(STAT_MOVEVARS_FRICTION_SLICK, AS_FLOAT, stat_sv_friction_slick);
+ addstat(STAT_GAMEPLAYFIX_EASIERWATERJUMP, AS_INT, stat_gameplayfix_easierwaterjump);
+
+ // new properties
+ addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_sv_jumpvelocity);
+ addstat(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, AS_FLOAT, stat_sv_airaccel_qw_stretchfactor);
+ addstat(STAT_MOVEVARS_MAXAIRSTRAFESPEED, AS_FLOAT, stat_sv_maxairstrafespeed);
+ addstat(STAT_MOVEVARS_MAXAIRSPEED, AS_FLOAT, stat_sv_maxairspeed);
+ addstat(STAT_MOVEVARS_AIRSTRAFEACCELERATE, AS_FLOAT, stat_sv_airstrafeaccelerate);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL, AS_FLOAT, stat_sv_warsowbunny_turnaccel);
+ addstat(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, AS_FLOAT, stat_sv_airaccel_sideways_friction);
+ addstat(STAT_MOVEVARS_AIRCONTROL, AS_FLOAT, stat_sv_aircontrol);
+ addstat(STAT_MOVEVARS_AIRCONTROL_POWER, AS_FLOAT, stat_sv_aircontrol_power);
+ addstat(STAT_MOVEVARS_AIRCONTROL_PENALTY, AS_FLOAT, stat_sv_aircontrol_penalty);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, AS_FLOAT, stat_sv_warsowbunny_airforwardaccel);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED, AS_FLOAT, stat_sv_warsowbunny_topspeed);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_ACCEL, AS_FLOAT, stat_sv_warsowbunny_accel);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, AS_FLOAT, stat_sv_warsowbunny_backtosideratio);
+ addstat(STAT_MOVEVARS_FRICTION, AS_FLOAT, stat_sv_friction);
+ addstat(STAT_MOVEVARS_ACCELERATE, AS_FLOAT, stat_sv_accelerate);
+ addstat(STAT_MOVEVARS_STOPSPEED, AS_FLOAT, stat_sv_stopspeed);
+ addstat(STAT_MOVEVARS_AIRACCELERATE, AS_FLOAT, stat_sv_airaccelerate);
+ addstat(STAT_MOVEVARS_AIRSTOPACCELERATE, AS_FLOAT, stat_sv_airstopaccelerate);
+
+ addstat(STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, AS_INT, stat_gameplayfix_upvelocityclearsonground);
+}
+
+void Physics_UpdateStats(float maxspd_mod)
+{
+ // blah
+ self.stat_pl_view_ofs = PL_VIEW_OFS;
+ self.stat_pl_crouch_view_ofs = PL_CROUCH_VIEW_OFS;
+
+ self.stat_pl_min = PL_MIN;
+ self.stat_pl_max = PL_MAX;
+ self.stat_pl_crouch_min = PL_CROUCH_MIN;
+ self.stat_pl_crouch_max = PL_CROUCH_MAX;
+
+
+ self.stat_sv_airaccel_qw = AdjustAirAccelQW(Physics_ClientOption(self, "airaccel_qw"), maxspd_mod);
+ if(Physics_ClientOption(self, "airstrafeaccel_qw"))
+ self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(Physics_ClientOption(self, "airstrafeaccel_qw"), maxspd_mod);
+ else
+ self.stat_sv_airstrafeaccel_qw = 0;
+ self.stat_sv_airspeedlimit_nonqw = Physics_ClientOption(self, "airspeedlimit_nonqw") * maxspd_mod;
+ self.stat_sv_maxspeed = Physics_ClientOption(self, "maxspeed") * maxspd_mod; // also slow walking
+ self.stat_movement_highspeed = PHYS_HIGHSPEED; // TODO: remove this!
+
+ self.stat_doublejump = PHYS_DOUBLEJUMP;
+
+ self.stat_jetpack_antigravity = PHYS_JETPACK_ANTIGRAVITY;
+ self.stat_jetpack_accel_up = PHYS_JETPACK_ACCEL_UP;
+ self.stat_jetpack_accel_side = PHYS_JETPACK_ACCEL_SIDE;
+ self.stat_jetpack_maxspeed_side = PHYS_JETPACK_MAXSPEED_SIDE;
+ self.stat_jetpack_maxspeed_up = PHYS_JETPACK_MAXSPEED_UP;
+ self.stat_jetpack_fuel = PHYS_JETPACK_FUEL;
+
+ self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN;
+ self.stat_jumpspeedcap_max = PHYS_JUMPSPEEDCAP_MAX;
+ self.stat_jumpspeedcap_disable_onramps = PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS;
+
+ self.stat_sv_friction_on_land = PHYS_FRICTION_ONLAND;
+ self.stat_sv_friction_slick = PHYS_FRICTION_SLICK;
+
+ self.stat_gameplayfix_easierwaterjump = GAMEPLAYFIX_EASIERWATERJUMP;
+
+
+ // old stats
+ // fix some new settings
+ self.stat_sv_airaccel_qw_stretchfactor = Physics_ClientOption(self, "airaccel_qw_stretchfactor");
+ self.stat_sv_maxairstrafespeed = Physics_ClientOption(self, "maxairstrafespeed");
+ self.stat_sv_maxairspeed = Physics_ClientOption(self, "maxairspeed");
+ self.stat_sv_airstrafeaccelerate = Physics_ClientOption(self, "airstrafeaccelerate");
+ self.stat_sv_warsowbunny_turnaccel = Physics_ClientOption(self, "warsowbunny_turnaccel");
+ self.stat_sv_airaccel_sideways_friction = Physics_ClientOption(self, "airaccel_sideways_friction");
+ self.stat_sv_aircontrol = Physics_ClientOption(self, "aircontrol");
+ self.stat_sv_aircontrol_power = Physics_ClientOption(self, "aircontrol_power");
+ self.stat_sv_aircontrol_penalty = Physics_ClientOption(self, "aircontrol_penalty");
+ self.stat_sv_warsowbunny_airforwardaccel = Physics_ClientOption(self, "warsowbunny_airforwardaccel");
+ self.stat_sv_warsowbunny_topspeed = Physics_ClientOption(self, "warsowbunny_topspeed");
+ self.stat_sv_warsowbunny_accel = Physics_ClientOption(self, "warsowbunny_accel");
+ self.stat_sv_warsowbunny_backtosideratio = Physics_ClientOption(self, "warsowbunny_backtosideratio");
+ self.stat_sv_friction = Physics_ClientOption(self, "friction");
+ self.stat_sv_accelerate = Physics_ClientOption(self, "accelerate");
+ self.stat_sv_stopspeed = Physics_ClientOption(self, "stopspeed");
+ self.stat_sv_airaccelerate = Physics_ClientOption(self, "airaccelerate");
+ self.stat_sv_airstopaccelerate = Physics_ClientOption(self, "airstopaccelerate");
+ self.stat_sv_jumpvelocity = Physics_ClientOption(self, "jumpvelocity");
+
+ self.stat_gameplayfix_upvelocityclearsonground = UPWARD_VELOCITY_CLEARS_ONGROUND;
+}
+#endif
+
+float IsMoveInDirection(vector mv, float ang) // key mix factor
+{
+ if (mv_x == 0 && mv_y == 0)
+ return 0; // avoid division by zero
+ ang -= RAD2DEG * atan2(mv_y, mv_x);
+ ang = remainder(ang, 360) / 45;
+ return ang > 1 ? 0 : ang < -1 ? 0 : 1 - fabs(ang);
+}
+
+float GeomLerp(float a, float lerp, float b)
+{
+ return a == 0 ? (lerp < 1 ? 0 : b)
+ : b == 0 ? (lerp > 0 ? 0 : a)
+ : a * pow(fabs(b / a), lerp);
+}
+
+noref float pmove_waterjumptime;
+
+const float unstick_count = 27;
+vector unstick_offsets[unstick_count] =
+{
+// 1 no nudge (just return the original if this test passes)
+ '0.000 0.000 0.000',
+// 6 simple nudges
+ ' 0.000 0.000 0.125', '0.000 0.000 -0.125',
+ '-0.125 0.000 0.000', '0.125 0.000 0.000',
+ ' 0.000 -0.125 0.000', '0.000 0.125 0.000',
+// 4 diagonal flat nudges
+ '-0.125 -0.125 0.000', '0.125 -0.125 0.000',
+ '-0.125 0.125 0.000', '0.125 0.125 0.000',
+// 8 diagonal upward nudges
+ '-0.125 0.000 0.125', '0.125 0.000 0.125',
+ ' 0.000 -0.125 0.125', '0.000 0.125 0.125',
+ '-0.125 -0.125 0.125', '0.125 -0.125 0.125',
+ '-0.125 0.125 0.125', '0.125 0.125 0.125',
+// 8 diagonal downward nudges
+ '-0.125 0.000 -0.125', '0.125 0.000 -0.125',
+ ' 0.000 -0.125 -0.125', '0.000 0.125 -0.125',
+ '-0.125 -0.125 -0.125', '0.125 -0.125 -0.125',
+ '-0.125 0.125 -0.125', '0.125 0.125 -0.125',
+};
+
+void PM_ClientMovement_Unstick()
+{
+ float i;
+ for (i = 0; i < unstick_count; i++)
+ {
+ vector neworigin = unstick_offsets[i] + self.origin;
+ tracebox(neworigin, PL_CROUCH_MIN, PL_CROUCH_MAX, neworigin, MOVE_NORMAL, self);
+ if (!trace_startsolid)
+ {
+ setorigin(self, neworigin);
+ return;// true;
+ }
+ }
+}
+
+void PM_ClientMovement_UpdateStatus(bool ground)
+{
+ // make sure player is not stuck
+ PM_ClientMovement_Unstick();
+
+ // set crouched
+ if (PHYS_INPUT_BUTTON_CROUCH(self))
+ {
+ // wants to crouch, this always works..
+ if (!IS_DUCKED(self))
+ SET_DUCKED(self);
+ }
+ else
+ {
+ // wants to stand, if currently crouching we need to check for a
+ // low ceiling first
+ if (IS_DUCKED(self))
+ {
+ tracebox(self.origin, PL_MIN, PL_MAX, self.origin, MOVE_NORMAL, self);
+ if (!trace_startsolid)
+ UNSET_DUCKED(self);
+ }
+ }
+
+ // set onground
+ vector origin1 = self.origin + '0 0 1';
+ vector origin2 = self.origin - '0 0 1';
+
+ if(ground)
+ {
+ tracebox(origin1, self.mins, self.maxs, origin2, MOVE_NORMAL, self);
+ if (trace_fraction < 1.0 && trace_plane_normal_z > 0.7)
+ {
+ SET_ONGROUND(self);
+
+ // this code actually "predicts" an impact; so let's clip velocity first
+ float f = self.velocity * trace_plane_normal;
+ self.velocity -= f * trace_plane_normal;
+ }
+ else
+ UNSET_ONGROUND(self);
+ }
+
+ // set watertype/waterlevel
+ origin1 = self.origin;
+ origin1_z += self.mins_z + 1;
+ self.waterlevel = WATERLEVEL_NONE;
+
+ int thepoint = pointcontents(origin1);
+
+ self.watertype = (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME);
+
+ if(self.watertype)
+ {
+ self.waterlevel = WATERLEVEL_WETFEET;
+ origin1_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
+ thepoint = pointcontents(origin1);
+ if(thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
+ {
+ self.waterlevel = WATERLEVEL_SWIMMING;
+ origin1_z = self.origin_z + 22;
+ thepoint = pointcontents(origin1);
+ if(thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
+ self.waterlevel = WATERLEVEL_SUBMERGED;
+ }
+ }
+
+ if(IS_ONGROUND(self) || self.velocity_z <= 0 || pmove_waterjumptime <= 0)
+ pmove_waterjumptime = 0;
+}
+
+void PM_ClientMovement_Move()
+{
+#ifdef CSQC
+ int bump;
+ float t;
+ float f;
+ vector neworigin;
+ vector currentorigin2;
+ vector neworigin2;
+ vector primalvelocity;
+
+ vector trace1_endpos = '0 0 0';
+ vector trace2_endpos = '0 0 0';
+ vector trace3_endpos = '0 0 0';
+ float trace1_fraction = 0;
+ float trace2_fraction = 0;
+ float trace3_fraction = 0;
+ vector trace1_plane_normal = '0 0 0';
+ vector trace2_plane_normal = '0 0 0';
+ vector trace3_plane_normal = '0 0 0';
+
+
+ PM_ClientMovement_UpdateStatus(false);
+ primalvelocity = self.velocity;
+ for(bump = 0, t = PHYS_INPUT_TIMELENGTH; bump < 8 && (self.velocity * self.velocity) > 0; bump++)
+ {
+ neworigin = self.origin + t * self.velocity;
+ tracebox(self.origin, self.mins, self.maxs, neworigin, MOVE_NORMAL, self);
+ trace1_endpos = trace_endpos;
+ trace1_fraction = trace_fraction;
+ trace1_plane_normal = trace_plane_normal;
+ if(trace1_fraction < 1 && trace1_plane_normal_z == 0)
+ {
+ // may be a step or wall, try stepping up
+ // first move forward at a higher level
+ currentorigin2 = self.origin;
+ currentorigin2_z += PHYS_STEPHEIGHT;
+ neworigin2 = neworigin;
+ neworigin2_z += PHYS_STEPHEIGHT;
+ tracebox(currentorigin2, self.mins, self.maxs, neworigin2, MOVE_NORMAL, self);
+ trace2_endpos = trace_endpos;
+ trace2_fraction = trace_fraction;
+ trace2_plane_normal = trace_plane_normal;
+ if(!trace_startsolid)
+ {
+ // then move down from there
+ currentorigin2 = trace2_endpos;
+ neworigin2 = trace2_endpos;
+ neworigin2_z = self.origin_z;
+ tracebox(currentorigin2, self.mins, self.maxs, neworigin2, MOVE_NORMAL, self);
+ trace3_endpos = trace_endpos;
+ trace3_fraction = trace_fraction;
+ trace3_plane_normal = trace_plane_normal;
+ // accept the new trace if it made some progress
+ if(fabs(trace3_endpos_x - trace1_endpos_x) >= 0.03125 || fabs(trace3_endpos_y - trace1_endpos_y) >= 0.03125)
+ {
+ trace1_endpos = trace2_endpos;
+ trace1_fraction = trace2_fraction;
+ trace1_plane_normal = trace2_plane_normal;
+ trace1_endpos = trace3_endpos;
+ }
+ }
+ }
+
+ // check if it moved at all
+ if(trace1_fraction >= 0.001)
+ setorigin(self, trace1_endpos);
+
+ // check if it moved all the way
+ if(trace1_fraction == 1)
+ break;
+
+ // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate
+ // <LordHavoc> I'm pretty sure I commented it out solely because it seemed redundant
+ // this got commented out in a change that supposedly makes the code match QW better
+ // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block
+ if(trace1_plane_normal_z > 0.7)
+ SET_ONGROUND(self);
+
+ t -= t * trace1_fraction;
+
+ f = (self.velocity * trace1_plane_normal);
+ self.velocity = self.velocity + -f * trace1_plane_normal;
+ }
+ if(pmove_waterjumptime > 0)
+ self.velocity = primalvelocity;
+#endif
+}
+
+void CPM_PM_Aircontrol(vector wishdir, float wishspeed)
+{
+ float k = 32 * (2 * IsMoveInDirection(self.movement, 0) - 1);
+ if (k <= 0)
+ return;
+
+ k *= bound(0, wishspeed / PHYS_MAXAIRSPEED(self), 1);
+
+ float zspeed = self.velocity_z;
+ self.velocity_z = 0;
+ float xyspeed = vlen(self.velocity);
+ self.velocity = normalize(self.velocity);
+
+ float dot = self.velocity * wishdir;
+
+ if (dot > 0) // we can't change direction while slowing down
+ {
+ k *= pow(dot, PHYS_AIRCONTROL_POWER) * PHYS_INPUT_TIMELENGTH;
+ xyspeed = max(0, xyspeed - PHYS_AIRCONTROL_PENALTY * sqrt(max(0, 1 - dot*dot)) * k/32);
+ k *= PHYS_AIRCONTROL;
+ self.velocity = normalize(self.velocity * xyspeed + wishdir * k);
+ }
+
+ self.velocity = self.velocity * xyspeed;
+ self.velocity_z = zspeed;
+}
+
+float AdjustAirAccelQW(float accelqw, float factor)
+{
+ return copysign(bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1), accelqw);
+}
+
+// example config for alternate speed clamping:
+// sv_airaccel_qw 0.8
+// sv_airaccel_sideways_friction 0
+// prvm_globalset server speedclamp_mode 1
+// (or 2)
+void PM_Accelerate(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
+ : -1; // no clamping
+
+ accelqw = fabs(accelqw);
+
+ if (GAMEPLAYFIX_Q2AIRACCELERATE)
+ wishspeed0 = wishspeed; // don't need to emulate this Q1 bug
+
+ float vel_straight = self.velocity * wishdir;
+ float vel_z = self.velocity_z;
+ vector vel_xy = vec2(self.velocity);
+ vector vel_perpend = vel_xy - vel_straight * wishdir;
+
+ float step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
+
+ float vel_xy_current = vlen(vel_xy);
+ if (speedlimit)
+ accelqw = AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed));
+ float vel_xy_forward = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
+ float vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw);
+ vel_xy_backward = max(0, vel_xy_backward); // not that it REALLY occurs that this would cause wrong behaviour afterwards
+ vel_straight = vel_straight + bound(0, wishspeed - vel_straight, step) * accelqw + step * (1 - accelqw);
+
+ 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 fmin = (vel_xy_backward * vel_xy_backward - vel_straight * vel_straight) / (vel_perpend * vel_perpend);
+ // assume: fmin > 1
+ // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend
+ // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend
+ // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy
+ // obviously, this cannot be
+ if (fmin <= 0)
+ vel_perpend *= f;
+ else
+ {
+ fmin = sqrt(fmin);
+ vel_perpend *= max(fmin, f);
+ }
+ }
+ else
+ vel_perpend *= max(0, 1 - PHYS_INPUT_TIMELENGTH * wishspeed * sidefric);
+
+ vel_xy = vel_straight * wishdir + vel_perpend;
+
+ if (speedclamp >= 0)
+ {
+ float vel_xy_preclamp;
+ vel_xy_preclamp = vlen(vel_xy);
+ if (vel_xy_preclamp > 0) // prevent division by zero
+ {
+ vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp;
+ if (vel_xy_current < vel_xy_preclamp)
+ vel_xy *= (vel_xy_current / vel_xy_preclamp);
+ }
+ }
+
+ self.velocity = vel_xy + vel_z * '0 0 1';
+}
+
+void PM_AirAccelerate(vector wishdir, float wishspeed)
+{
+ if (wishspeed == 0)
+ return;
+
+ vector curvel = self.velocity;
+ curvel_z = 0;
+ float curspeed = vlen(curvel);
+
+ if (wishspeed > curspeed * 1.01)
+ wishspeed = min(wishspeed, curspeed + PHYS_WARSOWBUNNY_AIRFORWARDACCEL * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH);
+ else
+ {
+ float f = max(0, (PHYS_WARSOWBUNNY_TOPSPEED - curspeed) / (PHYS_WARSOWBUNNY_TOPSPEED - PHYS_MAXSPEED(self)));
+ wishspeed = max(curspeed, PHYS_MAXSPEED(self)) + PHYS_WARSOWBUNNY_ACCEL * f * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH;
+ }
+ vector wishvel = wishdir * wishspeed;
+ vector acceldir = wishvel - curvel;
+ float addspeed = vlen(acceldir);
+ acceldir = normalize(acceldir);
+
+ float accelspeed = min(addspeed, PHYS_WARSOWBUNNY_TURNACCEL * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH);
+
+ if (PHYS_WARSOWBUNNY_BACKTOSIDERATIO < 1)
+ {
+ vector curdir = normalize(curvel);
+ float dot = acceldir * curdir;
+ if (dot < 0)
+ acceldir -= (1 - PHYS_WARSOWBUNNY_BACKTOSIDERATIO) * dot * curdir;
+ }
+
+ self.velocity += accelspeed * acceldir;
+}
+
+
+/*
+=============
+PlayerJump
+
+When you press the jump key
+returns true if handled
+=============
+*/
+bool PlayerJump (void)
+{
+ if (PHYS_FROZEN(self))
+ return true; // no jumping in freezetag when frozen
+
+#ifdef SVQC
+ if (self.player_blocked)
+ return true; // no jumping while blocked
+#endif
+
+ bool doublejump = false;
+ float mjumpheight = PHYS_JUMPVELOCITY;
+
+ player_multijump = doublejump;
+ player_jumpheight = mjumpheight;
+#ifdef SVQC
+ if (MUTATOR_CALLHOOK(PlayerJump))
+#elif defined(CSQC)
+ if(PM_multijump_checkjump())
+#endif
+ return true;
+
+ doublejump = player_multijump;
+ mjumpheight = player_jumpheight;
+
+ if (PHYS_DOUBLEJUMP)
+ {
+ tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
+ if (trace_fraction < 1 && trace_plane_normal_z > 0.7)
+ {
+ doublejump = true;
+
+ // we MUST clip velocity here!
+ float f;
+ f = self.velocity * trace_plane_normal;
+ if (f < 0)
+ self.velocity -= f * trace_plane_normal;
+ }
+ }
+
+ if (self.waterlevel >= WATERLEVEL_SWIMMING)
+ {
+ self.velocity_z = PHYS_MAXSPEED(self) * 0.7;
+ return true;
+ }
+
+ if (!doublejump)
+ if (!IS_ONGROUND(self))
+ return IS_JUMP_HELD(self);
+
+ if (PHYS_TRACK_CANJUMP(self))
+ if (IS_JUMP_HELD(self))
+ return true;
+
+ // sv_jumpspeedcap_min/sv_jumpspeedcap_max act as baseline
+ // velocity bounds. Final velocity is bound between (jumpheight *
+ // min + jumpheight) and (jumpheight * max + jumpheight);
+
+ if(PHYS_JUMPSPEEDCAP_MIN)
+ {
+ float minjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MIN;
+
+ if (self.velocity_z < minjumpspeed)
+ mjumpheight += minjumpspeed - self.velocity_z;
+ }
+
+ if(PHYS_JUMPSPEEDCAP_MAX)
+ {
+ // don't do jump speedcaps on ramps to preserve old xonotic ramjump style
+ tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
+
+ if (!(trace_fraction < 1 && trace_plane_normal_z < 0.98 && PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS))
+ {
+ float maxjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MAX;
+
+ if (self.velocity_z > maxjumpspeed)
+ mjumpheight -= self.velocity_z - maxjumpspeed;
+ }
+ }
+
+ if (!WAS_ONGROUND(self))
+ {
+#ifdef SVQC
+ if(autocvar_speedmeter)
+ dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
+#endif
+ if(self.lastground < time - 0.3)
+ {
+ self.velocity_x *= (1 - PHYS_FRICTION_ONLAND);
+ self.velocity_y *= (1 - PHYS_FRICTION_ONLAND);
+ }
+#ifdef SVQC
+ if(self.jumppadcount > 1)
+ dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
+ self.jumppadcount = 0;
+#endif
+ }
+
+ self.velocity_z += mjumpheight;
+
+ UNSET_ONGROUND(self);
+ SET_JUMP_HELD(self);
+
+#ifdef SVQC
+
+ self.oldvelocity_z = self.velocity_z;
+
+ animdecide_setaction(self, ANIMACTION_JUMP, true);
+
+ if (autocvar_g_jump_grunt)
+ PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+#endif
+ return true;
+}
+
+void CheckWaterJump()
+{
+// check for a jump-out-of-water
+ makevectors(self.v_angle);
+ vector start = self.origin;
+ start_z += 8;
+ v_forward_z = 0;
+ normalize(v_forward);
+ vector end = start + v_forward*24;
+ traceline (start, end, true, self);
+ if (trace_fraction < 1)
+ { // solid at waist
+ start_z = start_z + self.maxs_z - 8;
+ end = start + v_forward*24;
+ self.movedir = trace_plane_normal * -50;
+ traceline(start, end, true, self);
+ if (trace_fraction == 1)
+ { // open at eye level
+ self.velocity_z = 225;
+ self.flags |= FL_WATERJUMP;
+ SET_JUMP_HELD(self);
+#ifdef SVQC
+ self.teleport_time = time + 2; // safety net
+#elif defined(CSQC)
+ pmove_waterjumptime = time + 2;
+#endif
+ }
+ }
+}
+
+
+#ifdef SVQC
+ #define JETPACK_JUMP(s) s.cvar_cl_jetpack_jump
+#elif defined(CSQC)
+ float autocvar_cl_jetpack_jump;
+ #define JETPACK_JUMP(s) autocvar_cl_jetpack_jump
+#endif
+.float jetpack_stopped;
+// Hack: shouldn't need to know about this
+.float multijump_count;
+void CheckPlayerJump()
+{
+#ifdef SVQC
+ float was_flying = ITEMS_STAT(self) & IT_USING_JETPACK;
+#endif
+ if (JETPACK_JUMP(self) < 2)
+ ITEMS_STAT(self) &= ~IT_USING_JETPACK;
+
+ if(PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self))
+ {
+ float air_jump = !PlayerJump() || self.multijump_count > 0; // PlayerJump() has important side effects
+ float activate = JETPACK_JUMP(self) && air_jump && PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self);
+ float has_fuel = !PHYS_JETPACK_FUEL || PHYS_AMMO_FUEL(self) || ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO;
+
+ if (!(ITEMS_STAT(self) & IT_JETPACK)) { }
+ else if (self.jetpack_stopped) { }
+ else if (!has_fuel)
+ {
+#ifdef SVQC
+ if (was_flying) // TODO: ran out of fuel message
+ Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
+ else if (activate)
+ Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
+#endif
+ self.jetpack_stopped = true;
+ ITEMS_STAT(self) &= ~IT_USING_JETPACK;
+ }
+ else if (activate && !PHYS_FROZEN(self))
+ ITEMS_STAT(self) |= IT_USING_JETPACK;
+ }
+ else
+ {
+ self.jetpack_stopped = false;
+ ITEMS_STAT(self) &= ~IT_USING_JETPACK;
+ }
+ if (!PHYS_INPUT_BUTTON_JUMP(self))
+ UNSET_JUMP_HELD(self);
+
+ if (self.waterlevel == WATERLEVEL_SWIMMING)
+ CheckWaterJump();
+}
+
+float racecar_angle(float forward, float down)
+{
+ if (forward < 0)
+ {
+ forward = -forward;
+ down = -down;
+ }
+
+ float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
+
+ float angle_mult = forward / (800 + forward);
+
+ if (ret > 180)
+ return ret * angle_mult + 360 * (1 - angle_mult);
+ else
+ return ret * angle_mult;
+}
+
+void RaceCarPhysics()
+{
+#ifdef SVQC
+ // using this move type for "big rigs"
+ // the engine does not push the entity!
+
+ vector rigvel;
+
+ vector angles_save = self.angles;
+ float accel = bound(-1, self.movement.x / PHYS_MAXSPEED(self), 1);
+ float steer = bound(-1, self.movement.y / PHYS_MAXSPEED(self), 1);
+
+ if (g_bugrigs_reverse_speeding)
+ {
+ if (accel < 0)
+ {
+ // back accel is DIGITAL
+ // to prevent speedhack
+ if (accel < -0.5)
+ accel = -1;
+ else
+ accel = 0;
+ }
+ }
+
+ self.angles_x = 0;
+ self.angles_z = 0;
+ makevectors(self.angles); // new forward direction!
+
+ if (IS_ONGROUND(self) || g_bugrigs_air_steering)
+ {
+ float myspeed = self.velocity * v_forward;
+ float upspeed = self.velocity * v_up;
+
+ // responsiveness factor for steering and acceleration
+ float f = 1 / (1 + pow(max(-myspeed, myspeed) / g_bugrigs_speed_ref, g_bugrigs_speed_pow));
+ //MAXIMA: f(v) := 1 / (1 + (v / g_bugrigs_speed_ref) ^ g_bugrigs_speed_pow);
+
+ float steerfactor;
+ if (myspeed < 0 && g_bugrigs_reverse_spinning)
+ steerfactor = -myspeed * g_bugrigs_steer;
+ else
+ steerfactor = -myspeed * f * g_bugrigs_steer;
+
+ float accelfactor;
+ if (myspeed < 0 && g_bugrigs_reverse_speeding)
+ accelfactor = g_bugrigs_accel;
+ else
+ accelfactor = f * g_bugrigs_accel;
+ //MAXIMA: accel(v) := f(v) * g_bugrigs_accel;
+
+ if (accel < 0)
+ {
+ if (myspeed > 0)
+ {
+ myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * (g_bugrigs_friction_floor - g_bugrigs_friction_brake * accel));
+ }
+ else
+ {
+ if (!g_bugrigs_reverse_speeding)
+ myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * g_bugrigs_friction_floor);
+ }
+ }
+ else
+ {
+ if (myspeed >= 0)
+ {
+ myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * g_bugrigs_friction_floor);
+ }
+ else
+ {
+ if (g_bugrigs_reverse_stopping)
+ myspeed = 0;
+ else
+ myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * (g_bugrigs_friction_floor + g_bugrigs_friction_brake * accel));
+ }
+ }
+ // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
+ //MAXIMA: friction(v) := g_bugrigs_friction_floor;
+
+ self.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering
+ makevectors(self.angles); // new forward direction!
+
+ myspeed += accel * accelfactor * PHYS_INPUT_TIMELENGTH;
+
+ rigvel = myspeed * v_forward + '0 0 1' * upspeed;
+ }
+ else
+ {
+ float myspeed = vlen(self.velocity);
+
+ // responsiveness factor for steering and acceleration
+ float f = 1 / (1 + pow(max(0, myspeed / g_bugrigs_speed_ref), g_bugrigs_speed_pow));
+ float steerfactor = -myspeed * f;
+ self.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering
+
+ rigvel = self.velocity;
+ makevectors(self.angles); // new forward direction!
+ }
+
+ rigvel *= max(0, 1 - vlen(rigvel) * g_bugrigs_friction_air * PHYS_INPUT_TIMELENGTH);
+ //MAXIMA: airfriction(v) := v * v * g_bugrigs_friction_air;
+ //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
+ //MAXIMA: solve(total_acceleration(v) = 0, v);
+
+ if (g_bugrigs_planar_movement)
+ {
+ vector rigvel_xy, neworigin, up;
+ float mt;
+
+ rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better
+ rigvel_xy = vec2(rigvel);
+
+ if (g_bugrigs_planar_movement_car_jumping)
+ mt = MOVE_NORMAL;
+ else
+ mt = MOVE_NOMONSTERS;
+
+ tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 1024', mt, self);
+ up = trace_endpos - self.origin;
+
+ // BUG RIGS: align the move to the surface instead of doing collision testing
+ // can we move?
+ tracebox(trace_endpos, self.mins, self.maxs, trace_endpos + rigvel_xy * PHYS_INPUT_TIMELENGTH, mt, self);
+
+ // align to surface
+ tracebox(trace_endpos, self.mins, self.maxs, trace_endpos - up + '0 0 1' * rigvel_z * PHYS_INPUT_TIMELENGTH, mt, self);
+
+ if (trace_fraction < 0.5)
+ {
+ trace_fraction = 1;
+ neworigin = self.origin;
+ }
+ else
+ neworigin = trace_endpos;
+
+ if (trace_fraction < 1)
+ {
+ // now set angles_x so that the car points parallel to the surface
+ self.angles = vectoangles(
+ '1 0 0' * v_forward_x * trace_plane_normal_z
+ +
+ '0 1 0' * v_forward_y * trace_plane_normal_z
+ +
+ '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y)
+ );
+ SET_ONGROUND(self);
+ }
+ else
+ {
+ // now set angles_x so that the car points forward, but is tilted in velocity direction
+ UNSET_ONGROUND(self);
+ }
+
+ self.velocity = (neworigin - self.origin) * (1.0 / PHYS_INPUT_TIMELENGTH);
+ self.movetype = MOVETYPE_NOCLIP;
+ }
+ else
+ {
+ rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better
+ self.velocity = rigvel;
+ self.movetype = MOVETYPE_FLY;
+ }
+
+ trace_fraction = 1;
+ tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 4', MOVE_NORMAL, self);
+ if (trace_fraction != 1)
+ {
+ self.angles = vectoangles2(
+ '1 0 0' * v_forward_x * trace_plane_normal_z
+ +
+ '0 1 0' * v_forward_y * trace_plane_normal_z
+ +
+ '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y),
+ trace_plane_normal
+ );
+ }
+ else
+ {
+ vector vel_local;
+
+ vel_local_x = v_forward * self.velocity;
+ vel_local_y = v_right * self.velocity;
+ vel_local_z = v_up * self.velocity;
+
+ self.angles_x = racecar_angle(vel_local_x, vel_local_z);
+ self.angles_z = racecar_angle(-vel_local_y, vel_local_z);
+ }
+
+ // smooth the angles
+ vector vf1, vu1, smoothangles;
+ makevectors(self.angles);
+ float f = bound(0, PHYS_INPUT_TIMELENGTH * g_bugrigs_angle_smoothing, 1);
+ if (f == 0)
+ f = 1;
+ vf1 = v_forward * f;
+ vu1 = v_up * f;
+ makevectors(angles_save);
+ vf1 = vf1 + v_forward * (1 - f);
+ vu1 = vu1 + v_up * (1 - f);
+ smoothangles = vectoangles2(vf1, vu1);
+ self.angles_x = -smoothangles_x;
+ self.angles_z = smoothangles_z;
+#endif
+}
+
+string specialcommand = "xwxwxsxsxaxdxaxdx1x ";
+.float specialcommand_pos;
+void SpecialCommand()
+{
+#ifdef SVQC
+#ifdef TETRIS
+ TetrisImpulse();
+#else
+ if (!CheatImpulse(99))
+ print("A hollow voice says \"Plugh\".\n");
+#endif
+#endif
+}
+
+float PM_check_keepaway(void)
+{
+#ifdef SVQC
+ return (self.ballcarried && g_keepaway) ? autocvar_g_keepaway_ballcarrier_highspeed : 1;
+#else
+ return 1;
+#endif
+}
+
+void PM_check_race_movetime(void)
+{
+#ifdef SVQC
+ self.race_movetime_frac += PHYS_INPUT_TIMELENGTH;
+ float f = floor(self.race_movetime_frac);
+ self.race_movetime_frac -= f;
+ self.race_movetime_count += f;
+ self.race_movetime = self.race_movetime_frac + self.race_movetime_count;
+#endif
+}
+
+float PM_check_specialcommand(float buttons)
+{
+#ifdef SVQC
+ string c;
+ if (!buttons)
+ c = "x";
+ else if (buttons == 1)
+ c = "1";
+ else if (buttons == 2)
+ c = " ";
+ else if (buttons == 128)
+ c = "s";
+ else if (buttons == 256)
+ c = "w";
+ else if (buttons == 512)
+ c = "a";
+ else if (buttons == 1024)
+ c = "d";
+ else
+ c = "?";
+
+ if (c == substring(specialcommand, self.specialcommand_pos, 1))
+ {
+ self.specialcommand_pos += 1;
+ if (self.specialcommand_pos >= strlen(specialcommand))
+ {
+ self.specialcommand_pos = 0;
+ SpecialCommand();
+ return true;
+ }
+ }
+ else if (self.specialcommand_pos && (c != substring(specialcommand, self.specialcommand_pos - 1, 1)))
+ self.specialcommand_pos = 0;
+#endif
+ return false;
+}
+
+void PM_check_nickspam(void)
+{
+#ifdef SVQC
+ if (time >= self.nickspamtime)
+ return;
+ if (self.nickspamcount >= autocvar_g_nick_flood_penalty_yellow)
+ {
+ // slight annoyance for nick change scripts
+ self.movement = -1 * self.movement;
+ self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = self.BUTTON_ZOOM = self.BUTTON_CROUCH = self.BUTTON_HOOK = self.BUTTON_USE = 0;
+
+ if (self.nickspamcount >= autocvar_g_nick_flood_penalty_red) // if you are persistent and the slight annoyance above does not stop you, I'll show you!
+ {
+ self.v_angle_x = random() * 360;
+ self.v_angle_y = random() * 360;
+ // at least I'm not forcing retardedview by also assigning to angles_z
+ self.fixangle = true;
+ }
+ }
+#endif
+}
+
+void PM_check_punch()
+{
+#ifdef SVQC
+ if (self.punchangle != '0 0 0')
+ {
+ float f = vlen(self.punchangle) - 10 * PHYS_INPUT_TIMELENGTH;
+ if (f > 0)
+ self.punchangle = normalize(self.punchangle) * f;
+ else
+ self.punchangle = '0 0 0';
+ }
+
+ if (self.punchvector != '0 0 0')
+ {
+ float f = vlen(self.punchvector) - 30 * PHYS_INPUT_TIMELENGTH;
+ if (f > 0)
+ self.punchvector = normalize(self.punchvector) * f;
+ else
+ self.punchvector = '0 0 0';
+ }
+#endif
+}
+
+void PM_check_spider(void)
+{
+#ifdef SVQC
+ if (time >= self.spider_slowness)
+ return;
+ PHYS_MAXSPEED(self) *= 0.5; // half speed while slow from spider
+ PHYS_MAXAIRSPEED(self) *= 0.5;
+ PHYS_AIRSPEEDLIMIT_NONQW(self) *= 0.5;
+ PHYS_AIRSTRAFEACCELERATE(self) *= 0.5;
+#endif
+}
+
+// predict frozen movement, as frozen players CAN move in some cases
+void PM_check_frozen(void)
+{
+ if (!PHYS_FROZEN(self))
+ return;
+ if (PHYS_DODGING_FROZEN
+#ifdef SVQC
+ && IS_REAL_CLIENT(self)
+#endif
+ )
+ {
+ self.movement_x = bound(-5, self.movement.x, 5);
+ self.movement_y = bound(-5, self.movement.y, 5);
+ self.movement_z = bound(-5, self.movement.z, 5);
+ }
+ else
+ self.movement = '0 0 0';
+
+ vector midpoint = ((self.absmin + self.absmax) * 0.5);
+ if (pointcontents(midpoint) == CONTENT_WATER)
+ {
+ self.velocity = self.velocity * 0.5;
+
+ if (pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
+ self.velocity_z = 200;
+ }
+}
+
+void PM_check_hitground()
+{
+#ifdef SVQC
+ if (IS_ONGROUND(self))
+ if (IS_PLAYER(self)) // no fall sounds for observers thank you very much
+ if (self.wasFlying)
+ {
+ self.wasFlying = 0;
+ if (self.waterlevel < WATERLEVEL_SWIMMING)
+ if (time >= self.ladder_time)
+ if (!self.hook)
+ {
+ self.nextstep = time + 0.3 + random() * 0.1;
+ trace_dphitq3surfaceflags = 0;
+ tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
+ if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
+ {
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
+ GlobalSound(globalsound_metalfall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ else
+ GlobalSound(globalsound_fall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ }
+ }
+ }
+#endif
+}
+
+void PM_check_blocked(void)
+{
+#ifdef SVQC
+ if (!self.player_blocked)
+ return;
+ self.movement = '0 0 0';
+ self.disableclientprediction = 1;
+#endif
+}
+
+#ifdef SVQC
+float speedaward_lastsent;
+float speedaward_lastupdate;
+#endif
+void PM_check_race(void)
+{
+#ifdef SVQC
+ if(!(g_cts || g_race))
+ return;
+ if (vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed)
+ {
+ speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1');
+ speedaward_holder = self.netname;
+ speedaward_uid = self.crypto_idfp;
+ speedaward_lastupdate = time;
+ }
+ if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
+ {
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+ race_send_speedaward(MSG_ALL);
+ speedaward_lastsent = speedaward_speed;
+ if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
+ {
+ speedaward_alltimebest = speedaward_speed;
+ speedaward_alltimebest_holder = speedaward_holder;
+ speedaward_alltimebest_uid = speedaward_uid;
+ db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
+ db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
+ race_send_speedaward_alltimebest(MSG_ALL);
+ }
+ }
+#endif
+}
+
+void PM_check_vortex(void)
+{
+#ifdef SVQC
+ // WEAPONTODO
+ float xyspeed = vlen(vec2(self.velocity));
+ if (self.weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed))
+ {
+ // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed
+ xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed));
+ float f = (xyspeed - WEP_CVAR(vortex, charge_minspeed)) / (WEP_CVAR(vortex, charge_maxspeed) - WEP_CVAR(vortex, charge_minspeed));
+ // add the extra charge
+ self.vortex_charge = min(1, self.vortex_charge + WEP_CVAR(vortex, charge_velocity_rate) * f * PHYS_INPUT_TIMELENGTH);
+ }
+#endif
+}
+
+void PM_fly(float maxspd_mod)
+{
+ // noclipping or flying
+ UNSET_ONGROUND(self);
+
+ self.velocity = self.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION);
+ makevectors(self.v_angle);
+ //wishvel = v_forward * self.movement.x + v_right * self.movement.y + v_up * self.movement.z;
+ vector wishvel = v_forward * self.movement.x
+ + v_right * self.movement.y
+ + '0 0 1' * self.movement.z;
+ // acceleration
+ vector wishdir = normalize(wishvel);
+ float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod);
+#ifdef SVQC
+ if (time >= self.teleport_time)
+#endif
+ PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE * maxspd_mod, 1, 0, 0, 0);
+ PM_ClientMovement_Move();
+}
+
+void PM_swim(float maxspd_mod)
+{
+ // swimming
+ UNSET_ONGROUND(self);
+
+ float jump = PHYS_INPUT_BUTTON_JUMP(self);
+ // water jump only in certain situations
+ // this mimics quakeworld code
+ if (jump && self.waterlevel == WATERLEVEL_SWIMMING && self.velocity_z >= -180)
+ {
+ vector yawangles = '0 1 0' * self.v_angle.y;
+ makevectors(yawangles);
+ vector forward = v_forward;
+ vector spot = self.origin + 24 * forward;
+ spot_z += 8;
+ traceline(spot, spot, MOVE_NOMONSTERS, self);
+ if (trace_startsolid)
+ {
+ spot_z += 24;
+ traceline(spot, spot, MOVE_NOMONSTERS, self);
+ if (!trace_startsolid)
+ {
+ self.velocity = forward * 50;
+ self.velocity_z = 310;
+ pmove_waterjumptime = 2;
+ UNSET_ONGROUND(self);
+ SET_JUMP_HELD(self);
+ }
+ }
+ }
+ makevectors(self.v_angle);
+ //wishvel = v_forward * self.movement.x + v_right * self.movement.y + v_up * self.movement.z;
+ vector wishvel = v_forward * self.movement.x
+ + v_right * self.movement.y
+ + '0 0 1' * self.movement.z;
+ if (wishvel == '0 0 0')
+ wishvel = '0 0 -60'; // drift towards bottom
+
+ vector wishdir = normalize(wishvel);
+ float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod) * 0.7;
+
+ if (IS_DUCKED(self))
+ wishspeed *= 0.5;
+
+// if (pmove_waterjumptime <= 0) // TODO: use
+ {
+ // water friction
+ float f = 1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION;
+ f = min(max(0, f), 1);
+ self.velocity *= f;
+
+ f = wishspeed - self.velocity * wishdir;
+ if (f > 0)
+ {
+ float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, f);
+ self.velocity += accelspeed * wishdir;
+ }
+
+ // holding jump button swims upward slowly
+ if (jump)
+ {
+#if 0
+ if (self.watertype & CONTENT_LAVA)
+ self.velocity_z = 50;
+ else if (self.watertype & CONTENT_SLIME)
+ self.velocity_z = 80;
+ else
+ {
+ if (IS_NEXUIZ_DERIVED(gamemode))
+#endif
+ self.velocity_z = 200;
+#if 0
+ else
+ self.velocity_z = 100;
+ }
+#endif
+ }
+ }
+ // water acceleration
+ PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE * maxspd_mod, 1, 0, 0, 0);
+ PM_ClientMovement_Move();
+}
+
+void PM_ladder(float maxspd_mod)
+{
+ // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water
+ UNSET_ONGROUND(self);
+
+ float g;
+ g = PHYS_GRAVITY * PHYS_INPUT_TIMELENGTH;
+ if (PHYS_ENTGRAVITY(self))
+ g *= PHYS_ENTGRAVITY(self);
+ if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
+ {
+ g *= 0.5;
+ self.velocity_z += g;
+ }
+
+ self.velocity = self.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION);
+ makevectors(self.v_angle);
+ //wishvel = v_forward * self.movement.x + v_right * self.movement.y + v_up * self.movement.z;
+ vector wishvel = v_forward * self.movement_x
+ + v_right * self.movement_y
+ + '0 0 1' * self.movement_z;
+ self.velocity_z += g;
+ if (self.ladder_entity.classname == "func_water")
+ {
+ float f = vlen(wishvel);
+ if (f > self.ladder_entity.speed)
+ wishvel *= (self.ladder_entity.speed / f);
+
+ self.watertype = self.ladder_entity.skin;
+ f = self.ladder_entity.origin_z + self.ladder_entity.maxs_z;
+ if ((self.origin_z + self.view_ofs_z) < f)
+ self.waterlevel = WATERLEVEL_SUBMERGED;
+ else if ((self.origin_z + (self.mins_z + self.maxs_z) * 0.5) < f)
+ self.waterlevel = WATERLEVEL_SWIMMING;
+ else if ((self.origin_z + self.mins_z + 1) < f)
+ self.waterlevel = WATERLEVEL_WETFEET;
+ else
+ {
+ self.waterlevel = WATERLEVEL_NONE;
+ self.watertype = CONTENT_EMPTY;
+ }
+ }
+ // acceleration
+ vector wishdir = normalize(wishvel);
+ float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod);
+#ifdef SVQC
+ if (time >= self.teleport_time)
+#endif
+ // water acceleration
+ PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE*maxspd_mod, 1, 0, 0, 0);
+ PM_ClientMovement_Move();
+}
+
+void PM_jetpack(float maxspd_mod)
+{
+ //makevectors(self.v_angle.y * '0 1 0');
+ makevectors(self.v_angle);
+ vector wishvel = v_forward * self.movement_x
+ + v_right * self.movement_y;
+ // add remaining speed as Z component
+ float maxairspd = PHYS_MAXAIRSPEED(self) * max(1, maxspd_mod);
+ // fix speedhacks :P
+ wishvel = normalize(wishvel) * min(1, vlen(wishvel) / maxairspd);
+ // add the unused velocity as up component
+ wishvel_z = 0;
+
+ // if (self.BUTTON_JUMP)
+ wishvel_z = sqrt(max(0, 1 - wishvel * wishvel));
+
+ // it is now normalized, so...
+ float a_side = PHYS_JETPACK_ACCEL_SIDE;
+ float a_up = PHYS_JETPACK_ACCEL_UP;
+ float a_add = PHYS_JETPACK_ANTIGRAVITY * PHYS_GRAVITY;
+
+ wishvel_x *= a_side;
+ wishvel_y *= a_side;
+ wishvel_z *= a_up;
+ wishvel_z += a_add;
+
+ float best = 0;
+ //////////////////////////////////////////////////////////////////////////////////////
+ // finding the maximum over all vectors of above form
+ // with wishvel having an absolute value of 1
+ //////////////////////////////////////////////////////////////////////////////////////
+ // we're finding the maximum over
+ // f(a_side, a_up, a_add, z) := a_side * (1 - z^2) + (a_add + a_up * z)^2;
+ // for z in the range from -1 to 1
+ //////////////////////////////////////////////////////////////////////////////////////
+ // maximum is EITHER attained at the single extreme point:
+ float a_diff = a_side * a_side - a_up * a_up;
+ float f;
+ if (a_diff != 0)
+ {
+ f = a_add * a_up / a_diff; // this is the zero of diff(f(a_side, a_up, a_add, z), z)
+ if (f > -1 && f < 1) // can it be attained?
+ {
+ best = (a_diff + a_add * a_add) * (a_diff + a_up * a_up) / a_diff;
+ //print("middle\n");
+ }
+ }
+ // OR attained at z = 1:
+ f = (a_up + a_add) * (a_up + a_add);
+ if (f > best)
+ {
+ best = f;
+ //print("top\n");
+ }
+ // OR attained at z = -1:
+ f = (a_up - a_add) * (a_up - a_add);
+ if (f > best)
+ {
+ best = f;
+ //print("bottom\n");
+ }
+ best = sqrt(best);
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ //print("best possible acceleration: ", ftos(best), "\n");
+
+ float fxy, fz;
+ fxy = bound(0, 1 - (self.velocity * normalize(wishvel_x * '1 0 0' + wishvel_y * '0 1 0')) / PHYS_JETPACK_MAXSPEED_SIDE, 1);
+ if (wishvel_z - PHYS_GRAVITY > 0)
+ fz = bound(0, 1 - self.velocity_z / PHYS_JETPACK_MAXSPEED_UP, 1);
+ else
+ fz = bound(0, 1 + self.velocity_z / PHYS_JETPACK_MAXSPEED_UP, 1);
+
+ float fvel;
+ fvel = vlen(wishvel);
+ wishvel_x *= fxy;
+ wishvel_y *= fxy;
+ wishvel_z = (wishvel_z - PHYS_GRAVITY) * fz + PHYS_GRAVITY;
+
+ fvel = min(1, vlen(wishvel) / best);
+ if (PHYS_JETPACK_FUEL && !(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
+ f = min(1, PHYS_AMMO_FUEL(self) / (PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel));
+ else
+ f = 1;
+
+ //print("this acceleration: ", ftos(vlen(wishvel) * f), "\n");
+
+ if (f > 0 && wishvel != '0 0 0')
+ {
+ self.velocity = self.velocity + wishvel * f * PHYS_INPUT_TIMELENGTH;
+ UNSET_ONGROUND(self);
+
+#ifdef SVQC
+ if (!(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
+ self.ammo_fuel -= PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel * f;
+
+ ITEMS_STAT(self) |= IT_USING_JETPACK;
+
+ // jetpack also inhibits health regeneration, but only for 1 second
+ self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen);
+#endif
+ }
+
+#ifdef CSQC
+ float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
+ if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
+ self.velocity_z -= g * 0.5;
+ else
+ self.velocity_z -= g;
+ PM_ClientMovement_Move();
+ if (!IS_ONGROUND(self) || !(GAMEPLAYFIX_NOGRAVITYONGROUND))
+ if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
+ self.velocity_z -= g * 0.5;
+#endif
+}
+
+void PM_walk(float buttons_prev, float maxspd_mod)
+{
+ if (!WAS_ONGROUND(self))
+ {
+#ifdef SVQC
+ if (autocvar_speedmeter)
+ dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
+#endif
+ if (self.lastground < time - 0.3)
+ self.velocity *= (1 - PHYS_FRICTION_ONLAND);
+#ifdef SVQC
+ if (self.jumppadcount > 1)
+ dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
+ self.jumppadcount = 0;
+#endif
+ }
+
+ // walking
+ makevectors(self.v_angle.y * '0 1 0');
+ vector wishvel = v_forward * self.movement.x
+ + v_right * self.movement.y;
+ // acceleration
+ vector wishdir = normalize(wishvel);
+ float wishspeed = vlen(wishvel);
+
+ wishspeed = min(wishspeed, PHYS_MAXSPEED(self) * maxspd_mod);
+ if (IS_DUCKED(self))
+ wishspeed *= 0.5;
+
+ // apply edge friction
+ float f = vlen(vec2(self.velocity));
+ if (f > 0)
+ {
+ float realfriction;
+ trace_dphitq3surfaceflags = 0;
+ tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
+ // TODO: apply edge friction
+ // apply ground friction
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
+ realfriction = PHYS_FRICTION_SLICK;
+ else
+ realfriction = PHYS_FRICTION;
+
+ f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED) ? (PHYS_STOPSPEED / f) : 1);
+ f = max(0, f);
+ self.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 / v0) * PHYS_FRICTION)
+ = v0 - PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION
+ v0 = v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION
+ and
+ v = v0 * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
+ v0 = v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
+
+ These cases would be chosen ONLY if:
+ v0 < PHYS_STOPSPEED
+ v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION < PHYS_STOPSPEED
+ v < PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
+ and, respectively:
+ v0 >= PHYS_STOPSPEED
+ v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) >= PHYS_STOPSPEED
+ v >= PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
+ */
+ }
+ float addspeed = wishspeed - self.velocity * wishdir;
+ if (addspeed > 0)
+ {
+ float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
+ self.velocity += accelspeed * wishdir;
+ }
+ float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
+ if (!(GAMEPLAYFIX_NOGRAVITYONGROUND))
+ self.velocity_z -= g * (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1);
+ if (self.velocity * self.velocity)
+ PM_ClientMovement_Move();
+ if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
+ if (!IS_ONGROUND(self) || !GAMEPLAYFIX_NOGRAVITYONGROUND)
+ self.velocity_z -= g * 0.5;
+}
+
+void PM_air(float buttons_prev, float maxspd_mod)
+{
+ makevectors(self.v_angle.y * '0 1 0');
+ vector wishvel = v_forward * self.movement.x
+ + v_right * self.movement.y;
+ // acceleration
+ vector wishdir = normalize(wishvel);
+ float wishspeed = vlen(wishvel);
+
+#ifdef SVQC
+ if (time >= self.teleport_time)
+#else
+ if (pmove_waterjumptime <= 0)
+#endif
+ {
+ float maxairspd = PHYS_MAXAIRSPEED(self) * min(maxspd_mod, 1);
+
+ // apply air speed limit
+ float airaccelqw = PHYS_AIRACCEL_QW(self);
+ float wishspeed0 = wishspeed;
+ wishspeed = min(wishspeed, maxairspd);
+ if (IS_DUCKED(self))
+ wishspeed *= 0.5;
+ float airaccel = PHYS_AIRACCELERATE * min(maxspd_mod, 1);
+
+ float accelerating = (self.velocity * wishdir > 0);
+ float wishspeed2 = wishspeed;
+
+ // CPM: air control
+ if (PHYS_AIRSTOPACCELERATE)
+ {
+ vector curdir = normalize(vec2(self.velocity));
+ airaccel += (PHYS_AIRSTOPACCELERATE*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(self.movement, -90) + IsMoveInDirection(self.movement, +90); // if one is nonzero, other is always zero
+ if (PHYS_MAXAIRSTRAFESPEED)
+ wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED(self)*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED*maxspd_mod));
+ if (PHYS_AIRSTRAFEACCELERATE(self))
+ airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE(self)*maxspd_mod);
+ if (PHYS_AIRSTRAFEACCEL_QW(self))
+ airaccelqw =
+ (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(self) : PHYS_AIRACCEL_QW(self)) >= 0) ? +1 : -1)
+ *
+ (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(self)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(self))));
+ // !CPM
+
+ if (PHYS_WARSOWBUNNY_TURNACCEL && accelerating && self.movement.y == 0 && self.movement.x != 0)
+ PM_AirAccelerate(wishdir, wishspeed2);
+ else
+ PM_Accelerate(wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, PHYS_AIRACCEL_QW_STRETCHFACTOR(self), PHYS_AIRACCEL_SIDEWAYS_FRICTION / maxairspd, PHYS_AIRSPEEDLIMIT_NONQW(self));
+
+ if (PHYS_AIRCONTROL)
+ CPM_PM_Aircontrol(wishdir, wishspeed2);
+ }
+ float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
+ if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
+ self.velocity_z -= g * 0.5;
+ else
+ self.velocity_z -= g;
+ PM_ClientMovement_Move();
+ if (!IS_ONGROUND(self) || !(GAMEPLAYFIX_NOGRAVITYONGROUND))
+ if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
+ self.velocity_z -= g * 0.5;
+}
+
+// used for calculating airshots
+bool IsFlying(entity a)
+{
+ if(IS_ONGROUND(a))
+ return false;
+ if(a.waterlevel >= WATERLEVEL_SWIMMING)
+ return false;
+ traceline(a.origin, a.origin - '0 0 48', MOVE_NORMAL, a);
+ if(trace_fraction < 1)
+ return false;
+ return true;
+}
+
+void PM_Main()
+{
+ int buttons = PHYS_INPUT_BUTTON_MASK(self);
+#ifdef CSQC
+ self.items = getstati(STAT_ITEMS, 0, 24);
+
+ self.movement = PHYS_INPUT_MOVEVALUES(self);
+
+ vector oldv_angle = self.v_angle;
+ vector oldangles = self.angles; // we need to save these, as they're abused by other code
+ self.v_angle = PHYS_INPUT_ANGLES(self);
+ self.angles = PHYS_WORLD_ANGLES(self);
+
+ self.team = myteam + 1; // is this correct?
+ if (!(PHYS_INPUT_BUTTON_JUMP(self))) // !jump
+ UNSET_JUMP_HELD(self); // canjump = true
+ pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH;
+
+ PM_ClientMovement_UpdateStatus(true);
+#endif
+
+
+#ifdef SVQC
+ WarpZone_PlayerPhysics_FixVAngle();
+#endif
+ float maxspeed_mod = 1;
+ maxspeed_mod *= PM_check_keepaway();
+ maxspeed_mod *= PHYS_HIGHSPEED;
+
+#ifdef SVQC
+ Physics_UpdateStats(maxspeed_mod);
+
+ if (self.PlayerPhysplug)
+ if (self.PlayerPhysplug())
+ return;
+#endif
+
+ PM_check_race_movetime();
+#ifdef SVQC
+ anticheat_physics();
+#endif
+
+ if (PM_check_specialcommand(buttons))
+ return;
+#ifdef SVQC
+ if (sv_maxidle > 0)
+ {
+ if (buttons != self.buttons_old || self.movement != self.movement_old || self.v_angle != self.v_angle_old)
+ self.parm_idlesince = time;
+ }
+#endif
+ int buttons_prev = self.buttons_old;
+ self.buttons_old = buttons;
+ self.movement_old = self.movement;
+ self.v_angle_old = self.v_angle;
+
+ PM_check_nickspam();
+
+ PM_check_punch();
+#ifdef SVQC
+ if (IS_BOT_CLIENT(self))
+ {
+ if (playerdemo_read())
+ return;
+ bot_think();
+ }
+
+ if (IS_PLAYER(self))
+#endif
+ {
+#ifdef SVQC
+ if (self.race_penalty)
+ if (time > self.race_penalty)
+ self.race_penalty = 0;
+#endif
+
+ bool not_allowed_to_move = false;
+#ifdef SVQC
+ if (self.race_penalty)
+ not_allowed_to_move = true;
+#endif
+#ifdef SVQC
+ if (time < game_starttime)
+ not_allowed_to_move = true;
+#endif
+
+ if (not_allowed_to_move)
+ {
+ self.velocity = '0 0 0';
+ self.movetype = MOVETYPE_NONE;
+#ifdef SVQC
+ self.disableclientprediction = 2;
+#endif
+ }
+#ifdef SVQC
+ else if (self.disableclientprediction == 2)
+ {
+ if (self.movetype == MOVETYPE_NONE)
+ self.movetype = MOVETYPE_WALK;
+ self.disableclientprediction = 0;
+ }
+#endif
+ }
+
+#ifdef SVQC
+ if (self.movetype == MOVETYPE_NONE)
+ return;
+
+ // when we get here, disableclientprediction cannot be 2
+ self.disableclientprediction = 0;
+#endif
+
+ PM_check_spider();
+
+ PM_check_frozen();
+
+ PM_check_blocked();
+
+ maxspeed_mod = 1;
+
+ if (self.in_swamp)
+ maxspeed_mod *= self.swamp_slowdown; //cvar("g_balance_swamp_moverate");
+
+ // conveyors: first fix velocity
+ if (self.conveyor.state)
+ self.velocity -= self.conveyor.movedir;
+
+#ifdef SVQC
+ MUTATOR_CALLHOOK(PlayerPhysics);
+#endif
+#ifdef CSQC
+ PM_multijump();
+#endif
+
+// float forcedodge = 1;
+// if(forcedodge) {
+//#ifdef CSQC
+// PM_dodging_checkpressedkeys();
+//#endif
+// PM_dodging();
+// PM_ClientMovement_Move();
+// return;
+// }
+
+#ifdef SVQC
+ if (!IS_PLAYER(self))
+ {
+ maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
+ if (!self.spectatorspeed)
+ self.spectatorspeed = maxspeed_mod;
+ if (self.impulse && self.impulse <= 19 || (self.impulse >= 200 && self.impulse <= 209) || (self.impulse >= 220 && self.impulse <= 229))
+ {
+ if (self.lastclassname != "player")
+ {
+ if (self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || (self.impulse >= 200 && self.impulse <= 209))
+ self.spectatorspeed = bound(1, self.spectatorspeed + 0.5, 5);
+ else if (self.impulse == 11)
+ self.spectatorspeed = maxspeed_mod;
+ else if (self.impulse == 12 || self.impulse == 16 || self.impulse == 19 || (self.impulse >= 220 && self.impulse <= 229))
+ self.spectatorspeed = bound(1, self.spectatorspeed - 0.5, 5);
+ else if (self.impulse >= 1 && self.impulse <= 9)
+ self.spectatorspeed = 1 + 0.5 * (self.impulse - 1);
+ } // otherwise just clear
+ self.impulse = 0;
+ }
+ maxspeed_mod = self.spectatorspeed;
+ }
+
+ float spd = max(PHYS_MAXSPEED(self), PHYS_MAXAIRSPEED(self)) * maxspeed_mod;
+ if(self.speed != spd)
+ {
+ self.speed = spd;
+ string temps = ftos(spd);
+ stuffcmd(self, strcat("cl_forwardspeed ", temps, "\n"));
+ stuffcmd(self, strcat("cl_backspeed ", temps, "\n"));
+ stuffcmd(self, strcat("cl_sidespeed ", temps, "\n"));
+ stuffcmd(self, strcat("cl_upspeed ", temps, "\n"));
+ }
+#endif
+
+ if(PHYS_DEAD(self))
+ {
+ // handle water here
+ vector midpoint = ((self.absmin + self.absmax) * 0.5);
+ if(pointcontents(midpoint) == CONTENT_WATER)
+ {
+ self.velocity = self.velocity * 0.5;
+
+ // do we want this?
+ //if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
+ //{ self.velocity_z = 70; }
+ }
+ goto end;
+ }
+
+#ifdef SVQC
+ if (!self.fixangle && !g_bugrigs)
+ self.angles = '0 1 0' * self.v_angle.y;
+#endif
+
+ PM_check_hitground();
+
+ if(IsFlying(self))
+ self.wasFlying = 1;
+
+ if (IS_PLAYER(self))
+ CheckPlayerJump();
+
+ if (self.flags & FL_WATERJUMP)
+ {
+ self.velocity_x = self.movedir_x;
+ self.velocity_y = self.movedir_y;
+ if (time > self.teleport_time || self.waterlevel == WATERLEVEL_NONE)
+ {
+ self.flags &= ~FL_WATERJUMP;
+ self.teleport_time = 0;
+ }
+ }
+
+#ifdef SVQC
+ else if (g_bugrigs && IS_PLAYER(self))
+ RaceCarPhysics();
+#endif
+
+ else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS(self) & BUFF_FLIGHT))
+ PM_fly(maxspeed_mod);
+
+ else if (self.waterlevel >= WATERLEVEL_SWIMMING)
+ PM_swim(maxspeed_mod);
+
+ else if (time < self.ladder_time)
+ PM_ladder(maxspeed_mod);
+
+ else if (ITEMS_STAT(self) & IT_USING_JETPACK)
+ PM_jetpack(maxspeed_mod);
+
+ else if (IS_ONGROUND(self))
+ PM_walk(buttons_prev, maxspeed_mod);
+
+ else
+ PM_air(buttons_prev, maxspeed_mod);
+
+#ifdef SVQC
+ if (!IS_OBSERVER(self))
+ PM_check_race();
+#endif
+ PM_check_vortex();
+
+:end
+ if (IS_ONGROUND(self))
+ self.lastground = time;
+
+ // conveyors: then break velocity again
+ if(self.conveyor.state)
+ self.velocity += self.conveyor.movedir;
+
+ self.lastflags = self.flags;
+
+ self.lastclassname = self.classname;
+
+#ifdef CSQC
+ self.v_angle = oldv_angle;
+ self.angles = oldangles;
+#endif
+}
+
+#ifdef SVQC
+void SV_PlayerPhysics(void)
+#elif defined(CSQC)
+void CSQC_ClientMovement_PlayerMove_Frame(void)
+#endif
+{
+ PM_Main();
+
+#ifdef CSQC
+ self.pmove_flags =
+ ((self.flags & FL_DUCKED) ? PMF_DUCKED : 0) |
+ (!(self.flags & FL_JUMPRELEASED) ? 0 : PMF_JUMP_HELD) |
+ ((self.flags & FL_ONGROUND) ? PMF_ONGROUND : 0);
+#endif
+}
--- /dev/null
+#ifndef COMMON_PHYSICS_H
+#define COMMON_PHYSICS_H
+
+// Client/server mappings
+
+.entity conveyor;
+
+.float race_penalty;
+
+.float gravity;
+.float swamp_slowdown;
+.float lastflags;
+.float lastground;
+.float wasFlying;
+.float spectatorspeed;
+
+.vector movement_old;
+.float buttons_old;
+.vector v_angle_old;
+.string lastclassname;
+
+.float() PlayerPhysplug;
+float AdjustAirAccelQW(float accelqw, float factor);
+
+bool IsFlying(entity a);
+
+#ifdef CSQC
+
+ const int FL_WATERJUMP = 2048; // player jumping out of water
+ const int FL_JUMPRELEASED = 4096; // for jump debouncing
+
+ float PM_multijump_checkjump();
+ void PM_multijump();
+
+ .float watertype;
+ .int items;
+
+ .vector movement;
+ .vector v_angle;
+
+// TODO
+ #define IS_CLIENT(s) (s).isplayermodel
+ #define IS_PLAYER(s) (s).isplayermodel
+ #define isPushable(s) (s).isplayermodel
+
+ float player_multijump;
+ float player_jumpheight;
+
+ #define PHYS_INPUT_ANGLES(s) input_angles
+// TODO
+ #define PHYS_WORLD_ANGLES(s) input_angles
+
+ #define PHYS_INPUT_TIMELENGTH input_timelength
+ #define PHYS_INPUT_FRAMETIME serverdeltatime
+
+ #define PHYS_INPUT_MOVEVALUES(s) input_movevalues
+
+ #define PHYS_INPUT_BUTTON_MASK(s) (input_buttons | 128 * (input_movevalues_x < 0) | 256 * (input_movevalues_x > 0) | 512 * (input_movevalues_y < 0) | 1024 * (input_movevalues_y > 0))
+ #define PHYS_INPUT_BUTTON_ATCK(s) !!(input_buttons & 1)
+ #define PHYS_INPUT_BUTTON_JUMP(s) !!(input_buttons & 2)
+ #define PHYS_INPUT_BUTTON_ATCK2(s) !!(input_buttons & 4)
+ #define PHYS_INPUT_BUTTON_ZOOM(s) !!(input_buttons & 8)
+ #define PHYS_INPUT_BUTTON_CROUCH(s) !!(input_buttons & 16)
+ #define PHYS_INPUT_BUTTON_HOOK(s) !!(input_buttons & 32)
+ #define PHYS_INPUT_BUTTON_USE(s) !!(input_buttons & 64)
+ #define PHYS_INPUT_BUTTON_BACKWARD(s) !!(input_buttons & 128)
+ #define PHYS_INPUT_BUTTON_FORWARD(s) !!(input_buttons & 256)
+ #define PHYS_INPUT_BUTTON_LEFT(s) !!(input_buttons & 512)
+ #define PHYS_INPUT_BUTTON_RIGHT(s) !!(input_buttons & 1024)
+ #define PHYS_INPUT_BUTTON_JETPACK(s) !!(input_buttons & 4096)
+
+ #define PHYS_DEAD(s) s.csqcmodel_isdead
+
+ #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE !!(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
+ #define GAMEPLAYFIX_NOGRAVITYONGROUND cvar("sv_gameplayfix_nogravityonground")
+ #define GAMEPLAYFIX_Q2AIRACCELERATE cvar("sv_gameplayfix_q2airaccelerate")
+ #define GAMEPLAYFIX_EASIERWATERJUMP getstati(STAT_GAMEPLAYFIX_EASIERWATERJUMP)
+ #define GAMEPLAYFIX_DOWNTRACEONGROUND getstati(STAT_GAMEPLAYFIX_DOWNTRACEONGROUND)
+ #define GAMEPLAYFIX_STEPMULTIPLETIMES getstati(STAT_GAMEPLAYFIX_STEPMULTIPLETIMES)
+ #define GAMEPLAYFIX_UNSTICKPLAYERS getstati(STAT_GAMEPLAYFIX_UNSTICKPLAYERS)
+ #define GAMEPLAYFIX_STEPDOWN getstati(STAT_GAMEPLAYFIX_STEPDOWN)
+
+ #define IS_DUCKED(s) !!(s.flags & FL_DUCKED)
+ #define SET_DUCKED(s) s.flags |= FL_DUCKED
+ #define UNSET_DUCKED(s) s.flags &= ~FL_DUCKED
+
+ #define IS_JUMP_HELD(s) !(s.flags & FL_JUMPRELEASED)
+ #define SET_JUMP_HELD(s) s.flags &= ~FL_JUMPRELEASED
+ #define UNSET_JUMP_HELD(s) s.flags |= FL_JUMPRELEASED
+
+ #define IS_ONGROUND(s) !!(s.flags & FL_ONGROUND)
+ #define SET_ONGROUND(s) s.flags |= FL_ONGROUND
+ #define UNSET_ONGROUND(s) s.flags &= ~FL_ONGROUND
+
+ #define WAS_ONGROUND(s) !!(s.lastflags & FL_ONGROUND)
+
+ #define ITEMS_STAT(s) (s).items
+ #define BUFFS(s) getstati(STAT_BUFFS)
+
+ #define PHYS_AMMO_FUEL(s) getstati(STAT_FUEL)
+
+ #define PHYS_FROZEN(s) getstati(STAT_FROZEN)
+
+ #define PHYS_DOUBLEJUMP getstati(STAT_DOUBLEJUMP)
+
+ #define PHYS_BUGRIGS getstati(STAT_BUGRIGS)
+ #define PHYS_BUGRIGS_ANGLE_SMOOTHING getstati(STAT_BUGRIGS_ANGLE_SMOOTHING)
+ #define PHYS_BUGRIGS_PLANAR_MOVEMENT getstati(STAT_BUGRIGS_PLANAR_MOVEMENT)
+ #define PHYS_BUGRIGS_REVERSE_SPEEDING getstati(STAT_BUGRIGS_REVERSE_SPEEDING)
+ #define PHYS_BUGRIGS_FRICTION_FLOOR getstatf(STAT_BUGRIGS_FRICTION_FLOOR)
+ #define PHYS_BUGRIGS_AIR_STEERING getstati(STAT_BUGRIGS_AIR_STEERING)
+ #define PHYS_BUGRIGS_FRICTION_BRAKE getstatf(STAT_BUGRIGS_FRICTION_BRAKE)
+ #define PHYS_BUGRIGS_ACCEL getstatf(STAT_BUGRIGS_ACCEL)
+ #define PHYS_BUGRIGS_SPEED_REF getstatf(STAT_BUGRIGS_SPEED_REF)
+ #define PHYS_BUGRIGS_SPEED_POW getstatf(STAT_BUGRIGS_SPEED_POW)
+ #define PHYS_BUGRIGS_STEER getstatf(STAT_BUGRIGS_STEER)
+ #define PHYS_BUGRIGS_FRICTION_AIR getstatf(STAT_BUGRIGS_FRICTION_AIR)
+ #define PHYS_BUGRIGS_CAR_JUMPING getstatf(STAT_BUGRIGS_CAR_JUMPING)
+ #define PHYS_BUGRIGS_REVERSE_SPINNING getstatf(STAT_BUGRIGS_REVERSE_SPINNING)
+ #define PHYS_BUGRIGS_REVERSE_STOPPING getstatf(STAT_BUGRIGS_REVERSE_STOPPING)
+
+ #define PHYS_JUMPSPEEDCAP_MIN getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MIN)
+ #define PHYS_JUMPSPEEDCAP_MAX getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MAX)
+ #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
+
+ #define PHYS_TRACK_CANJUMP(s) getstati(STAT_MOVEVARS_TRACK_CANJUMP)
+ #define PHYS_ACCELERATE getstatf(STAT_MOVEVARS_ACCELERATE)
+ #define PHYS_AIRACCEL_QW(s) getstatf(STAT_MOVEVARS_AIRACCEL_QW)
+ #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s) getstatf(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR)
+ #define PHYS_AIRACCEL_SIDEWAYS_FRICTION getstatf(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION)
+ #define PHYS_AIRACCELERATE getstatf(STAT_MOVEVARS_AIRACCELERATE)
+ #define PHYS_AIRCONTROL getstatf(STAT_MOVEVARS_AIRCONTROL)
+ #define PHYS_AIRCONTROL_PENALTY getstatf(STAT_MOVEVARS_AIRCONTROL_PENALTY)
+ #define PHYS_AIRCONTROL_POWER getstatf(STAT_MOVEVARS_AIRCONTROL_POWER)
+ #define PHYS_AIRSPEEDLIMIT_NONQW(s) getstatf(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW)
+ #define PHYS_AIRSTOPACCELERATE getstatf(STAT_MOVEVARS_AIRSTOPACCELERATE)
+ #define PHYS_AIRSTRAFEACCEL_QW(s) getstatf(STAT_MOVEVARS_AIRSTRAFEACCEL_QW)
+ #define PHYS_AIRSTRAFEACCELERATE(s) getstatf(STAT_MOVEVARS_AIRSTRAFEACCELERATE)
+ #define PHYS_ENTGRAVITY(s) getstatf(STAT_MOVEVARS_ENTGRAVITY)
+ #define PHYS_FRICTION getstatf(STAT_MOVEVARS_FRICTION)
+ #define PHYS_FRICTION_SLICK getstatf(STAT_MOVEVARS_FRICTION_SLICK)
+ #define PHYS_FRICTION_ONLAND getstatf(STAT_MOVEVARS_FRICTION_ONLAND)
+ #define PHYS_GRAVITY getstatf(STAT_MOVEVARS_GRAVITY)
+ #define PHYS_HIGHSPEED getstatf(STAT_MOVEVARS_HIGHSPEED)
+ #define PHYS_JUMPVELOCITY getstatf(STAT_MOVEVARS_JUMPVELOCITY)
+ #define PHYS_MAXAIRSPEED(s) getstatf(STAT_MOVEVARS_MAXAIRSPEED)
+ #define PHYS_MAXAIRSTRAFESPEED getstatf(STAT_MOVEVARS_MAXAIRSTRAFESPEED)
+ #define PHYS_MAXSPEED(s) getstatf(STAT_MOVEVARS_MAXSPEED)
+ #define PHYS_STEPHEIGHT getstatf(STAT_MOVEVARS_STEPHEIGHT)
+ #define PHYS_STOPSPEED getstatf(STAT_MOVEVARS_STOPSPEED)
+ #define PHYS_WARSOWBUNNY_ACCEL getstatf(STAT_MOVEVARS_WARSOWBUNNY_ACCEL)
+ #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO getstatf(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO)
+ #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL getstatf(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL)
+ #define PHYS_WARSOWBUNNY_TOPSPEED getstatf(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED)
+ #define PHYS_WARSOWBUNNY_TURNACCEL getstatf(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL)
+
+ #define PHYS_WALLFRICTION getstati(STAT_MOVEVARS_WALLFRICTION)
+
+ #define PHYS_JETPACK_ACCEL_UP getstatf(STAT_JETPACK_ACCEL_UP)
+ #define PHYS_JETPACK_ACCEL_SIDE getstatf(STAT_JETPACK_ACCEL_SIDE)
+ #define PHYS_JETPACK_ANTIGRAVITY getstatf(STAT_JETPACK_ANTIGRAVITY)
+ #define PHYS_JETPACK_FUEL getstatf(STAT_JETPACK_FUEL)
+ #define PHYS_JETPACK_MAXSPEED_UP getstatf(STAT_JETPACK_MAXSPEED_UP)
+ #define PHYS_JETPACK_MAXSPEED_SIDE getstatf(STAT_JETPACK_MAXSPEED_SIDE)
+
+ #define PHYS_DODGING_FROZEN getstati(STAT_DODGING_FROZEN)
+
+ #define PHYS_NOSTEP getstati(STAT_NOSTEP)
+ #define PHYS_JUMPSTEP getstati(STAT_MOVEVARS_JUMPSTEP)
+
+#elif defined(SVQC)
+
+ bool Physics_Valid(string thecvar);
+
+ .vector stat_pl_view_ofs;
+ .vector stat_pl_crouch_view_ofs;
+
+ .vector stat_pl_min;
+ .vector stat_pl_max;
+ .vector stat_pl_crouch_min;
+ .vector stat_pl_crouch_max;
+
+ .float stat_sv_airaccel_qw;
+ .float stat_sv_airstrafeaccel_qw;
+ .float stat_sv_airspeedlimit_nonqw;
+ .float stat_sv_maxspeed;
+ .float stat_movement_highspeed;
+
+ .float stat_sv_friction_on_land;
+ .float stat_sv_friction_slick;
+
+ .float stat_doublejump;
+
+ .float stat_jumpspeedcap_min;
+ .float stat_jumpspeedcap_max;
+ .float stat_jumpspeedcap_disable_onramps;
+
+ .float stat_jetpack_accel_side;
+ .float stat_jetpack_accel_up;
+ .float stat_jetpack_antigravity;
+ .float stat_jetpack_fuel;
+ .float stat_jetpack_maxspeed_up;
+ .float stat_jetpack_maxspeed_side;
+ .float stat_gameplayfix_easierwaterjump;
+ .float stat_gameplayfix_downtracesupportsongroundflag;
+ .float stat_gameplayfix_stepmultipletimes;
+ .float stat_gameplayfix_unstickplayers;
+ .float stat_gameplayfix_stepdown;
+
+ .float stat_bugrigs;
+ .float stat_bugrigs_angle_smoothing;
+ .float stat_bugrigs_planar_movement;
+ .float stat_bugrigs_reverse_speeding;
+ .float stat_bugrigs_friction_floor;
+ .float stat_bugrigs_air_steering;
+ .float stat_bugrigs_friction_brake;
+ .float stat_bugrigs_accel;
+ .float stat_bugrigs_speed_ref;
+ .float stat_bugrigs_speed_pow;
+ .float stat_bugrigs_steer;
+ .float stat_bugrigs_friction_air;
+ .float stat_bugrigs_car_jumping;
+ .float stat_bugrigs_reverse_spinning;
+ .float stat_bugrigs_reverse_stopping;
+
+ // new properties
+ .float stat_sv_jumpvelocity;
+ .float stat_sv_airaccel_qw_stretchfactor;
+ .float stat_sv_maxairstrafespeed;
+ .float stat_sv_maxairspeed;
+ .float stat_sv_airstrafeaccelerate;
+ .float stat_sv_warsowbunny_turnaccel;
+ .float stat_sv_airaccel_sideways_friction;
+ .float stat_sv_aircontrol;
+ .float stat_sv_aircontrol_power;
+ .float stat_sv_aircontrol_penalty;
+ .float stat_sv_warsowbunny_airforwardaccel;
+ .float stat_sv_warsowbunny_topspeed;
+ .float stat_sv_warsowbunny_accel;
+ .float stat_sv_warsowbunny_backtosideratio;
+ .float stat_sv_friction;
+ .float stat_sv_accelerate;
+ .float stat_sv_stopspeed;
+ .float stat_sv_airaccelerate;
+ .float stat_sv_airstopaccelerate;
+
+ .float stat_nostep;
+ .float stat_jumpstep;
+
+ #define PHYS_INPUT_ANGLES(s) s.v_angle
+ #define PHYS_WORLD_ANGLES(s) s.angles
+
+ #define PHYS_INPUT_TIMELENGTH frametime
+ #define PHYS_INPUT_FRAMETIME sys_frametime
+
+ #define PHYS_INPUT_MOVEVALUES(s) s.movement
+ // TODO: cache
+ #define PHYS_INPUT_BUTTON_MASK(s) (s.BUTTON_ATCK | 2 * s.BUTTON_JUMP | 4 * s.BUTTON_ATCK2 | 8 * s.BUTTON_ZOOM | 16 * s.BUTTON_CROUCH | 32 * s.BUTTON_HOOK | 64 * s.BUTTON_USE | 128 * (s.movement_x < 0) | 256 * (s.movement_x > 0) | 512 * (s.movement_y < 0) | 1024 * (s.movement_y > 0))
+ #define PHYS_INPUT_BUTTON_ATCK(s) s.BUTTON_ATCK
+ #define PHYS_INPUT_BUTTON_JUMP(s) s.BUTTON_JUMP
+ #define PHYS_INPUT_BUTTON_ATCK2(s) s.BUTTON_ATCK2
+ #define PHYS_INPUT_BUTTON_ZOOM(s) s.BUTTON_ZOOM
+ #define PHYS_INPUT_BUTTON_CROUCH(s) s.BUTTON_CROUCH
+ #define PHYS_INPUT_BUTTON_HOOK(s) s.BUTTON_HOOK
+ #define PHYS_INPUT_BUTTON_USE(s) s.BUTTON_USE
+ #define PHYS_INPUT_BUTTON_BACKWARD(s) (s.movement_x < 0)
+ #define PHYS_INPUT_BUTTON_FORWARD(s) (s.movement_x > 0)
+ #define PHYS_INPUT_BUTTON_LEFT(s) (s.movement_y < 0)
+ #define PHYS_INPUT_BUTTON_RIGHT(s) (s.movement_y > 0)
+ #define PHYS_INPUT_BUTTON_JETPACK(s) s.BUTTON_JETPACK
+
+ #define PHYS_DEAD(s) s.deadflag != DEAD_NO
+
+ #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE autocvar_sv_gameplayfix_gravityunaffectedbyticrate
+ #define GAMEPLAYFIX_NOGRAVITYONGROUND cvar("sv_gameplayfix_nogravityonground")
+ #define GAMEPLAYFIX_Q2AIRACCELERATE autocvar_sv_gameplayfix_q2airaccelerate
+ #define GAMEPLAYFIX_EASIERWATERJUMP cvar("sv_gameplayfix_easierwaterjump")
+ #define GAMEPLAYFIX_DOWNTRACEONGROUND cvar("sv_gameplayfix_downtracesupportsongroundflag")
+ #define GAMEPLAYFIX_STEPMULTIPLETIMES cvar("sv_gameplayfix_stepmultipletimes")
+ #define GAMEPLAYFIX_UNSTICKPLAYERS cvar("sv_gameplayfix_unstickplayers")
+ #define GAMEPLAYFIX_STEPDOWN cvar("sv_gameplayfix_stepdown")
+
+ #define IS_DUCKED(s) s.crouch
+ #define SET_DUCKED(s) s.crouch = true
+ #define UNSET_DUCKED(s) s.crouch = false
+
+ #define IS_JUMP_HELD(s) !(s.flags & FL_JUMPRELEASED)
+ #define SET_JUMP_HELD(s) s.flags &= ~FL_JUMPRELEASED
+ #define UNSET_JUMP_HELD(s) s.flags |= FL_JUMPRELEASED
+
+ #define IS_ONGROUND(s) !!(s.flags & FL_ONGROUND)
+ #define SET_ONGROUND(s) s.flags |= FL_ONGROUND
+ #define UNSET_ONGROUND(s) s.flags &= ~FL_ONGROUND
+
+ #define WAS_ONGROUND(s) !!((s).lastflags & FL_ONGROUND)
+
+ #define ITEMS_STAT(s) s.items
+ #define BUFFS(s) (s).buffs
+
+ #define PHYS_AMMO_FUEL(s) s.ammo_fuel
+
+ #define PHYS_FROZEN(s) s.frozen
+
+ #define PHYS_DOUBLEJUMP autocvar_sv_doublejump
+
+ #define PHYS_BUGRIGS g_bugrigs
+ #define PHYS_BUGRIGS_ANGLE_SMOOTHING g_bugrigs_angle_smoothing
+ #define PHYS_BUGRIGS_PLANAR_MOVEMENT g_bugrigs_planar_movement
+ #define PHYS_BUGRIGS_REVERSE_SPEEDING g_bugrigs_reverse_speeding
+ #define PHYS_BUGRIGS_FRICTION_FLOOR g_bugrigs_friction_floor
+ #define PHYS_BUGRIGS_AIR_STEERING g_bugrigs_air_steering
+ #define PHYS_BUGRIGS_FRICTION_BRAKE g_bugrigs_friction_brake
+ #define PHYS_BUGRIGS_ACCEL g_bugrigs_accel
+ #define PHYS_BUGRIGS_SPEED_REF g_bugrigs_speed_ref
+ #define PHYS_BUGRIGS_SPEED_POW g_bugrigs_speed_pow
+ #define PHYS_BUGRIGS_STEER g_bugrigs_steer
+ #define PHYS_BUGRIGS_FRICTION_AIR g_bugrigs_friction_air
+ #define PHYS_BUGRIGS_CAR_JUMPING g_bugrigs_planar_movement_car_jumping
+ #define PHYS_BUGRIGS_REVERSE_SPINNING g_bugrigs_reverse_spinning
+ #define PHYS_BUGRIGS_REVERSE_STOPPING g_bugrigs_reverse_stopping
+
+ #define PHYS_JUMPSPEEDCAP_MIN autocvar_sv_jumpspeedcap_min
+ #define PHYS_JUMPSPEEDCAP_MAX autocvar_sv_jumpspeedcap_max
+ #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS autocvar_sv_jumpspeedcap_max_disable_on_ramps
+
+ #define PHYS_TRACK_CANJUMP(s) s.cvar_cl_movement_track_canjump
+ #define PHYS_ACCELERATE self.stat_sv_accelerate
+ #define PHYS_AIRACCEL_QW(s) s.stat_sv_airaccel_qw
+ #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s) self.stat_sv_airaccel_qw_stretchfactor
+ #define PHYS_AIRACCEL_SIDEWAYS_FRICTION self.stat_sv_airaccel_sideways_friction
+ #define PHYS_AIRACCELERATE self.stat_sv_airaccelerate
+ #define PHYS_AIRCONTROL self.stat_sv_aircontrol
+ #define PHYS_AIRCONTROL_PENALTY self.stat_sv_aircontrol_penalty
+ #define PHYS_AIRCONTROL_POWER self.stat_sv_aircontrol_power
+ #define PHYS_AIRSPEEDLIMIT_NONQW(s) s.stat_sv_airspeedlimit_nonqw
+ #define PHYS_AIRSTOPACCELERATE self.stat_sv_airstopaccelerate
+ #define PHYS_AIRSTRAFEACCEL_QW(s) s.stat_sv_airstrafeaccel_qw
+ #define PHYS_AIRSTRAFEACCELERATE(s) s.stat_sv_airstrafeaccelerate
+ #define PHYS_ENTGRAVITY(s) s.gravity
+ #define PHYS_FRICTION self.stat_sv_friction
+ #define PHYS_FRICTION_SLICK autocvar_sv_friction_slick
+ #define PHYS_FRICTION_ONLAND autocvar_sv_friction_on_land
+ #define PHYS_GRAVITY autocvar_sv_gravity
+ #define PHYS_HIGHSPEED autocvar_g_movement_highspeed
+ #define PHYS_JUMPVELOCITY self.stat_sv_jumpvelocity
+ #define PHYS_MAXAIRSPEED(s) self.stat_sv_maxairspeed
+ #define PHYS_MAXAIRSTRAFESPEED self.stat_sv_maxairstrafespeed
+ #define PHYS_MAXSPEED(s) s.stat_sv_maxspeed
+ #define PHYS_STEPHEIGHT autocvar_sv_stepheight
+ #define PHYS_STOPSPEED self.stat_sv_stopspeed
+ #define PHYS_WARSOWBUNNY_ACCEL self.stat_sv_warsowbunny_accel
+ #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO self.stat_sv_warsowbunny_backtosideratio
+ #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL self.stat_sv_warsowbunny_airforwardaccel
+ #define PHYS_WARSOWBUNNY_TOPSPEED self.stat_sv_warsowbunny_topspeed
+ #define PHYS_WARSOWBUNNY_TURNACCEL self.stat_sv_warsowbunny_turnaccel
+
+ #define PHYS_WALLFRICTION cvar("sv_wallfriction")
+
+ #define PHYS_JETPACK_ACCEL_UP autocvar_g_jetpack_acceleration_up
+ #define PHYS_JETPACK_ACCEL_SIDE autocvar_g_jetpack_acceleration_side
+ #define PHYS_JETPACK_ANTIGRAVITY autocvar_g_jetpack_antigravity
+ #define PHYS_JETPACK_FUEL autocvar_g_jetpack_fuel
+ #define PHYS_JETPACK_MAXSPEED_UP autocvar_g_jetpack_maxspeed_up
+ #define PHYS_JETPACK_MAXSPEED_SIDE autocvar_g_jetpack_maxspeed_side
+
+ #define PHYS_DODGING_FROZEN autocvar_sv_dodging_frozen
+
+ #define PHYS_NOSTEP cvar("sv_nostep")
+ #define PHYS_JUMPSTEP cvar("sv_jumpstep")
+
+#endif
+#endif
#include "constants.qh"
#include "util.qh"
#include "urllib.qh"
- #include "weapons/weapons.qh"
+ #include "weapons/all.qh"
#include "../server/weapons/accuracy.qh"
#include "../server/defs.qh"
#include "playerstats.qh"
// 255 is the current limit (MAX_CL_STATS - 1), engine will need to be modified if you wish to add more stats
const int MAX_CL_STATS = 256;
-const int STAT_HEALTH = 0;
+// -Wdouble-declaration
+// const int STAT_HEALTH = 0;
// 1 empty?
const int STAT_WEAPON = 2;
-const int STAT_AMMO = 3;
-const int STAT_ARMOR = 4;
-const int STAT_WEAPONFRAME = 5;
-const int STAT_SHELLS = 6;
-const int STAT_NAILS = 7;
-const int STAT_ROCKETS = 8;
-const int STAT_CELLS = 9;
-const int STAT_ACTIVEWEAPON = 10;
-const int STAT_TOTALSECRETS = 11;
-const int STAT_TOTALMONSTERS = 12;
-const int STAT_SECRETS = 13;
-const int STAT_MONSTERS = 14;
-const int STAT_ITEMS = 15;
-const int STAT_VIEWHEIGHT = 16;
+// -Wdouble-declaration
+// const int STAT_AMMO = 3;
+// -Wdouble-declaration
+// const int STAT_ARMOR = 4;
+// -Wdouble-declaration
+// const int STAT_WEAPONFRAME = 5;
+// -Wdouble-declaration
+// const int STAT_SHELLS = 6;
+// -Wdouble-declaration
+// const int STAT_NAILS = 7;
+// -Wdouble-declaration
+// const int STAT_ROCKETS = 8;
+// -Wdouble-declaration
+// const int STAT_CELLS = 9;
+// -Wdouble-declaration
+// const int STAT_ACTIVEWEAPON = 10;
+// -Wdouble-declaration
+// const int STAT_TOTALSECRETS = 11;
+// -Wdouble-declaration
+// const int STAT_TOTALMONSTERS = 12;
+// -Wdouble-declaration
+// const int STAT_SECRETS = 13;
+// -Wdouble-declaration
+// const int STAT_MONSTERS = 14;
+// -Wdouble-declaration
+// const int STAT_ITEMS = 15;
+// -Wdouble-declaration
+// const int STAT_VIEWHEIGHT = 16;
// 17 empty?
// 18 empty?
// 19 empty?
const int STAT_PLASMA = 84;
const int STAT_OK_AMMO_CHARGE = 85;
const int STAT_OK_AMMO_CHARGEPOOL = 86;
-const int STAT_BUFF_TIME = 87;
-// 88 empty?
-// 89 empty?
+const int STAT_FROZEN = 87;
+const int STAT_REVIVE_PROGRESS = 88;
+const int STAT_BUFF_TIME = 89;
// 90 empty?
// 91 empty?
// 92 empty?
/* Gamemode-specific stats end here */
-
-const int STAT_FROZEN = 105;
-const int STAT_REVIVE_PROGRESS = 106;
-// 107 empty?
-// 108 empty?
-// 109 empty?
-// 110 empty?
-// 111 empty?
-// 112 empty?
-// 113 empty?
-// 114 empty?
-// 115 empty?
-// 116 empty?
-// 117 empty?
-// 118 empty?
-// 119 empty?
+const int STAT_PL_VIEW_OFS1 = 105;
+const int STAT_PL_VIEW_OFS2 = 106;
+const int STAT_PL_VIEW_OFS3 = 107;
+const int STAT_PL_MIN1 = 108;
+const int STAT_PL_MIN2 = 109;
+const int STAT_PL_MIN3 = 110;
+const int STAT_PL_MAX1 = 111;
+const int STAT_PL_MAX2 = 112;
+const int STAT_PL_MAX3 = 113;
+const int STAT_PL_CROUCH_MIN1 = 114;
+const int STAT_PL_CROUCH_MIN2 = 115;
+const int STAT_PL_CROUCH_MIN3 = 116;
+const int STAT_PL_CROUCH_MAX1 = 117;
+const int STAT_PL_CROUCH_MAX2 = 118;
+const int STAT_PL_CROUCH_MAX3 = 119;
+const int STAT_PL_CROUCH_VIEW_OFS1 = 117;
+const int STAT_PL_CROUCH_VIEW_OFS2 = 118;
+const int STAT_PL_CROUCH_VIEW_OFS3 = 119;
// 120 empty?
// 121 empty?
// 122 empty?
// 165 empty?
// 166 empty?
// 167 empty?
-// 168 empty?
-// 169 empty?
-// 170 empty?
-// 171 empty?
-// 172 empty?
-// 173 empty?
-// 174 empty?
-// 175 empty?
-// 176 empty?
-// 177 empty?
-// 178 empty?
-// 179 empty?
-// 180 empty?
-// 181 empty?
-// 182 empty?
-// 183 empty?
-// 184 empty?
-// 185 empty?
-// 186 empty?
-// 187 empty?
-// 188 empty?
-// 189 empty?
-// 190 empty?
-// 191 empty?
-// 192 empty?
-// 193 empty?
-// 194 empty?
-// 195 empty?
-// 196 empty?
-// 197 empty?
-// 198 empty?
-// 199 empty?
-// 200 empty?
-// 201 empty?
-// 202 empty?
-// 203 empty?
-// 204 empty?
-// 205 empty?
-// 206 empty?
-// 207 empty?
-// 208 empty?
-// 209 empty?
-// 210 empty?
-// 211 empty?
-// 212 empty?
-// 213 empty?
-// 214 empty?
-// 215 empty?
-// 216 empty?
-// 217 empty?
-// 218 empty?
-// 219 empty?
+const int STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND = 168;
+const int STAT_BUGRIGS_REVERSE_STOPPING = 169;
+const int STAT_BUGRIGS_REVERSE_SPINNING = 170;
+const int STAT_BUGRIGS_CAR_JUMPING = 171;
+const int STAT_BUGRIGS_FRICTION_AIR = 172;
+const int STAT_BUGRIGS_STEER = 173;
+const int STAT_BUGRIGS_SPEED_POW = 174;
+const int STAT_BUGRIGS_SPEED_REF = 175;
+const int STAT_BUGRIGS_ACCEL = 176;
+const int STAT_BUGRIGS_FRICTION_BRAKE = 177;
+const int STAT_BUGRIGS_AIR_STEERING = 178;
+const int STAT_BUGRIGS_FRICTION_FLOOR = 179;
+const int STAT_BUGRIGS_REVERSE_SPEEDING = 180;
+const int STAT_BUGRIGS_PLANAR_MOVEMENT = 181;
+const int STAT_BUGRIGS_ANGLE_SMOOTHING = 182;
+const int STAT_BUGRIGS = 183;
+const int STAT_GAMEPLAYFIX_STEPDOWN = 184;
+const int STAT_MOVEVARS_JUMPSTEP = 185;
+const int STAT_NOSTEP = 186;
+const int STAT_GAMEPLAYFIX_UNSTICKPLAYERS = 187;
+const int STAT_GAMEPLAYFIX_STEPMULTIPLETIMES = 188;
+const int STAT_GAMEPLAYFIX_DOWNTRACEONGROUND = 189;
+const int STAT_GAMEPLAYFIX_EASIERWATERJUMP = 190;
+const int STAT_MOVEVARS_FRICTION_SLICK = 191;
+const int STAT_MOVEVARS_FRICTION_ONLAND = 192;
+const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS = 193;
+const int STAT_MOVEVARS_JUMPSPEEDCAP_MAX = 194;
+const int STAT_MOVEVARS_JUMPSPEEDCAP_MIN = 195;
+const int STAT_DOUBLEJUMP = 196;
+const int STAT_MOVEVARS_TRACK_CANJUMP = 197;
+const int STAT_MULTIJUMP_ADD = 198;
+const int STAT_MULTIJUMP_SPEED = 199;
+const int STAT_MULTIJUMP = 200;
+const int STAT_DODGING_TIMEOUT = 201;
+const int STAT_DODGING_WALL = 202;
+const int STAT_DODGING_UP_SPEED = 203;
+const int STAT_DODGING_RAMP_TIME = 204;
+const int STAT_DODGING_HEIGHT_THRESHOLD = 205;
+const int STAT_DODGING_DISTANCE_THRESHOLD = 206;
+const int STAT_DODGING_HORIZ_SPEED = 207;
+const int STAT_DODGING_DELAY = 208;
+const int STAT_DODGING_FROZEN_NO_DOUBLETAP = 209;
+const int STAT_DODGING_HORIZ_SPEED_FROZEN = 210;
+const int STAT_DODGING = 211;
+const int STAT_DODGING_FROZEN = 212;
+const int STAT_JETPACK_MAXSPEED_UP = 213;
+const int STAT_JETPACK_MAXSPEED_SIDE = 214;
+const int STAT_JETPACK_FUEL = 215;
+const int STAT_JETPACK_ANTIGRAVITY = 216;
+const int STAT_JETPACK_ACCEL_SIDE = 217;
+const int STAT_JETPACK_ACCEL_UP = 218;
+const int STAT_MOVEVARS_HIGHSPEED = 219;
const int STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220;
const int STAT_MOVEVARS_AIRCONTROL_PENALTY = 221;
const int STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222;
const int STAT_MOVEVARS_AIRSTRAFEACCELERATE = 232;
const int STAT_MOVEVARS_MAXAIRSTRAFESPEED = 233;
const int STAT_MOVEVARS_AIRCONTROL = 234;
-const int STAT_FRAGLIMIT = 235;
-const int STAT_TIMELIMIT = 236;
+// -Wdouble-declaration
+// const int STAT_FRAGLIMIT = 235;
+// -Wdouble-declaration
+// const int STAT_TIMELIMIT = 236;
const int STAT_MOVEVARS_WALLFRICTION = 237;
const int STAT_MOVEVARS_FRICTION = 238;
const int STAT_MOVEVARS_WATERFRICTION = 239;
-const int STAT_MOVEVARS_TICRATE = 240;
-const int STAT_MOVEVARS_TIMESCALE = 241;
-const int STAT_MOVEVARS_GRAVITY = 242;
+// -Wdouble-declaration
+// const int STAT_MOVEVARS_TICRATE = 240;
+// -Wdouble-declaration
+// const int STAT_MOVEVARS_TIMESCALE = 241;
+// -Wdouble-declaration
+// const int STAT_MOVEVARS_GRAVITY = 242;
const int STAT_MOVEVARS_STOPSPEED = 243;
const int STAT_MOVEVARS_MAXSPEED = 244;
const int STAT_MOVEVARS_SPECTATORMAXSPEED = 245;
--- /dev/null
+#ifdef SVQC
+.float height;
+void func_bobbing_controller_think()
+{
+ vector v;
+ self.nextthink = time + 0.1;
+
+ if(self.owner.active != ACTIVE_ACTIVE)
+ {
+ self.owner.velocity = '0 0 0';
+ return;
+ }
+
+ // calculate sinewave using makevectors
+ makevectors((self.nextthink * self.owner.cnt + self.owner.phase * 360) * '0 1 0');
+ v = self.owner.destvec + self.owner.movedir * v_forward_y;
+ if(self.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed
+ // * 10 so it will arrive in 0.1 sec
+ self.owner.velocity = (v - self.owner.SUB_ORIGIN) * 10;
+}
+
+/*QUAKED spawnfunc_func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
+Brush model that moves back and forth on one axis (default Z).
+speed : how long one cycle takes in seconds (default 4)
+height : how far the cycle moves (default 32)
+phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
+noise : path/name of looping .wav file to play.
+dmg : Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime : See above.
+*/
+void spawnfunc_func_bobbing()
+{
+ entity controller;
+ if (self.noise != "")
+ {
+ precache_sound(self.noise);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+ }
+ if (!self.speed)
+ self.speed = 4;
+ if (!self.height)
+ self.height = 32;
+ // center of bobbing motion
+ self.destvec = self.origin;
+ // time scale to get degrees
+ self.cnt = 360 / self.speed;
+
+ self.active = ACTIVE_ACTIVE;
+
+ // damage when blocked
+ self.blocked = generic_plat_blocked;
+ if(self.dmg && (self.message == ""))
+ self.message = " was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+ if(self.dmg && (!self.dmgtime))
+ self.dmgtime = 0.25;
+ self.dmgtime2 = time;
+
+ // how far to bob
+ if (self.spawnflags & 1) // X
+ self.movedir = '1 0 0' * self.height;
+ else if (self.spawnflags & 2) // Y
+ self.movedir = '0 1 0' * self.height;
+ else // Z
+ self.movedir = '0 0 1' * self.height;
+
+ if (!InitMovingBrushTrigger())
+ return;
+
+ // wait for targets to spawn
+ controller = spawn();
+ controller.classname = "func_bobbing_controller";
+ controller.owner = self;
+ controller.nextthink = time + 1;
+ controller.think = func_bobbing_controller_think;
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 999999999;
+ self.SUB_THINK = SUB_NullThink;
+
+ // Savage: Reduce bandwith, critical on e.g. nexdm02
+ self.effects |= EF_LOWPRECISION;
+
+ // TODO make a reset function for this one
+}
+#endif
--- /dev/null
+#ifdef SVQC
+
+#include "../../../server/_all.qh"
+
+#include "../../../server/g_subs.qh"
+#include "../../../server/waypointsprites.qh"
+#include "../../../server/g_damage.qh"
+#include "../../../server/bot/bot.qh"
+#include "../../common/csqcmodel_settings.qh"
+#include "../../../csqcmodellib/sv_model.qh"
+#include "../../../server/weapons/common.qh"
+
+.entity sprite;
+
+.float dmg;
+.float dmg_edge;
+.float dmg_radius;
+.float dmg_force;
+.float debrismovetype;
+.float debrissolid;
+.vector debrisvelocity;
+.vector debrisvelocityjitter;
+.vector debrisavelocityjitter;
+.float debristime;
+.float debristimejitter;
+.float debrisfadetime;
+.float debrisdamageforcescale;
+.float debrisskin;
+
+.string mdl_dead; // or "" to hide when broken
+.string debris; // space separated list of debris models
+// other fields:
+// mdl = particle effect name
+// count = particle effect multiplier
+// targetname = target to trigger to unbreak the model
+// target = targets to trigger when broken
+// health = amount of damage it can take
+// spawnflags:
+// 1 = start disabled (needs to be triggered to activate)
+// 2 = indicate damage
+// notes:
+// for mdl_dead to work, origin must be set (using a common/origin brush).
+// Otherwise mdl_dead will be displayed at the map origin, and nobody would
+// want that!
+
+void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+
+//
+// func_breakable
+// - basically func_assault_destructible for general gameplay use
+//
+void LaunchDebris (string debrisname, vector force)
+{
+ entity dbr = spawn();
+ setorigin(dbr, self.absmin
+ + '1 0 0' * random() * (self.absmax.x - self.absmin.x)
+ + '0 1 0' * random() * (self.absmax.y - self.absmin.y)
+ + '0 0 1' * random() * (self.absmax.z - self.absmin.z));
+ setmodel (dbr, debrisname );
+ dbr.skin = self.debrisskin;
+ dbr.colormap = self.colormap; // inherit team colors
+ dbr.owner = self; // do not be affected by our own explosion
+ dbr.movetype = self.debrismovetype;
+ dbr.solid = self.debrissolid;
+ if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
+ setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
+ dbr.velocity_x = self.debrisvelocity.x + self.debrisvelocityjitter.x * crandom();
+ dbr.velocity_y = self.debrisvelocity.y + self.debrisvelocityjitter.y * crandom();
+ dbr.velocity_z = self.debrisvelocity.z + self.debrisvelocityjitter.z * crandom();
+ self.velocity = self.velocity + force * self.debrisdamageforcescale;
+ dbr.avelocity_x = random()*self.debrisavelocityjitter.x;
+ dbr.avelocity_y = random()*self.debrisavelocityjitter.y;
+ dbr.avelocity_z = random()*self.debrisavelocityjitter.z;
+ dbr.damageforcescale = self.debrisdamageforcescale;
+ if(dbr.damageforcescale)
+ dbr.takedamage = DAMAGE_YES;
+ SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);
+}
+
+void func_breakable_colormod()
+{
+ float h;
+ if (!(self.spawnflags & 2))
+ return;
+ h = self.health / self.max_health;
+ if(h < 0.25)
+ self.colormod = '1 0 0';
+ else if(h <= 0.75)
+ self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
+ else
+ self.colormod = '1 1 1';
+
+ CSQCMODEL_AUTOUPDATE();
+}
+
+void func_breakable_look_destroyed()
+{
+ float floorZ;
+
+ if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
+ self.dropped_origin = self.origin;
+
+ if(self.mdl_dead == "")
+ self.effects |= EF_NODRAW;
+ else {
+ if (self.origin == '0 0 0') { // probably no origin brush, so don't spawn in the middle of the map..
+ floorZ = self.absmin.z;
+ setorigin(self,((self.absmax+self.absmin)*.5));
+ self.origin_z = floorZ;
+ }
+ setmodel(self, self.mdl_dead);
+ self.effects &= ~EF_NODRAW;
+ }
+
+ CSQCMODEL_AUTOUPDATE();
+
+ self.solid = SOLID_NOT;
+}
+
+void func_breakable_look_restore()
+{
+ setmodel(self, self.mdl);
+ self.effects &= ~EF_NODRAW;
+
+ if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
+ setorigin(self, self.dropped_origin);
+
+ CSQCMODEL_AUTOUPDATE();
+
+ self.solid = SOLID_BSP;
+}
+
+void func_breakable_behave_destroyed()
+{
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_NO;
+ self.bot_attack = false;
+ self.event_damage = func_null;
+ self.state = 1;
+ func_breakable_colormod();
+ if (self.noise1)
+ stopsound (self, CH_TRIGGER_SINGLE);
+}
+
+void func_breakable_behave_restore()
+{
+ self.health = self.max_health;
+ if(self.sprite)
+ {
+ WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+ }
+ self.takedamage = DAMAGE_AIM;
+ self.bot_attack = true;
+ self.event_damage = func_breakable_damage;
+ self.state = 0;
+ self.nextthink = 0; // cancel auto respawn
+ func_breakable_colormod();
+ if (self.noise1)
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+}
+
+void func_breakable_init_for_player(entity player)
+{
+ if (self.noise1 && self.state == 0 && clienttype(player) == CLIENTTYPE_REAL)
+ {
+ msg_entity = player;
+ soundto (MSG_ONE, self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ }
+}
+
+void func_breakable_destroyed()
+{
+ func_breakable_look_destroyed();
+ func_breakable_behave_destroyed();
+
+ CSQCMODEL_AUTOUPDATE();
+}
+
+void func_breakable_restore()
+{
+ func_breakable_look_restore();
+ func_breakable_behave_restore();
+
+ CSQCMODEL_AUTOUPDATE();
+}
+
+vector debrisforce; // global, set before calling this
+void func_breakable_destroy() {
+ float n, i;
+ string oldmsg;
+
+ activator = self.owner;
+ self.owner = world; // set by W_PrepareExplosionByDamage
+
+ // now throw around the debris
+ n = tokenize_console(self.debris);
+ for(i = 0; i < n; ++i)
+ LaunchDebris(argv(i), debrisforce);
+
+ func_breakable_destroyed();
+
+ if(self.noise)
+ sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+
+ if(self.dmg)
+ RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
+
+ if(self.cnt)
+ pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
+
+ if(self.respawntime)
+ {
+ self.think = func_breakable_restore;
+ self.nextthink = time + self.respawntime + crandom() * self.respawntimejitter;
+ }
+
+ oldmsg = self.message;
+ self.message = "";
+ SUB_UseTargets();
+ self.message = oldmsg;
+}
+
+void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ if(self.state == 1)
+ return;
+ if(self.spawnflags & DOOR_NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ if(self.team)
+ if(attacker.team == self.team)
+ return;
+ self.health = self.health - damage;
+ if(self.sprite)
+ {
+ WaypointSprite_Ping(self.sprite);
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+ }
+ func_breakable_colormod();
+
+ if(self.health <= 0)
+ {
+ debrisforce = force;
+ W_PrepareExplosionByDamage(attacker, func_breakable_destroy);
+ }
+}
+
+void func_breakable_reset()
+{
+ self.team = self.team_saved;
+ func_breakable_look_restore();
+ if(self.spawnflags & 1)
+ func_breakable_behave_destroyed();
+ else
+ func_breakable_behave_restore();
+
+ CSQCMODEL_AUTOUPDATE();
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+void spawnfunc_func_breakable()
+{
+ float n, i;
+ if(!self.health)
+ self.health = 100;
+ self.max_health = self.health;
+
+ // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
+ if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;
+ if(!self.debrissolid) self.debrissolid = SOLID_NOT;
+ if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';
+ if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';
+ if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';
+ if(!self.debristime) self.debristime = 3.5;
+ if(!self.debristimejitter) self.debristime = 2.5;
+
+ if(self.mdl != "")
+ self.cnt = particleeffectnum(self.mdl);
+ if(self.count == 0)
+ self.count = 1;
+
+ if(self.message == "")
+ self.message = "got too close to an explosion";
+ if(self.message2 == "")
+ self.message2 = "was pushed into an explosion by";
+ if(!self.dmg_radius)
+ self.dmg_radius = 150;
+ if(!self.dmg_force)
+ self.dmg_force = 200;
+
+ self.mdl = self.model;
+ SetBrushEntityModel();
+
+ self.use = func_breakable_restore;
+
+ // precache all the models
+ if (self.mdl_dead)
+ precache_model(self.mdl_dead);
+ n = tokenize_console(self.debris);
+ for(i = 0; i < n; ++i)
+ precache_model(argv(i));
+ if(self.noise)
+ precache_sound(self.noise);
+ if(self.noise1)
+ precache_sound(self.noise1);
+
+ self.team_saved = self.team;
+ self.dropped_origin = self.origin;
+
+ self.reset = func_breakable_reset;
+ func_breakable_reset();
+
+ self.init_for_player_needed = 1;
+ self.init_for_player = func_breakable_init_for_player;
+
+ CSQCMODEL_AUTOINIT();
+}
+
+// for use in maps with a "model" key set
+void spawnfunc_misc_breakablemodel() {
+ spawnfunc_func_breakable();
+}
+#endif
--- /dev/null
+#ifndef TRIGGERS_FUNC_BREAKABLE_H
+#define TRIGGERS_FUNC_BREAKABLE_H
+
+#ifdef SVQC
+void spawnfunc_func_breakable();
+#endif
+
+#endif
--- /dev/null
+#ifdef SVQC
+// button and multiple button
+
+void() button_wait;
+void() button_return;
+
+void button_wait()
+{
+ self.state = STATE_TOP;
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+ self.SUB_THINK = button_return;
+ activator = self.enemy;
+ SUB_UseTargets();
+ self.frame = 1; // use alternate textures
+}
+
+void button_done()
+{
+ self.state = STATE_BOTTOM;
+}
+
+void button_return()
+{
+ self.state = STATE_DOWN;
+ SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, button_done);
+ self.frame = 0; // use normal textures
+ if (self.health)
+ self.takedamage = DAMAGE_YES; // can be shot again
+}
+
+
+void button_blocked()
+{
+ // do nothing, just don't come all the way back out
+}
+
+
+void button_fire()
+{
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_NO; // will be reset upon return
+
+ if (self.state == STATE_UP || self.state == STATE_TOP)
+ return;
+
+ if (self.noise != "")
+ sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+
+ self.state = STATE_UP;
+ SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, button_wait);
+}
+
+void button_reset()
+{
+ self.health = self.max_health;
+ setorigin(self, self.pos1);
+ self.frame = 0; // use normal textures
+ self.state = STATE_BOTTOM;
+ if (self.health)
+ self.takedamage = DAMAGE_YES; // can be shot again
+}
+
+void button_use()
+{
+ if(self.active != ACTIVE_ACTIVE)
+ return;
+
+ self.enemy = activator;
+ button_fire ();
+}
+
+void button_touch()
+{
+ if (!other)
+ return;
+ if (!other.iscreature)
+ return;
+ if(other.velocity * self.movedir < 0)
+ return;
+ self.enemy = other;
+ if (other.owner)
+ self.enemy = other.owner;
+ button_fire ();
+}
+
+void button_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ if(self.spawnflags & DOOR_NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ self.health = self.health - damage;
+ if (self.health <= 0)
+ {
+ self.enemy = damage_attacker;
+ button_fire ();
+ }
+}
+
+
+/*QUAKED spawnfunc_func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle" determines the opening direction
+"target" all entities with a matching targetname will be used
+"speed" override the default 40 speed
+"wait" override the default 1 second wait (-1 = never return)
+"lip" override the default 4 pixel lip remaining at end of move
+"health" if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the InstaGib laser
+"sounds"
+0) steam metal
+1) wooden clunk
+2) metallic click
+3) in-out
+*/
+void spawnfunc_func_button()
+{
+ SetMovedir ();
+
+ if (!InitMovingBrushTrigger())
+ return;
+ self.effects |= EF_LOWPRECISION;
+
+ self.blocked = button_blocked;
+ self.use = button_use;
+
+// if (self.health == 0) // all buttons are now shootable
+// self.health = 10;
+ if (self.health)
+ {
+ self.max_health = self.health;
+ self.event_damage = button_damage;
+ self.takedamage = DAMAGE_YES;
+ }
+ else
+ self.touch = button_touch;
+
+ if (!self.speed)
+ self.speed = 40;
+ if (!self.wait)
+ self.wait = 1;
+ if (!self.lip)
+ self.lip = 4;
+
+ if(self.noise != "")
+ precache_sound(self.noise);
+
+ self.active = ACTIVE_ACTIVE;
+
+ self.pos1 = self.origin;
+ self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
+ self.flags |= FL_NOTARGET;
+
+ button_reset();
+}
+#endif
--- /dev/null
+void conveyor_think()
+{
+#ifdef CSQC
+ // TODO: check if this is what is causing the glitchiness when switching between them
+ float dt = time - self.move_time;
+ self.move_time = time;
+ if(dt <= 0) { return; }
+#endif
+ entity e;
+
+ // set myself as current conveyor where possible
+ for(e = world; (e = findentity(e, conveyor, self)); )
+ e.conveyor = world;
+
+ if(self.state)
+ {
+ for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
+ if(!e.conveyor.state)
+ if(isPushable(e))
+ {
+ vector emin = e.absmin;
+ vector emax = e.absmax;
+ if(self.solid == SOLID_BSP)
+ {
+ emin -= '1 1 1';
+ emax += '1 1 1';
+ }
+ if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
+ if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
+ e.conveyor = self;
+ }
+
+ for(e = world; (e = findentity(e, conveyor, self)); )
+ {
+ if(IS_CLIENT(e)) // doing it via velocity has quite some advantages
+ continue; // done in SV_PlayerPhysics continue;
+
+ setorigin(e, e.origin + self.movedir * PHYS_INPUT_FRAMETIME);
+ move_out_of_solid(e);
+#ifdef SVQC
+ UpdateCSQCProjectile(e);
+#endif
+ /*
+ // stupid conveyor code
+ tracebox(e.origin, e.mins, e.maxs, e.origin + self.movedir * sys_frametime, MOVE_NORMAL, e);
+ if(trace_fraction > 0)
+ setorigin(e, trace_endpos);
+ */
+ }
+ }
+
+#ifdef SVQC
+ self.nextthink = time;
+#endif
+}
+
+#ifdef SVQC
+
+void conveyor_use()
+{
+ self.state = !self.state;
+
+ self.SendFlags |= 2;
+}
+
+void conveyor_reset()
+{
+ self.state = (self.spawnflags & 1);
+
+ self.SendFlags |= 2;
+}
+
+bool conveyor_send(entity to, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & 1)
+ {
+ WriteByte(MSG_ENTITY, self.warpzone_isboxy);
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteCoord(MSG_ENTITY, self.mins_x);
+ WriteCoord(MSG_ENTITY, self.mins_y);
+ WriteCoord(MSG_ENTITY, self.mins_z);
+ WriteCoord(MSG_ENTITY, self.maxs_x);
+ WriteCoord(MSG_ENTITY, self.maxs_y);
+ WriteCoord(MSG_ENTITY, self.maxs_z);
+
+ WriteCoord(MSG_ENTITY, self.movedir_x);
+ WriteCoord(MSG_ENTITY, self.movedir_y);
+ WriteCoord(MSG_ENTITY, self.movedir_z);
+
+ WriteByte(MSG_ENTITY, self.speed);
+ WriteByte(MSG_ENTITY, self.state);
+
+ WriteString(MSG_ENTITY, self.targetname);
+ WriteString(MSG_ENTITY, self.target);
+ }
+
+ if(sf & 2)
+ WriteByte(MSG_ENTITY, self.state);
+
+ return true;
+}
+
+void conveyor_init()
+{
+ if (!self.speed)
+ self.speed = 200;
+ self.movedir = self.movedir * self.speed;
+ self.think = conveyor_think;
+ self.nextthink = time;
+ IFTARGETED
+ {
+ self.use = conveyor_use;
+ self.reset = conveyor_reset;
+ conveyor_reset();
+ }
+ else
+ self.state = 1;
+
+ FixSize(self);
+
+ Net_LinkEntity(self, 0, false, conveyor_send);
+
+ self.SendFlags |= 1;
+}
+
+void spawnfunc_trigger_conveyor()
+{
+ SetMovedir();
+ EXACTTRIGGER_INIT;
+ conveyor_init();
+}
+
+void spawnfunc_func_conveyor()
+{
+ SetMovedir();
+ InitMovingBrushTrigger();
+ self.movetype = MOVETYPE_NONE;
+ conveyor_init();
+}
+
+#elif defined(CSQC)
+
+void conveyor_init()
+{
+ self.draw = conveyor_think;
+ self.drawmask = MASK_NORMAL;
+
+ self.movetype = MOVETYPE_NONE;
+ self.model = "";
+ self.solid = SOLID_TRIGGER;
+ self.move_origin = self.origin;
+ self.move_time = time;
+}
+
+void ent_conveyor()
+{
+ float sf = ReadByte();
+
+ if(sf & 1)
+ {
+ self.warpzone_isboxy = ReadByte();
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+
+ self.mins_x = ReadCoord();
+ self.mins_y = ReadCoord();
+ self.mins_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ setsize(self, self.mins, self.maxs);
+
+ self.movedir_x = ReadCoord();
+ self.movedir_y = ReadCoord();
+ self.movedir_z = ReadCoord();
+
+ self.speed = ReadByte();
+ self.state = ReadByte();
+
+ self.targetname = strzone(ReadString());
+ self.target = strzone(ReadString());
+
+ conveyor_init();
+ }
+
+ if(sf & 2)
+ self.state = ReadByte();
+}
+#endif
--- /dev/null
+#ifdef CSQC
+void ent_conveyor();
+#endif
--- /dev/null
+/*
+
+Doors are similar to buttons, but can spawn a fat trigger field around them
+to open without a touch, and they link together to form simultanious
+double/quad doors.
+
+Door.owner is the master door. If there is only one door, it points to itself.
+If multiple doors, all will point to a single one.
+
+Door.enemy chains from the master door through all doors linked in the chain.
+
+*/
+
+
+/*
+=============================================================================
+
+THINK FUNCTIONS
+
+=============================================================================
+*/
+
+void() door_go_down;
+void() door_go_up;
+void() door_rotating_go_down;
+void() door_rotating_go_up;
+
+void door_blocked()
+{
+ if((self.spawnflags & 8)
+#ifdef SVQC
+ && (other.takedamage != DAMAGE_NO)
+#elif defined(CSQC)
+ && !PHYS_DEAD(other)
+#endif
+ )
+ { // KIll Kill Kill!!
+#ifdef SVQC
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+#endif
+ }
+ else
+ {
+#ifdef SVQC
+ if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
+ Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+#endif
+
+ // don't change direction for dead or dying stuff
+ if(PHYS_DEAD(other)
+#ifdef SVQC
+ && (other.takedamage == DAMAGE_NO)
+#endif
+ )
+ {
+ if (self.wait >= 0)
+ {
+ if (self.state == STATE_DOWN)
+ if (self.classname == "door")
+ {
+ door_go_up ();
+ } else
+ {
+ door_rotating_go_up ();
+ }
+ else
+ if (self.classname == "door")
+ {
+ door_go_down ();
+ } else
+ {
+ door_rotating_go_down ();
+ }
+ }
+ }
+#ifdef SVQC
+ else
+ {
+ //gib dying stuff just to make sure
+ if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ }
+#endif
+ }
+}
+
+void door_hit_top()
+{
+ if (self.noise1 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ self.state = STATE_TOP;
+ if (self.spawnflags & DOOR_TOGGLE)
+ return; // don't come down automatically
+ if (self.classname == "door")
+ {
+ self.SUB_THINK = door_go_down;
+ } else
+ {
+ self.SUB_THINK = door_rotating_go_down;
+ }
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+}
+
+void door_hit_bottom()
+{
+ if (self.noise1 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ self.state = STATE_BOTTOM;
+}
+
+void door_go_down()
+{
+ if (self.noise2 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ if (self.max_health)
+ {
+ self.takedamage = DAMAGE_YES;
+ self.health = self.max_health;
+ }
+
+ self.state = STATE_DOWN;
+ SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, door_hit_bottom);
+}
+
+void door_go_up()
+{
+ if (self.state == STATE_UP)
+ return; // already going up
+
+ if (self.state == STATE_TOP)
+ { // reset top wait time
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+ return;
+ }
+
+ if (self.noise2 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ self.state = STATE_UP;
+ SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, door_hit_top);
+
+ string oldmessage;
+ oldmessage = self.message;
+ self.message = "";
+ SUB_UseTargets();
+ self.message = oldmessage;
+}
+
+
+/*
+=============================================================================
+
+ACTIVATION FUNCTIONS
+
+=============================================================================
+*/
+
+float door_check_keys(void)
+{
+ local entity door;
+
+
+ if (self.owner)
+ door = self.owner;
+ else
+ door = self;
+
+ // no key needed
+ if (!door.itemkeys)
+ return true;
+
+ // this door require a key
+ // only a player can have a key
+ if (!IS_PLAYER(other))
+ return false;
+
+#ifdef SVQC
+ if (item_keys_usekey(door, other))
+ {
+ // some keys were used
+ if (other.key_door_messagetime <= time)
+ {
+
+ play2(other, "misc/talk.wav");
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
+ other.key_door_messagetime = time + 2;
+ }
+ }
+ else
+ {
+ // no keys were used
+ if (other.key_door_messagetime <= time)
+ {
+ play2(other, "misc/talk.wav");
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
+
+ other.key_door_messagetime = time + 2;
+ }
+ }
+#endif
+
+ if (door.itemkeys)
+ {
+#ifdef SVQC
+ // door is now unlocked
+ play2(other, "misc/talk.wav");
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_UNLOCKED);
+#endif
+ return true;
+ }
+ else
+ return false;
+}
+
+void door_fire()
+{
+ entity oself;
+ entity starte;
+
+ if (self.owner != self)
+ objerror ("door_fire: self.owner != self");
+
+ oself = self;
+
+ if (self.spawnflags & DOOR_TOGGLE)
+ {
+ if (self.state == STATE_UP || self.state == STATE_TOP)
+ {
+ starte = self;
+ do
+ {
+ if (self.classname == "door")
+ {
+ door_go_down ();
+ }
+ else
+ {
+ door_rotating_go_down ();
+ }
+ self = self.enemy;
+ } while ( (self != starte) && (self != world) );
+ self = oself;
+ return;
+ }
+ }
+
+// trigger all paired doors
+ starte = self;
+ do
+ {
+ if (self.classname == "door")
+ {
+ door_go_up ();
+ } else
+ {
+ // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
+ if ((self.spawnflags & 2) && other.trigger_reverse!=0 && self.lip!=666 && self.state == STATE_BOTTOM)
+ {
+ self.lip = 666; // self.lip is used to remember reverse opening direction for door_rotating
+ self.pos2 = '0 0 0' - self.pos2;
+ }
+ // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
+ if (!((self.spawnflags & 2) && (self.spawnflags & 8) && self.state == STATE_DOWN
+ && (((self.lip==666) && (other.trigger_reverse==0)) || ((self.lip!=666) && (other.trigger_reverse!=0)))))
+ {
+ door_rotating_go_up ();
+ }
+ }
+ self = self.enemy;
+ } while ( (self != starte) && (self != world) );
+ self = oself;
+}
+
+void door_use()
+{
+ entity oself;
+
+ //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
+
+ if (self.owner)
+ {
+ oself = self;
+ self = self.owner;
+ door_fire ();
+ self = oself;
+ }
+}
+
+void door_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ entity oself;
+ if(self.spawnflags & DOOR_NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ self.health = self.health - damage;
+
+ if (self.itemkeys)
+ {
+ // don't allow opening doors through damage if keys are required
+ return;
+ }
+
+ if (self.health <= 0)
+ {
+ oself = self;
+ self = self.owner;
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_NO; // wil be reset upon return
+ door_use ();
+ self = oself;
+ }
+}
+
+
+/*
+================
+door_touch
+
+Prints messages
+================
+*/
+
+void door_touch()
+{
+ if (!IS_PLAYER(other))
+ return;
+ if (self.owner.attack_finished_single > time)
+ return;
+
+ self.owner.attack_finished_single = time + 2;
+
+#ifdef SVQC
+ if (!(self.owner.dmg) && (self.owner.message != ""))
+ {
+ if (IS_CLIENT(other))
+ centerprint(other, self.owner.message);
+ play2(other, "misc/talk.wav");
+ }
+#endif
+}
+
+void door_generic_plat_blocked()
+{
+
+ if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
+#ifdef SVQC
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+#endif
+ }
+ else
+ {
+
+#ifdef SVQC
+ if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
+ Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+#endif
+
+ //Dont chamge direction for dead or dying stuff
+ if(PHYS_DEAD(other) && (other.takedamage == DAMAGE_NO))
+ {
+ if (self.wait >= 0)
+ {
+ if (self.state == STATE_DOWN)
+ door_rotating_go_up ();
+ else
+ door_rotating_go_down ();
+ }
+ }
+#ifdef SVQC
+ else
+ {
+ //gib dying stuff just to make sure
+ if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ }
+#endif
+ }
+}
+
+void door_rotating_hit_top()
+{
+ if (self.noise1 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ self.state = STATE_TOP;
+ if (self.spawnflags & DOOR_TOGGLE)
+ return; // don't come down automatically
+ self.SUB_THINK = door_rotating_go_down;
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+}
+
+void door_rotating_hit_bottom()
+{
+ if (self.noise1 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ if (self.lip==666) // self.lip is used to remember reverse opening direction for door_rotating
+ {
+ self.pos2 = '0 0 0' - self.pos2;
+ self.lip = 0;
+ }
+ self.state = STATE_BOTTOM;
+}
+
+void door_rotating_go_down()
+{
+ if (self.noise2 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ if (self.max_health)
+ {
+ self.takedamage = DAMAGE_YES;
+ self.health = self.max_health;
+ }
+
+ self.state = STATE_DOWN;
+ SUB_CalcAngleMove (self.pos1, TSPEED_LINEAR, self.speed, door_rotating_hit_bottom);
+}
+
+void door_rotating_go_up()
+{
+ if (self.state == STATE_UP)
+ return; // already going up
+
+ if (self.state == STATE_TOP)
+ { // reset top wait time
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+ return;
+ }
+ if (self.noise2 != "")
+ sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ self.state = STATE_UP;
+ SUB_CalcAngleMove (self.pos2, TSPEED_LINEAR, self.speed, door_rotating_hit_top);
+
+ string oldmessage;
+ oldmessage = self.message;
+ self.message = "";
+ SUB_UseTargets();
+ self.message = oldmessage;
+}
+
+
+/*
+=========================================
+door trigger
+
+Spawned if a door lacks a real activator
+=========================================
+*/
+
+void door_trigger_touch()
+{
+ if (other.health < 1)
+#ifdef SVQC
+ if (!((other.iscreature || (other.flags & FL_PROJECTILE)) && !PHYS_DEAD(other)))
+#elif defined(CSQC)
+ if(!((IS_CLIENT(other) || other.classname == "csqcprojectile") && !PHYS_DEAD(other)))
+#endif
+ return;
+
+ if (time < self.attack_finished_single)
+ return;
+
+ // check if door is locked
+ if (!door_check_keys())
+ return;
+
+ self.attack_finished_single = time + 1;
+
+ activator = other;
+
+ self = self.owner;
+ door_use ();
+}
+
+void spawn_field(vector fmins, vector fmaxs)
+{
+ entity trigger;
+ vector t1 = fmins, t2 = fmaxs;
+
+ trigger = spawn();
+ trigger.classname = "doortriggerfield";
+ trigger.movetype = MOVETYPE_NONE;
+ trigger.solid = SOLID_TRIGGER;
+ trigger.owner = self;
+#ifdef SVQC
+ trigger.touch = door_trigger_touch;
+#elif defined(CSQC)
+ trigger.trigger_touch = door_trigger_touch;
+ trigger.draw = trigger_draw_generic;
+ trigger.drawmask = MASK_NORMAL;
+#endif
+
+ setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
+}
+
+
+/*
+=============
+LinkDoors
+
+
+=============
+*/
+
+entity LinkDoors_nextent(entity cur, entity near, entity pass)
+{
+ while((cur = find(cur, classname, self.classname)) && ((cur.spawnflags & 4) || cur.enemy))
+ {
+ }
+ return cur;
+}
+
+bool LinkDoors_isconnected(entity e1, entity e2, entity pass)
+{
+ float DELTA = 4;
+ if((e1.absmin_x > e2.absmax_x + DELTA)
+ || (e1.absmin_y > e2.absmax_y + DELTA)
+ || (e1.absmin_z > e2.absmax_z + DELTA)
+ || (e2.absmin_x > e1.absmax_x + DELTA)
+ || (e2.absmin_y > e1.absmax_y + DELTA)
+ || (e2.absmin_z > e1.absmax_z + DELTA)
+ ) { return false; }
+ return true;
+}
+
+#ifdef SVQC
+void door_link();
+#endif
+void LinkDoors()
+{
+ entity t;
+ vector cmins, cmaxs;
+
+#ifdef SVQC
+ door_link();
+#endif
+
+ if (self.enemy)
+ return; // already linked by another door
+ if (self.spawnflags & 4)
+ {
+ self.owner = self.enemy = self;
+
+ if (self.health)
+ return;
+ IFTARGETED
+ return;
+ if (self.items)
+ return;
+
+ spawn_field(self.absmin, self.absmax);
+
+ return; // don't want to link this door
+ }
+
+ FindConnectedComponent(self, enemy, LinkDoors_nextent, LinkDoors_isconnected, world);
+
+ // set owner, and make a loop of the chain
+ dprint("LinkDoors: linking doors:");
+ for(t = self; ; t = t.enemy)
+ {
+ dprint(" ", etos(t));
+ t.owner = self;
+ if(t.enemy == world)
+ {
+ t.enemy = self;
+ break;
+ }
+ }
+ dprint("\n");
+
+ // collect health, targetname, message, size
+ cmins = self.absmin;
+ cmaxs = self.absmax;
+ for(t = self; ; t = t.enemy)
+ {
+ if(t.health && !self.health)
+ self.health = t.health;
+ if((t.targetname != "") && (self.targetname == ""))
+ self.targetname = t.targetname;
+ if((t.message != "") && (self.message == ""))
+ self.message = t.message;
+ if (t.absmin_x < cmins_x)
+ cmins_x = t.absmin_x;
+ if (t.absmin_y < cmins_y)
+ cmins_y = t.absmin_y;
+ if (t.absmin_z < cmins_z)
+ cmins_z = t.absmin_z;
+ if (t.absmax_x > cmaxs_x)
+ cmaxs_x = t.absmax_x;
+ if (t.absmax_y > cmaxs_y)
+ cmaxs_y = t.absmax_y;
+ if (t.absmax_z > cmaxs_z)
+ cmaxs_z = t.absmax_z;
+ if(t.enemy == self)
+ break;
+ }
+
+ // distribute health, targetname, message
+ for(t = self; t; t = t.enemy)
+ {
+ t.health = self.health;
+ t.targetname = self.targetname;
+ t.message = self.message;
+ if(t.enemy == self)
+ break;
+ }
+
+ // shootable, or triggered doors just needed the owner/enemy links,
+ // they don't spawn a field
+
+ if (self.health)
+ return;
+ IFTARGETED
+ return;
+ if (self.items)
+ return;
+
+ spawn_field(cmins, cmaxs);
+}
+
+#ifdef SVQC
+/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+
+GOLD_KEY causes the door to open only if the activator holds a gold key.
+
+SILVER_KEY causes the door to open only if the activator holds a silver key.
+
+"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle" determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health" if set, door must be shot open
+"speed" movement speed (100 default)
+"wait" wait before returning (3 default, -1 = never return)
+"lip" lip remaining at end of move (8 default)
+"dmg" damage to inflict when blocked (2 default)
+"sounds"
+0) no sound
+1) stone
+2) base
+3) stone chain
+4) screechy metal
+FIXME: only one sound set available at the time being
+
+*/
+
+float door_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_DOOR);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ WriteString(MSG_ENTITY, self.classname);
+ WriteByte(MSG_ENTITY, self.spawnflags);
+
+ WriteString(MSG_ENTITY, self.model);
+
+ trigger_common_write(true);
+
+ WriteCoord(MSG_ENTITY, self.pos1_x);
+ WriteCoord(MSG_ENTITY, self.pos1_y);
+ WriteCoord(MSG_ENTITY, self.pos1_z);
+ WriteCoord(MSG_ENTITY, self.pos2_x);
+ WriteCoord(MSG_ENTITY, self.pos2_y);
+ WriteCoord(MSG_ENTITY, self.pos2_z);
+
+ WriteCoord(MSG_ENTITY, self.size_x);
+ WriteCoord(MSG_ENTITY, self.size_y);
+ WriteCoord(MSG_ENTITY, self.size_z);
+
+ WriteShort(MSG_ENTITY, self.wait);
+ WriteShort(MSG_ENTITY, self.speed);
+ WriteByte(MSG_ENTITY, self.lip);
+ WriteByte(MSG_ENTITY, self.state);
+ WriteCoord(MSG_ENTITY, self.SUB_LTIME);
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ // client makes use of this, we do not
+ }
+
+ if(sf & SF_TRIGGER_UPDATE)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteCoord(MSG_ENTITY, self.pos1_x);
+ WriteCoord(MSG_ENTITY, self.pos1_y);
+ WriteCoord(MSG_ENTITY, self.pos1_z);
+ WriteCoord(MSG_ENTITY, self.pos2_x);
+ WriteCoord(MSG_ENTITY, self.pos2_y);
+ WriteCoord(MSG_ENTITY, self.pos2_z);
+ }
+
+ return true;
+}
+
+void door_link()
+{
+ // set size now, as everything is loaded
+ //FixSize(self);
+ //Net_LinkEntity(self, false, 0, door_send);
+}
+#endif
+
+void door_init_startopen()
+{
+ SUB_SETORIGIN(self, self.pos2);
+ self.pos2 = self.pos1;
+ self.pos1 = self.origin;
+
+#ifdef SVQC
+ self.SendFlags |= SF_TRIGGER_UPDATE;
+#endif
+}
+
+void door_reset()
+{
+ SUB_SETORIGIN(self, self.pos1);
+ self.SUB_VELOCITY = '0 0 0';
+ self.state = STATE_BOTTOM;
+ self.SUB_THINK = func_null;
+ self.SUB_NEXTTHINK = 0;
+
+#ifdef SVQC
+ self.SendFlags |= SF_TRIGGER_RESET;
+#endif
+}
+
+#ifdef SVQC
+
+// spawnflags require key (for now only func_door)
+void spawnfunc_func_door()
+{
+ // Quake 1 keys compatibility
+ if (self.spawnflags & SPAWNFLAGS_GOLD_KEY)
+ self.itemkeys |= ITEM_KEY_BIT(0);
+ if (self.spawnflags & SPAWNFLAGS_SILVER_KEY)
+ self.itemkeys |= ITEM_KEY_BIT(1);
+
+ SetMovedir ();
+
+ self.max_health = self.health;
+ if (!InitMovingBrushTrigger())
+ return;
+ self.effects |= EF_LOWPRECISION;
+ self.classname = "door";
+
+ self.blocked = door_blocked;
+ self.use = door_use;
+
+ if(self.dmg && (self.message == ""))
+ self.message = "was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+
+ if (self.sounds > 0)
+ {
+ precache_sound ("plats/medplat1.wav");
+ precache_sound ("plats/medplat2.wav");
+ self.noise2 = "plats/medplat1.wav";
+ self.noise1 = "plats/medplat2.wav";
+ }
+
+ if (!self.speed)
+ self.speed = 100;
+ if (!self.wait)
+ self.wait = 3;
+ if (!self.lip)
+ self.lip = 8;
+
+ self.pos1 = self.SUB_ORIGIN;
+ self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+ if (self.spawnflags & DOOR_START_OPEN)
+ InitializeEntity(self, door_init_startopen, INITPRIO_SETLOCATION);
+
+ self.state = STATE_BOTTOM;
+
+ if (self.health)
+ {
+ self.takedamage = DAMAGE_YES;
+ self.event_damage = door_damage;
+ }
+
+ if (self.items)
+ self.wait = -1;
+
+ self.touch = door_touch;
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+ InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
+
+ self.reset = door_reset;
+}
+
+#elif defined(CSQC)
+
+void door_draw()
+{
+ Movetype_Physics_NoMatchServer();
+
+ trigger_draw_generic();
+}
+
+void ent_door()
+{
+ float sf = ReadByte();
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ self.classname = strzone(ReadString());
+ self.spawnflags = ReadByte();
+
+ self.mdl = strzone(ReadString());
+ setmodel(self, self.mdl);
+
+ trigger_common_read(true);
+
+ self.pos1_x = ReadCoord();
+ self.pos1_y = ReadCoord();
+ self.pos1_z = ReadCoord();
+ self.pos2_x = ReadCoord();
+ self.pos2_y = ReadCoord();
+ self.pos2_z = ReadCoord();
+
+ self.size_x = ReadCoord();
+ self.size_y = ReadCoord();
+ self.size_z = ReadCoord();
+
+ self.wait = ReadShort();
+ self.speed = ReadShort();
+ self.lip = ReadByte();
+ self.state = ReadByte();
+ self.SUB_LTIME = ReadCoord();
+
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_PUSH;
+ self.trigger_touch = door_touch;
+ self.draw = door_draw;
+ self.drawmask = MASK_NORMAL;
+ self.use = door_use;
+
+ LinkDoors();
+
+ if(self.spawnflags & DOOR_START_OPEN)
+ door_init_startopen();
+
+ self.move_time = time;
+ self.move_origin = self.origin;
+ self.move_movetype = MOVETYPE_PUSH;
+ self.move_angles = self.angles;
+ self.move_blocked = door_blocked;
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ door_reset();
+ }
+
+ if(sf & SF_TRIGGER_UPDATE)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+ self.move_origin = self.origin;
+
+ self.pos1_x = ReadCoord();
+ self.pos1_y = ReadCoord();
+ self.pos1_z = ReadCoord();
+ self.pos2_x = ReadCoord();
+ self.pos2_y = ReadCoord();
+ self.pos2_z = ReadCoord();
+ }
+}
+
+#endif
--- /dev/null
+// door constants
+const int DOOR_START_OPEN = 1;
+const int DOOR_DONT_LINK = 4;
+const int DOOR_TOGGLE = 32;
+
+const int DOOR_NOSPLASH = 256; // generic anti-splashdamage spawnflag
+
+const int SPAWNFLAGS_GOLD_KEY = 8;
+const int SPAWNFLAGS_SILVER_KEY = 16;
+
+#ifdef CSQC
+// stuff for preload
+void ent_door();
+
+// abused
+.float attack_finished_single;
+#endif
--- /dev/null
+#ifdef SVQC
+/*QUAKED spawnfunc_func_door_rotating (0 .5 .8) ? START_OPEN BIDIR DOOR_DONT_LINK BIDIR_IN_DOWN x TOGGLE X_AXIS Y_AXIS
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor.
+The usage of bidirectional doors requires two manually instantiated triggers (trigger_multiple), the one to open it in the other direction
+must have set trigger_reverse to 1.
+BIDIR_IN_DOWN will the door prevent from reopening while closing if it is triggered from the other side.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
+
+"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle" determines the destination angle for opening. negative values reverse the direction.
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health" if set, door must be shot open
+"speed" movement speed (100 default)
+"wait" wait before returning (3 default, -1 = never return)
+"dmg" damage to inflict when blocked (2 default)
+"sounds"
+0) no sound
+1) stone
+2) base
+3) stone chain
+4) screechy metal
+FIXME: only one sound set available at the time being
+*/
+
+void door_rotating_reset()
+{
+ self.angles = self.pos1;
+ self.avelocity = '0 0 0';
+ self.state = STATE_BOTTOM;
+ self.think = func_null;
+ self.nextthink = 0;
+}
+
+void door_rotating_init_startopen()
+{
+ self.angles = self.movedir;
+ self.pos2 = '0 0 0';
+ self.pos1 = self.movedir;
+}
+
+
+void spawnfunc_func_door_rotating()
+{
+
+ //if (!self.deathtype) // map makers can override this
+ // self.deathtype = " got in the way";
+
+ // I abuse "movedir" for denoting the axis for now
+ if (self.spawnflags & 64) // X (untested)
+ self.movedir = '0 0 1';
+ else if (self.spawnflags & 128) // Y (untested)
+ self.movedir = '1 0 0';
+ else // Z
+ self.movedir = '0 1 0';
+
+ if (self.angles_y==0) self.angles_y = 90;
+
+ self.movedir = self.movedir * self.angles_y;
+ self.angles = '0 0 0';
+
+ self.max_health = self.health;
+ self.avelocity = self.movedir;
+ if (!InitMovingBrushTrigger())
+ return;
+ self.velocity = '0 0 0';
+ //self.effects |= EF_LOWPRECISION;
+ self.classname = "door_rotating";
+
+ self.blocked = door_blocked;
+ self.use = door_use;
+
+ if(self.spawnflags & 8)
+ self.dmg = 10000;
+
+ if(self.dmg && (self.message == ""))
+ self.message = "was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+
+ if (self.sounds > 0)
+ {
+ precache_sound ("plats/medplat1.wav");
+ precache_sound ("plats/medplat2.wav");
+ self.noise2 = "plats/medplat1.wav";
+ self.noise1 = "plats/medplat2.wav";
+ }
+
+ if (!self.speed)
+ self.speed = 50;
+ if (!self.wait)
+ self.wait = 1;
+ self.lip = 0; // self.lip is used to remember reverse opening direction for door_rotating
+
+ self.pos1 = '0 0 0';
+ self.pos2 = self.movedir;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+ if (self.spawnflags & DOOR_START_OPEN)
+ InitializeEntity(self, door_rotating_init_startopen, INITPRIO_SETLOCATION);
+
+ self.state = STATE_BOTTOM;
+
+ if (self.health)
+ {
+ self.takedamage = DAMAGE_YES;
+ self.event_damage = door_damage;
+ }
+
+ if (self.items)
+ self.wait = -1;
+
+ self.touch = door_touch;
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+ InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
+
+ self.reset = door_rotating_reset;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void() fd_secret_move1;
+void() fd_secret_move2;
+void() fd_secret_move3;
+void() fd_secret_move4;
+void() fd_secret_move5;
+void() fd_secret_move6;
+void() fd_secret_done;
+
+const float SECRET_OPEN_ONCE = 1; // stays open
+const float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
+const float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
+const float SECRET_NO_SHOOT = 8; // only opened by trigger
+const float SECRET_YES_SHOOT = 16; // shootable even if targeted
+
+void fd_secret_use()
+{
+ float temp;
+ string message_save;
+
+ self.health = 10000;
+ self.bot_attack = true;
+
+ // exit if still moving around...
+ if (self.origin != self.oldorigin)
+ return;
+
+ message_save = self.message;
+ self.message = ""; // no more message
+ SUB_UseTargets(); // fire all targets / killtargets
+ self.message = message_save;
+
+ self.velocity = '0 0 0';
+
+ // Make a sound, wait a little...
+
+ if (self.noise1 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
+
+ temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
+ makevectors(self.mangle);
+
+ if (!self.t_width)
+ {
+ if (self.spawnflags & SECRET_1ST_DOWN)
+ self.t_width = fabs(v_up * self.size);
+ else
+ self.t_width = fabs(v_right * self.size);
+ }
+
+ if (!self.t_length)
+ self.t_length = fabs(v_forward * self.size);
+
+ if (self.spawnflags & SECRET_1ST_DOWN)
+ self.dest1 = self.origin - v_up * self.t_width;
+ else
+ self.dest1 = self.origin + v_right * (self.t_width * temp);
+
+ self.dest2 = self.dest1 + v_forward * self.t_length;
+ SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move1);
+ if (self.noise2 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ fd_secret_use();
+}
+
+// Wait after first movement...
+void fd_secret_move1()
+{
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 1.0;
+ self.think = fd_secret_move2;
+ if (self.noise3 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+// Start moving sideways w/sound...
+void fd_secret_move2()
+{
+ if (self.noise2 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ SUB_CalcMove(self.dest2, TSPEED_LINEAR, self.speed, fd_secret_move3);
+}
+
+// Wait here until time to go back...
+void fd_secret_move3()
+{
+ if (self.noise3 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+ if (!(self.spawnflags & SECRET_OPEN_ONCE))
+ {
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+ self.think = fd_secret_move4;
+ }
+}
+
+// Move backward...
+void fd_secret_move4()
+{
+ if (self.noise2 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move5);
+}
+
+// Wait 1 second...
+void fd_secret_move5()
+{
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 1.0;
+ self.think = fd_secret_move6;
+ if (self.noise3 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_move6()
+{
+ if (self.noise2 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+ SUB_CalcMove(self.oldorigin, TSPEED_LINEAR, self.speed, fd_secret_done);
+}
+
+void fd_secret_done()
+{
+ if (self.spawnflags&SECRET_YES_SHOOT)
+ {
+ self.health = 10000;
+ self.takedamage = DAMAGE_YES;
+ //self.th_pain = fd_secret_use;
+ }
+ if (self.noise3 != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+void secret_blocked()
+{
+ if (time < self.attack_finished_single)
+ return;
+ self.attack_finished_single = time + 0.5;
+ //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
+}
+
+/*
+==============
+secret_touch
+
+Prints messages
+================
+*/
+void secret_touch()
+{
+ if (!other.iscreature)
+ return;
+ if (self.attack_finished_single > time)
+ return;
+
+ self.attack_finished_single = time + 2;
+
+ if (self.message)
+ {
+ if (IS_CLIENT(other))
+ centerprint(other, self.message);
+ play2(other, "misc/talk.wav");
+ }
+}
+
+void secret_reset()
+{
+ if (self.spawnflags&SECRET_YES_SHOOT)
+ {
+ self.health = 10000;
+ self.takedamage = DAMAGE_YES;
+ }
+ setorigin(self, self.oldorigin);
+ self.think = func_null;
+ self.SUB_NEXTTHINK = 0;
+}
+
+/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
+Basic secret door. Slides back, then to the side. Angle determines direction.
+wait = # of seconds before coming back
+1st_left = 1st move is left of arrow
+1st_down = 1st move is down from arrow
+always_shoot = even if targeted, keep shootable
+t_width = override WIDTH to move back (or height if going down)
+t_length = override LENGTH to move sideways
+"dmg" damage to inflict when blocked (2 default)
+
+If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
+"sounds"
+1) medieval
+2) metal
+3) base
+*/
+
+void spawnfunc_func_door_secret()
+{
+ /*if (!self.deathtype) // map makers can override this
+ self.deathtype = " got in the way";*/
+
+ if (!self.dmg)
+ self.dmg = 2;
+
+ // Magic formula...
+ self.mangle = self.angles;
+ self.angles = '0 0 0';
+ self.classname = "door";
+ if (!InitMovingBrushTrigger())
+ return;
+ self.effects |= EF_LOWPRECISION;
+
+ self.touch = secret_touch;
+ self.blocked = secret_blocked;
+ self.speed = 50;
+ self.use = fd_secret_use;
+ IFTARGETED
+ {
+ }
+ else
+ self.spawnflags |= SECRET_YES_SHOOT;
+
+ if(self.spawnflags&SECRET_YES_SHOOT)
+ {
+ self.health = 10000;
+ self.takedamage = DAMAGE_YES;
+ self.event_damage = fd_secret_damage;
+ }
+ self.oldorigin = self.origin;
+ if (!self.wait)
+ self.wait = 5; // 5 seconds before closing
+
+ self.reset = secret_reset;
+ secret_reset();
+}
+#endif
--- /dev/null
+#ifdef SVQC
+/*QUAKED spawnfunc_func_fourier (0 .5 .8) ?
+Brush model that moves in a pattern of added up sine waves, can be used e.g. for circular motions.
+netname: list of <frequencymultiplier> <phase> <x> <y> <z> quadruples, separated by spaces; note that phase 0 represents a sine wave, and phase 0.25 a cosine wave (by default, it uses 1 0 0 0 1, to match func_bobbing's defaults
+speed: how long one cycle of frequency multiplier 1 in seconds (default 4)
+height: amplitude modifier (default 32)
+phase: cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
+noise: path/name of looping .wav file to play.
+dmg: Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime: See above.
+*/
+
+void func_fourier_controller_think()
+{
+ vector v;
+ float n, i, t;
+
+ self.nextthink = time + 0.1;
+ if(self.owner.active != ACTIVE_ACTIVE)
+ {
+ self.owner.velocity = '0 0 0';
+ return;
+ }
+
+
+ n = floor((tokenize_console(self.owner.netname)) / 5);
+ t = self.nextthink * self.owner.cnt + self.owner.phase * 360;
+
+ v = self.owner.destvec;
+
+ for(i = 0; i < n; ++i)
+ {
+ makevectors((t * stof(argv(i*5)) + stof(argv(i*5+1)) * 360) * '0 1 0');
+ v = v + ('1 0 0' * stof(argv(i*5+2)) + '0 1 0' * stof(argv(i*5+3)) + '0 0 1' * stof(argv(i*5+4))) * self.owner.height * v_forward_y;
+ }
+
+ if(self.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed
+ // * 10 so it will arrive in 0.1 sec
+ self.owner.velocity = (v - self.owner.origin) * 10;
+}
+
+void spawnfunc_func_fourier()
+{
+ entity controller;
+ if (self.noise != "")
+ {
+ precache_sound(self.noise);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+ }
+
+ if (!self.speed)
+ self.speed = 4;
+ if (!self.height)
+ self.height = 32;
+ self.destvec = self.origin;
+ self.cnt = 360 / self.speed;
+
+ self.blocked = generic_plat_blocked;
+ if(self.dmg && (self.message == ""))
+ self.message = " was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+ if(self.dmg && (!self.dmgtime))
+ self.dmgtime = 0.25;
+ self.dmgtime2 = time;
+
+ if(self.netname == "")
+ self.netname = "1 0 0 0 1";
+
+ if (!InitMovingBrushTrigger())
+ return;
+
+ self.active = ACTIVE_ACTIVE;
+
+ // wait for targets to spawn
+ controller = spawn();
+ controller.classname = "func_fourier_controller";
+ controller.owner = self;
+ controller.nextthink = time + 1;
+ controller.think = func_fourier_controller_think;
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 999999999;
+ self.SUB_THINK = SUB_NullThink; // for PushMove
+
+ // Savage: Reduce bandwith, critical on e.g. nexdm02
+ self.effects |= EF_LOWPRECISION;
+
+ // TODO make a reset function for this one
+}
+#endif
--- /dev/null
+#include "include.qh"
+
+#include "bobbing.qc"
+#include "breakable.qc"
+#include "button.qc"
+#include "conveyor.qc"
+#include "door.qc"
+#include "door_rotating.qc"
+#include "door_secret.qc"
+#include "fourier.qc"
+#include "ladder.qc"
+#include "pendulum.qc"
+#include "plat.qc"
+#include "pointparticles.qc"
+#include "rainsnow.qc"
+#include "rotating.qc"
+#include "stardust.qc"
+#include "train.qc"
+#include "vectormamamam.qc"
--- /dev/null
+#ifndef TRIGGERS_FUNC_INCLUDE_H
+#define TRIGGERS_FUNC_INCLUDE_H
+
+#include "conveyor.qh"
+#include "door.qh"
+#include "ladder.qh"
+#include "plat.qh"
+#include "rainsnow.qh"
+#include "pointparticles.qh"
+#include "train.qh"
+
+#endif
--- /dev/null
+void func_ladder_touch()
+{
+#ifdef SVQC
+ if (!other.iscreature)
+ return;
+ if (other.vehicle_flags & VHF_ISVEHICLE)
+ return;
+#endif
+#ifdef CSQC
+ if(other.classname != "csqcmodel")
+ return;
+#endif
+
+ EXACTTRIGGER_TOUCH;
+
+ other.ladder_time = time + 0.1;
+ other.ladder_entity = self;
+}
+
+#ifdef SVQC
+float func_ladder_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
+
+ WriteString(MSG_ENTITY, self.classname);
+ WriteByte(MSG_ENTITY, self.skin);
+ WriteByte(MSG_ENTITY, self.speed);
+ WriteString(MSG_ENTITY, self.mdl);
+
+ trigger_common_write(false);
+
+ return true;
+}
+
+void func_ladder_link()
+{
+ //self.SendEntity = func_ladder_send;
+ //self.SendFlags = 0xFFFFFF;
+ //self.model = "null";
+}
+
+void spawnfunc_func_ladder()
+{
+ self.mdl = self.model;
+ EXACTTRIGGER_INIT;
+ self.touch = func_ladder_touch;
+
+ func_ladder_link();
+}
+
+void spawnfunc_func_water()
+{
+ self.mdl = self.model;
+ EXACTTRIGGER_INIT;
+ self.touch = func_ladder_touch;
+
+ func_ladder_link();
+}
+
+#elif defined(CSQC)
+.float speed;
+
+void ent_func_ladder()
+{
+ self.classname = strzone(ReadString());
+ self.skin = ReadByte();
+ self.speed = ReadByte();
+ self.model = strzone(ReadString());
+
+ trigger_common_read(false);
+ self.mins = self.maxs = '0 0 0';
+
+ self.solid = SOLID_TRIGGER;
+ self.draw = trigger_draw_generic;
+ self.trigger_touch = func_ladder_touch;
+ self.drawmask = MASK_NORMAL;
+ self.move_time = time;
+ self.entremove = trigger_remove_generic;
+
+ //precache_model(self.mdl);
+ EXACTTRIGGER_INIT;
+}
+#endif
--- /dev/null
+.float ladder_time;
+.entity ladder_entity;
+
+#ifdef CSQC
+void ent_func_ladder();
+#endif
--- /dev/null
+#ifdef SVQC
+.float freq;
+void func_pendulum_controller_think()
+{
+ float v;
+ self.nextthink = time + 0.1;
+
+ if (!(self.owner.active == ACTIVE_ACTIVE))
+ {
+ self.owner.avelocity_x = 0;
+ return;
+ }
+
+ // calculate sinewave using makevectors
+ makevectors((self.nextthink * self.owner.freq + self.owner.phase) * '0 360 0');
+ v = self.owner.speed * v_forward_y + self.cnt;
+ if(self.owner.classname == "func_pendulum") // don't brake stuff if the func_bobbing was killtarget'ed
+ {
+ // * 10 so it will arrive in 0.1 sec
+ self.owner.avelocity_z = (remainder(v - self.owner.angles_z, 360)) * 10;
+ }
+}
+
+void spawnfunc_func_pendulum()
+{
+ entity controller;
+ if (self.noise != "")
+ {
+ precache_sound(self.noise);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+ }
+
+ self.active = ACTIVE_ACTIVE;
+
+ // keys: angle, speed, phase, noise, freq
+
+ if(!self.speed)
+ self.speed = 30;
+ // not initializing self.dmg to 2, to allow damageless pendulum
+
+ if(self.dmg && (self.message == ""))
+ self.message = " was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+ if(self.dmg && (!self.dmgtime))
+ self.dmgtime = 0.25;
+ self.dmgtime2 = time;
+
+ self.blocked = generic_plat_blocked;
+
+ self.avelocity_z = 0.0000001;
+ if (!InitMovingBrushTrigger())
+ return;
+
+ if(!self.freq)
+ {
+ // find pendulum length (same formula as Q3A)
+ self.freq = 1 / (M_PI * 2) * sqrt(autocvar_sv_gravity / (3 * max(8, fabs(self.mins_z))));
+ }
+
+ // copy initial angle
+ self.cnt = self.angles_z;
+
+ // wait for targets to spawn
+ controller = spawn();
+ controller.classname = "func_pendulum_controller";
+ controller.owner = self;
+ controller.nextthink = time + 1;
+ controller.think = func_pendulum_controller_think;
+ self.nextthink = self.SUB_LTIME + 999999999;
+ self.SUB_THINK = SUB_NullThink; // for PushMove
+
+ //self.effects |= EF_LOWPRECISION;
+
+ // TODO make a reset function for this one
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void plat_link();
+
+void plat_delayedinit()
+{
+ plat_link();
+ plat_spawn_inside_trigger(); // the "start moving" trigger
+}
+
+float plat_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_PLAT);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ WriteByte(MSG_ENTITY, self.platmovetype_start);
+ WriteByte(MSG_ENTITY, self.platmovetype_turn);
+ WriteByte(MSG_ENTITY, self.platmovetype_end);
+ WriteByte(MSG_ENTITY, self.spawnflags);
+
+ WriteString(MSG_ENTITY, self.model);
+
+ trigger_common_write(true);
+
+ WriteCoord(MSG_ENTITY, self.pos1_x);
+ WriteCoord(MSG_ENTITY, self.pos1_y);
+ WriteCoord(MSG_ENTITY, self.pos1_z);
+ WriteCoord(MSG_ENTITY, self.pos2_x);
+ WriteCoord(MSG_ENTITY, self.pos2_y);
+ WriteCoord(MSG_ENTITY, self.pos2_z);
+
+ WriteCoord(MSG_ENTITY, self.size_x);
+ WriteCoord(MSG_ENTITY, self.size_y);
+ WriteCoord(MSG_ENTITY, self.size_z);
+
+ WriteAngle(MSG_ENTITY, self.mangle_x);
+ WriteAngle(MSG_ENTITY, self.mangle_y);
+ WriteAngle(MSG_ENTITY, self.mangle_z);
+
+ WriteShort(MSG_ENTITY, self.speed);
+ WriteShort(MSG_ENTITY, self.height);
+ WriteByte(MSG_ENTITY, self.lip);
+ WriteByte(MSG_ENTITY, self.state);
+
+ WriteShort(MSG_ENTITY, self.dmg);
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ // used on client
+ }
+
+ return true;
+}
+
+void plat_link()
+{
+ //Net_LinkEntity(self, 0, false, plat_send);
+}
+
+void spawnfunc_func_plat()
+{
+ if (self.sounds == 0)
+ self.sounds = 2;
+
+ if(self.spawnflags & 4)
+ self.dmg = 10000;
+
+ if(self.dmg && (self.message == ""))
+ self.message = "was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+
+ if (self.sounds == 1)
+ {
+ precache_sound ("plats/plat1.wav");
+ precache_sound ("plats/plat2.wav");
+ self.noise = "plats/plat1.wav";
+ self.noise1 = "plats/plat2.wav";
+ }
+
+ if (self.sounds == 2)
+ {
+ precache_sound ("plats/medplat1.wav");
+ precache_sound ("plats/medplat2.wav");
+ self.noise = "plats/medplat1.wav";
+ self.noise1 = "plats/medplat2.wav";
+ }
+
+ if (self.sound1)
+ {
+ precache_sound (self.sound1);
+ self.noise = self.sound1;
+ }
+ if (self.sound2)
+ {
+ precache_sound (self.sound2);
+ self.noise1 = self.sound2;
+ }
+
+ self.mangle = self.angles;
+ self.angles = '0 0 0';
+
+ self.classname = "plat";
+ if (!InitMovingBrushTrigger())
+ return;
+ self.effects |= EF_LOWPRECISION;
+ setsize (self, self.mins , self.maxs);
+
+ self.blocked = plat_crush;
+
+ if (!self.speed)
+ self.speed = 150;
+ if (!self.lip)
+ self.lip = 16;
+ if (!self.height)
+ self.height = self.size_z - self.lip;
+
+ self.pos1 = self.origin;
+ self.pos2 = self.origin;
+ self.pos2_z = self.origin_z - self.height;
+
+ self.reset = plat_reset;
+ plat_reset();
+
+ InitializeEntity(self, plat_delayedinit, INITPRIO_FINDTARGET);
+}
+#elif defined(CSQC)
+void plat_draw()
+{
+ Movetype_Physics_NoMatchServer();
+ //Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
+}
+
+void ent_plat()
+{
+ float sf = ReadByte();
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ self.platmovetype_start = ReadByte();
+ self.platmovetype_turn = ReadByte();
+ self.platmovetype_end = ReadByte();
+ self.spawnflags = ReadByte();
+
+ self.model = strzone(ReadString());
+ setmodel(self, self.model);
+
+ trigger_common_read(true);
+
+ self.pos1_x = ReadCoord();
+ self.pos1_y = ReadCoord();
+ self.pos1_z = ReadCoord();
+ self.pos2_x = ReadCoord();
+ self.pos2_y = ReadCoord();
+ self.pos2_z = ReadCoord();
+
+ self.size_x = ReadCoord();
+ self.size_y = ReadCoord();
+ self.size_z = ReadCoord();
+
+ self.mangle_x = ReadAngle();
+ self.mangle_y = ReadAngle();
+ self.mangle_z = ReadAngle();
+
+ self.speed = ReadShort();
+ self.height = ReadShort();
+ self.lip = ReadByte();
+ self.state = ReadByte();
+
+ self.dmg = ReadShort();
+
+ self.classname = "plat";
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_PUSH;
+ self.drawmask = MASK_NORMAL;
+ self.draw = plat_draw;
+ self.use = plat_use;
+ self.entremove = trigger_remove_generic;
+
+ plat_reset(); // also called here
+
+ self.move_movetype = MOVETYPE_PUSH;
+ self.move_origin = self.origin;
+ self.move_angles = self.angles;
+ self.move_time = time;
+
+ plat_spawn_inside_trigger();
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ plat_reset();
+
+ self.move_origin = self.origin;
+ self.move_angles = self.angles;
+ self.move_time = time;
+ }
+}
+#endif
--- /dev/null
+#ifdef CSQC
+void ent_plat();
+#endif
--- /dev/null
+#ifdef CSQC
+ #include "../../../client/particles.qh"
+#endif
+
+#ifdef SVQC
+// NOTE: also contains func_sparks
+
+float pointparticles_SendEntity(entity to, float fl)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
+
+ // optional features to save space
+ fl = fl & 0x0F;
+ if(self.spawnflags & 2)
+ fl |= 0x10; // absolute count on toggle-on
+ if(self.movedir != '0 0 0' || self.velocity != '0 0 0')
+ fl |= 0x20; // 4 bytes - saves CPU
+ if(self.waterlevel || self.count != 1)
+ fl |= 0x40; // 4 bytes - obscure features almost never used
+ if(self.mins != '0 0 0' || self.maxs != '0 0 0')
+ fl |= 0x80; // 14 bytes - saves lots of space
+
+ WriteByte(MSG_ENTITY, fl);
+ if(fl & 2)
+ {
+ if(self.state)
+ WriteCoord(MSG_ENTITY, self.impulse);
+ else
+ WriteCoord(MSG_ENTITY, 0); // off
+ }
+ if(fl & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+ }
+ if(fl & 1)
+ {
+ if(self.model != "null")
+ {
+ WriteShort(MSG_ENTITY, self.modelindex);
+ if(fl & 0x80)
+ {
+ WriteCoord(MSG_ENTITY, self.mins_x);
+ WriteCoord(MSG_ENTITY, self.mins_y);
+ WriteCoord(MSG_ENTITY, self.mins_z);
+ WriteCoord(MSG_ENTITY, self.maxs_x);
+ WriteCoord(MSG_ENTITY, self.maxs_y);
+ WriteCoord(MSG_ENTITY, self.maxs_z);
+ }
+ }
+ else
+ {
+ WriteShort(MSG_ENTITY, 0);
+ if(fl & 0x80)
+ {
+ WriteCoord(MSG_ENTITY, self.maxs_x);
+ WriteCoord(MSG_ENTITY, self.maxs_y);
+ WriteCoord(MSG_ENTITY, self.maxs_z);
+ }
+ }
+ WriteShort(MSG_ENTITY, self.cnt);
+ if(fl & 0x20)
+ {
+ WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
+ WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
+ }
+ if(fl & 0x40)
+ {
+ WriteShort(MSG_ENTITY, self.waterlevel * 16.0);
+ WriteByte(MSG_ENTITY, self.count * 16.0);
+ }
+ WriteString(MSG_ENTITY, self.noise);
+ if(self.noise != "")
+ {
+ WriteByte(MSG_ENTITY, floor(self.atten * 64));
+ WriteByte(MSG_ENTITY, floor(self.volume * 255));
+ }
+ WriteString(MSG_ENTITY, self.bgmscript);
+ if(self.bgmscript != "")
+ {
+ WriteByte(MSG_ENTITY, floor(self.bgmscriptattack * 64));
+ WriteByte(MSG_ENTITY, floor(self.bgmscriptdecay * 64));
+ WriteByte(MSG_ENTITY, floor(self.bgmscriptsustain * 255));
+ WriteByte(MSG_ENTITY, floor(self.bgmscriptrelease * 64));
+ }
+ }
+ return 1;
+}
+
+void pointparticles_use()
+{
+ self.state = !self.state;
+ self.SendFlags |= 2;
+}
+
+void pointparticles_think()
+{
+ if(self.origin != self.oldorigin)
+ {
+ self.SendFlags |= 4;
+ self.oldorigin = self.origin;
+ }
+ self.nextthink = time;
+}
+
+void pointparticles_reset()
+{
+ if(self.spawnflags & 1)
+ self.state = 1;
+ else
+ self.state = 0;
+}
+
+void spawnfunc_func_pointparticles()
+{
+ if(self.model != "")
+ setmodel(self, self.model);
+ if(self.noise != "")
+ precache_sound (self.noise);
+
+ if(!self.bgmscriptsustain)
+ self.bgmscriptsustain = 1;
+ else if(self.bgmscriptsustain < 0)
+ self.bgmscriptsustain = 0;
+
+ if(!self.atten)
+ self.atten = ATTEN_NORM;
+ else if(self.atten < 0)
+ self.atten = 0;
+ if(!self.volume)
+ self.volume = 1;
+ if(!self.count)
+ self.count = 1;
+ if(!self.impulse)
+ self.impulse = 1;
+
+ if(!self.modelindex)
+ {
+ setorigin(self, self.origin + self.mins);
+ setsize(self, '0 0 0', self.maxs - self.mins);
+ }
+ if(!self.cnt)
+ self.cnt = particleeffectnum(self.mdl);
+
+ Net_LinkEntity(self, (self.spawnflags & 4), 0, pointparticles_SendEntity);
+
+ IFTARGETED
+ {
+ self.use = pointparticles_use;
+ self.reset = pointparticles_reset;
+ self.reset();
+ }
+ else
+ self.state = 1;
+ self.think = pointparticles_think;
+ self.nextthink = time;
+}
+
+void spawnfunc_func_sparks()
+{
+ // self.cnt is the amount of sparks that one burst will spawn
+ if(self.cnt < 1) {
+ self.cnt = 25.0; // nice default value
+ }
+
+ // self.wait is the probability that a sparkthink will spawn a spark shower
+ // range: 0 - 1, but 0 makes little sense, so...
+ if(self.wait < 0.05) {
+ self.wait = 0.25; // nice default value
+ }
+
+ self.count = self.cnt;
+ self.mins = '0 0 0';
+ self.maxs = '0 0 0';
+ self.velocity = '0 0 -1';
+ self.mdl = "TE_SPARK";
+ self.impulse = 10 * self.wait; // by default 2.5/sec
+ self.wait = 0;
+ self.cnt = 0; // use mdl
+
+ spawnfunc_func_pointparticles();
+}
+#elif defined(CSQC)
+
+void Draw_PointParticles()
+{
+ float n, i, fail;
+ vector p;
+ vector sz;
+ vector o;
+ o = self.origin;
+ sz = self.maxs - self.mins;
+ n = doBGMScript(self);
+ if(self.absolute == 2)
+ {
+ if(n >= 0)
+ n = self.just_toggled ? self.impulse : 0;
+ else
+ n = self.impulse * drawframetime;
+ }
+ else
+ {
+ n *= self.impulse * drawframetime;
+ if(self.just_toggled)
+ if(n < 1)
+ n = 1;
+ }
+ if(n == 0)
+ return;
+ fail = 0;
+ for(i = random(); i <= n && fail <= 64*n; ++i)
+ {
+ p = o + self.mins;
+ p.x += random() * sz.x;
+ p.y += random() * sz.y;
+ p.z += random() * sz.z;
+ if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
+ {
+ if(self.movedir != '0 0 0')
+ {
+ traceline(p, p + normalize(self.movedir) * 4096, 0, world);
+ p = trace_endpos;
+ pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
+ }
+ else
+ {
+ pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
+ }
+ if(self.noise != "")
+ {
+ setorigin(self, p);
+ sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
+ }
+ self.just_toggled = 0;
+ }
+ else if(self.absolute)
+ {
+ ++fail;
+ --i;
+ }
+ }
+ setorigin(self, o);
+}
+
+void Ent_PointParticles_Remove()
+{
+ if(self.noise)
+ strunzone(self.noise);
+ self.noise = string_null;
+ if(self.bgmscript)
+ strunzone(self.bgmscript);
+ self.bgmscript = string_null;
+}
+
+void Ent_PointParticles()
+{
+ float i;
+ vector v;
+ int f = ReadByte();
+ if(f & 2)
+ {
+ i = ReadCoord(); // density (<0: point, >0: volume)
+ if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
+ self.just_toggled = 1;
+ self.impulse = i;
+ }
+ if(f & 4)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ }
+ if(f & 1)
+ {
+ self.modelindex = ReadShort();
+ if(f & 0x80)
+ {
+ if(self.modelindex)
+ {
+ self.mins_x = ReadCoord();
+ self.mins_y = ReadCoord();
+ self.mins_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ }
+ else
+ {
+ self.mins = '0 0 0';
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ }
+ }
+ else
+ {
+ self.mins = self.maxs = '0 0 0';
+ }
+
+ self.cnt = ReadShort(); // effect number
+
+ if(f & 0x20)
+ {
+ self.velocity = decompressShortVector(ReadShort());
+ self.movedir = decompressShortVector(ReadShort());
+ }
+ else
+ {
+ self.velocity = self.movedir = '0 0 0';
+ }
+ if(f & 0x40)
+ {
+ self.waterlevel = ReadShort() / 16.0;
+ self.count = ReadByte() / 16.0;
+ }
+ else
+ {
+ self.waterlevel = 0;
+ self.count = 1;
+ }
+ if(self.noise)
+ strunzone(self.noise);
+ if(self.bgmscript)
+ strunzone(self.bgmscript);
+ self.noise = strzone(ReadString());
+ if(self.noise != "")
+ {
+ self.atten = ReadByte() / 64.0;
+ self.volume = ReadByte() / 255.0;
+ }
+ self.bgmscript = strzone(ReadString());
+ if(self.bgmscript != "")
+ {
+ self.bgmscriptattack = ReadByte() / 64.0;
+ self.bgmscriptdecay = ReadByte() / 64.0;
+ self.bgmscriptsustain = ReadByte() / 255.0;
+ self.bgmscriptrelease = ReadByte() / 64.0;
+ }
+ BGMScript_InitEntity(self);
+ }
+
+ if(f & 2)
+ {
+ self.absolute = (self.impulse >= 0);
+ if(!self.absolute)
+ {
+ v = self.maxs - self.mins;
+ self.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
+ }
+ }
+
+ if(f & 0x10)
+ self.absolute = 2;
+
+ setorigin(self, self.origin);
+ setsize(self, self.mins, self.maxs);
+ self.solid = SOLID_NOT;
+ self.draw = Draw_PointParticles;
+ self.entremove = Ent_PointParticles_Remove;
+}
+#endif
--- /dev/null
+#ifdef CSQC
+
+void Ent_PointParticles();
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifdef SVQC
+float rainsnow_SendEntity(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
+ WriteByte(MSG_ENTITY, self.state);
+ WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x);
+ WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y);
+ WriteCoord(MSG_ENTITY, self.origin_z + self.mins_z);
+ WriteCoord(MSG_ENTITY, self.maxs_x - self.mins_x);
+ WriteCoord(MSG_ENTITY, self.maxs_y - self.mins_y);
+ WriteCoord(MSG_ENTITY, self.maxs_z - self.mins_z);
+ WriteShort(MSG_ENTITY, compressShortVector(self.dest));
+ WriteShort(MSG_ENTITY, self.count);
+ WriteByte(MSG_ENTITY, self.cnt);
+ return 1;
+}
+
+/*QUAKED spawnfunc_func_rain (0 .5 .8) ?
+This is an invisible area like a trigger, which rain falls inside of.
+
+Keys:
+"velocity"
+ falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
+"cnt"
+ sets color of rain (default 12 - white)
+"count"
+ adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
+*/
+void spawnfunc_func_rain()
+{
+ self.dest = self.velocity;
+ self.velocity = '0 0 0';
+ if (!self.dest)
+ self.dest = '0 0 -700';
+ self.angles = '0 0 0';
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_NOT;
+ SetBrushEntityModel();
+ if (!self.cnt)
+ self.cnt = 12;
+ if (!self.count)
+ self.count = 2000;
+ self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
+ if (self.count < 1)
+ self.count = 1;
+ if(self.count > 65535)
+ self.count = 65535;
+
+ self.state = 1; // 1 is rain, 0 is snow
+ self.Version = 1;
+
+ Net_LinkEntity(self, false, 0, rainsnow_SendEntity);
+}
+
+
+/*QUAKED spawnfunc_func_snow (0 .5 .8) ?
+This is an invisible area like a trigger, which snow falls inside of.
+
+Keys:
+"velocity"
+ falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
+"cnt"
+ sets color of rain (default 12 - white)
+"count"
+ adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
+*/
+void spawnfunc_func_snow()
+{
+ self.dest = self.velocity;
+ self.velocity = '0 0 0';
+ if (!self.dest)
+ self.dest = '0 0 -300';
+ self.angles = '0 0 0';
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_NOT;
+ SetBrushEntityModel();
+ if (!self.cnt)
+ self.cnt = 12;
+ if (!self.count)
+ self.count = 2000;
+ self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
+ if (self.count < 1)
+ self.count = 1;
+ if(self.count > 65535)
+ self.count = 65535;
+
+ self.state = 0; // 1 is rain, 0 is snow
+ self.Version = 1;
+
+ Net_LinkEntity(self, false, 0, rainsnow_SendEntity);
+}
+#elif defined(CSQC)
+void Draw_Rain()
+{
+ te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
+}
+
+void Draw_Snow()
+{
+ te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
+}
+
+void Ent_RainOrSnow()
+{
+ self.impulse = ReadByte(); // Rain, Snow, or Whatever
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ self.velocity = decompressShortVector(ReadShort());
+ self.count = ReadShort() * 10;
+ self.glow_color = ReadByte(); // color
+
+ self.mins = -0.5 * self.maxs;
+ self.maxs = 0.5 * self.maxs;
+ self.origin = self.origin - self.mins;
+
+ setorigin(self, self.origin);
+ setsize(self, self.mins, self.maxs);
+ self.solid = SOLID_NOT;
+ if(self.impulse)
+ self.draw = Draw_Rain;
+ else
+ self.draw = Draw_Snow;
+}
+#endif
--- /dev/null
+#ifdef CSQC
+void Ent_RainOrSnow();
+#endif
--- /dev/null
+#ifdef SVQC
+void func_rotating_setactive(float astate)
+{
+
+ if (astate == ACTIVE_TOGGLE)
+ {
+ if(self.active == ACTIVE_ACTIVE)
+ self.active = ACTIVE_NOT;
+ else
+ self.active = ACTIVE_ACTIVE;
+ }
+ else
+ self.active = astate;
+
+ if(self.active == ACTIVE_NOT)
+ self.avelocity = '0 0 0';
+ else
+ self.avelocity = self.pos1;
+}
+
+/*QUAKED spawnfunc_func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
+Brush model that spins in place on one axis (default Z).
+speed : speed to rotate (in degrees per second)
+noise : path/name of looping .wav file to play.
+dmg : Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime : See above.
+*/
+
+void spawnfunc_func_rotating()
+{
+ if (self.noise != "")
+ {
+ precache_sound(self.noise);
+ ambientsound(self.origin, self.noise, VOL_BASE, ATTEN_IDLE);
+ }
+
+ self.active = ACTIVE_ACTIVE;
+ self.setactive = func_rotating_setactive;
+
+ if (!self.speed)
+ self.speed = 100;
+ // FIXME: test if this turns the right way, then remove this comment (negate as needed)
+ if (self.spawnflags & 4) // X (untested)
+ self.avelocity = '0 0 1' * self.speed;
+ // FIXME: test if this turns the right way, then remove this comment (negate as needed)
+ else if (self.spawnflags & 8) // Y (untested)
+ self.avelocity = '1 0 0' * self.speed;
+ // FIXME: test if this turns the right way, then remove this comment (negate as needed)
+ else // Z
+ self.avelocity = '0 1 0' * self.speed;
+
+ self.pos1 = self.avelocity;
+
+ if(self.dmg && (self.message == ""))
+ self.message = " was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+
+
+ if(self.dmg && (!self.dmgtime))
+ self.dmgtime = 0.25;
+
+ self.dmgtime2 = time;
+
+ if (!InitMovingBrushTrigger())
+ return;
+ // no EF_LOWPRECISION here, as rounding angles is bad
+
+ self.blocked = generic_plat_blocked;
+
+ // wait for targets to spawn
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 999999999;
+ self.SUB_THINK = SUB_NullThink; // for PushMove
+
+ // TODO make a reset function for this one
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void spawnfunc_func_stardust()
+{
+ self.effects = EF_STARDUST;
+
+ CSQCMODEL_AUTOINIT();
+}
+#endif
--- /dev/null
+.float train_wait_turning;
+void() train_next;
+void train_wait()
+{
+ entity oldself;
+ oldself = self;
+ self = self.enemy;
+ SUB_UseTargets();
+ self = oldself;
+ self.enemy = world;
+
+ // if turning is enabled, the train will turn toward the next point while waiting
+ if(self.platmovetype_turn && !self.train_wait_turning)
+ {
+ entity targ, cp;
+ vector ang;
+ targ = find(world, targetname, self.target);
+ if((self.spawnflags & 1) && targ.curvetarget)
+ cp = find(world, targetname, targ.curvetarget);
+ else
+ cp = world;
+
+ if(cp) // bezier curves movement
+ ang = cp.origin - (self.origin - self.view_ofs); // use the origin of the control point of the next path_corner
+ else // linear movement
+ ang = targ.origin - (self.origin - self.view_ofs); // use the origin of the next path_corner
+ ang = vectoangles(ang);
+ ang_x = -ang_x; // flip up / down orientation
+
+ if(self.wait > 0) // slow turning
+ SUB_CalcAngleMove(ang, TSPEED_TIME, self.SUB_LTIME - time + self.wait, train_wait);
+ else // instant turning
+ SUB_CalcAngleMove(ang, TSPEED_TIME, 0.0000001, train_wait);
+ self.train_wait_turning = true;
+ return;
+ }
+
+#ifdef SVQC
+ if(self.noise != "")
+ stopsoundto(MSG_BROADCAST, self, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
+#endif
+
+ if(self.wait < 0 || self.train_wait_turning) // no waiting or we already waited while turning
+ {
+ self.train_wait_turning = false;
+ train_next();
+ }
+ else
+ {
+ self.SUB_THINK = train_next;
+ self.SUB_NEXTTHINK = self.SUB_LTIME + self.wait;
+ }
+}
+
+void train_next()
+{
+ entity targ, cp = world;
+ vector cp_org = '0 0 0';
+
+ targ = find(world, targetname, self.target);
+ self.target = targ.target;
+ if (self.spawnflags & 1)
+ {
+ if(targ.curvetarget)
+ {
+ cp = find(world, targetname, targ.curvetarget); // get its second target (the control point)
+ cp_org = cp.origin - self.view_ofs; // no control point found, assume a straight line to the destination
+ }
+ }
+ if (self.target == "")
+ objerror("train_next: no next target");
+ self.wait = targ.wait;
+ if (!self.wait)
+ self.wait = 0.1;
+
+ if(targ.platmovetype)
+ {
+ // this path_corner contains a movetype overrider, apply it
+ self.platmovetype_start = targ.platmovetype_start;
+ self.platmovetype_end = targ.platmovetype_end;
+ }
+ else
+ {
+ // this path_corner doesn't contain a movetype overrider, use the train's defaults
+ self.platmovetype_start = self.platmovetype_start_default;
+ self.platmovetype_end = self.platmovetype_end_default;
+ }
+
+ if (targ.speed)
+ {
+ if (cp)
+ SUB_CalcMove_Bezier(cp_org, targ.origin - self.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
+ else
+ SUB_CalcMove(targ.origin - self.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
+ }
+ else
+ {
+ if (cp)
+ SUB_CalcMove_Bezier(cp_org, targ.origin - self.view_ofs, TSPEED_LINEAR, self.speed, train_wait);
+ else
+ SUB_CalcMove(targ.origin - self.view_ofs, TSPEED_LINEAR, self.speed, train_wait);
+ }
+
+ if(self.noise != "")
+ sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+}
+
+#ifdef SVQC
+float train_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_TRAIN);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ WriteString(MSG_ENTITY, self.platmovetype);
+ WriteByte(MSG_ENTITY, self.platmovetype_turn);
+ WriteByte(MSG_ENTITY, self.spawnflags);
+
+ WriteString(MSG_ENTITY, self.model);
+
+ trigger_common_write(true);
+
+ WriteString(MSG_ENTITY, self.curvetarget);
+
+ WriteCoord(MSG_ENTITY, self.pos1_x);
+ WriteCoord(MSG_ENTITY, self.pos1_y);
+ WriteCoord(MSG_ENTITY, self.pos1_z);
+ WriteCoord(MSG_ENTITY, self.pos2_x);
+ WriteCoord(MSG_ENTITY, self.pos2_y);
+ WriteCoord(MSG_ENTITY, self.pos2_z);
+
+ WriteCoord(MSG_ENTITY, self.size_x);
+ WriteCoord(MSG_ENTITY, self.size_y);
+ WriteCoord(MSG_ENTITY, self.size_z);
+
+ WriteCoord(MSG_ENTITY, self.view_ofs_x);
+ WriteCoord(MSG_ENTITY, self.view_ofs_y);
+ WriteCoord(MSG_ENTITY, self.view_ofs_z);
+
+ WriteAngle(MSG_ENTITY, self.mangle_x);
+ WriteAngle(MSG_ENTITY, self.mangle_y);
+ WriteAngle(MSG_ENTITY, self.mangle_z);
+
+ WriteShort(MSG_ENTITY, self.speed);
+ WriteShort(MSG_ENTITY, self.height);
+ WriteByte(MSG_ENTITY, self.lip);
+ WriteByte(MSG_ENTITY, self.state);
+ WriteByte(MSG_ENTITY, self.wait);
+
+ WriteShort(MSG_ENTITY, self.dmg);
+ WriteByte(MSG_ENTITY, self.dmgtime);
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ // used on client
+ }
+
+ return true;
+}
+
+void train_link()
+{
+ //Net_LinkEntity(self, 0, false, train_send);
+}
+
+void func_train_find()
+{
+ entity targ;
+ targ = find(world, targetname, self.target);
+ self.target = targ.target;
+ if (self.target == "")
+ objerror("func_train_find: no next target");
+ SUB_SETORIGIN(self, targ.origin - self.view_ofs);
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 1;
+ self.SUB_THINK = train_next;
+
+ train_link();
+}
+
+#endif
+
+/*QUAKED spawnfunc_func_train (0 .5 .8) ?
+Ridable platform, targets spawnfunc_path_corner path to follow.
+speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
+target : targetname of first spawnfunc_path_corner (starts here)
+*/
+#ifdef SVQC
+void spawnfunc_func_train()
+{
+ if (self.noise != "")
+ precache_sound(self.noise);
+
+ if (self.target == "")
+ objerror("func_train without a target");
+ if (!self.speed)
+ self.speed = 100;
+
+ if (!InitMovingBrushTrigger())
+ return;
+ self.effects |= EF_LOWPRECISION;
+
+ if (self.spawnflags & 2)
+ {
+ self.platmovetype_turn = true;
+ self.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
+ }
+ else
+ self.view_ofs = self.mins;
+
+ // wait for targets to spawn
+ InitializeEntity(self, func_train_find, INITPRIO_FINDTARGET);
+
+ self.blocked = generic_plat_blocked;
+ if(self.dmg && (self.message == ""))
+ self.message = " was squished";
+ if(self.dmg && (self.message2 == ""))
+ self.message2 = "was squished by";
+ if(self.dmg && (!self.dmgtime))
+ self.dmgtime = 0.25;
+ self.dmgtime2 = time;
+
+ if(!set_platmovetype(self, self.platmovetype))
+ return;
+ self.platmovetype_start_default = self.platmovetype_start;
+ self.platmovetype_end_default = self.platmovetype_end;
+
+ // TODO make a reset function for this one
+}
+#elif defined(CSQC)
+void train_draw()
+{
+ //Movetype_Physics_NoMatchServer();
+ Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
+}
+
+void ent_train()
+{
+ float sf = ReadByte();
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ self.platmovetype = strzone(ReadString());
+ self.platmovetype_turn = ReadByte();
+ self.spawnflags = ReadByte();
+
+ self.model = strzone(ReadString());
+ setmodel(self, self.model);
+
+ trigger_common_read(true);
+
+ self.curvetarget = strzone(ReadString());
+
+ self.pos1_x = ReadCoord();
+ self.pos1_y = ReadCoord();
+ self.pos1_z = ReadCoord();
+ self.pos2_x = ReadCoord();
+ self.pos2_y = ReadCoord();
+ self.pos2_z = ReadCoord();
+
+ self.size_x = ReadCoord();
+ self.size_y = ReadCoord();
+ self.size_z = ReadCoord();
+
+ self.view_ofs_x = ReadCoord();
+ self.view_ofs_y = ReadCoord();
+ self.view_ofs_z = ReadCoord();
+
+ self.mangle_x = ReadAngle();
+ self.mangle_y = ReadAngle();
+ self.mangle_z = ReadAngle();
+
+ self.speed = ReadShort();
+ self.height = ReadShort();
+ self.lip = ReadByte();
+ self.state = ReadByte();
+ self.wait = ReadByte();
+
+ self.dmg = ReadShort();
+ self.dmgtime = ReadByte();
+
+ self.classname = "func_train";
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_PUSH;
+ self.drawmask = MASK_NORMAL;
+ self.draw = train_draw;
+ self.entremove = trigger_remove_generic;
+
+ if(set_platmovetype(self, self.platmovetype))
+ {
+ self.platmovetype_start_default = self.platmovetype_start;
+ self.platmovetype_end_default = self.platmovetype_end;
+ }
+
+ // everything is set up by the time the train is linked, we shouldn't need this
+ //func_train_find();
+
+ // but we will need these
+ //self.move_nextthink = self.move_ltime + 0.1;
+ //self.move_think = train_next;
+ train_next();
+
+ self.move_movetype = MOVETYPE_PUSH;
+ self.move_origin = self.origin;
+ self.move_angles = self.angles;
+ self.move_time = time;
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ // TODO: make a reset function for trains
+ }
+}
+
+#endif
--- /dev/null
+#ifdef CSQC
+.float dmgtime;
+void ent_train();
+#endif
--- /dev/null
+#ifdef SVQC
+// reusing some fields havocbots declared
+.entity wp00, wp01, wp02, wp03;
+
+.float targetfactor, target2factor, target3factor, target4factor;
+.vector targetnormal, target2normal, target3normal, target4normal;
+
+vector func_vectormamamam_origin(entity o, float t)
+{
+ vector v, p;
+ float f;
+ entity e;
+
+ f = o.spawnflags;
+ v = '0 0 0';
+
+ e = o.wp00;
+ if(e)
+ {
+ p = e.origin + t * e.velocity;
+ if(f & 1)
+ v = v + (p * o.targetnormal) * o.targetnormal * o.targetfactor;
+ else
+ v = v + (p - (p * o.targetnormal) * o.targetnormal) * o.targetfactor;
+ }
+
+ e = o.wp01;
+ if(e)
+ {
+ p = e.origin + t * e.velocity;
+ if(f & 2)
+ v = v + (p * o.target2normal) * o.target2normal * o.target2factor;
+ else
+ v = v + (p - (p * o.target2normal) * o.target2normal) * o.target2factor;
+ }
+
+ e = o.wp02;
+ if(e)
+ {
+ p = e.origin + t * e.velocity;
+ if(f & 4)
+ v = v + (p * o.target3normal) * o.target3normal * o.target3factor;
+ else
+ v = v + (p - (p * o.target3normal) * o.target3normal) * o.target3factor;
+ }
+
+ e = o.wp03;
+ if(e)
+ {
+ p = e.origin + t * e.velocity;
+ if(f & 8)
+ v = v + (p * o.target4normal) * o.target4normal * o.target4factor;
+ else
+ v = v + (p - (p * o.target4normal) * o.target4normal) * o.target4factor;
+ }
+
+ return v;
+}
+
+void func_vectormamamam_controller_think()
+{
+ self.nextthink = time + 0.1;
+
+ if(self.owner.active != ACTIVE_ACTIVE)
+ {
+ self.owner.velocity = '0 0 0';
+ return;
+ }
+
+ if(self.owner.classname == "func_vectormamamam") // don't brake stuff if the func_vectormamamam was killtarget'ed
+ self.owner.velocity = (self.owner.destvec + func_vectormamamam_origin(self.owner, 0.1) - self.owner.origin) * 10;
+}
+
+void func_vectormamamam_findtarget()
+{
+ if(self.target != "")
+ self.wp00 = find(world, targetname, self.target);
+
+ if(self.target2 != "")
+ self.wp01 = find(world, targetname, self.target2);
+
+ if(self.target3 != "")
+ self.wp02 = find(world, targetname, self.target3);
+
+ if(self.target4 != "")
+ self.wp03 = find(world, targetname, self.target4);
+
+ if(!self.wp00 && !self.wp01 && !self.wp02 && !self.wp03)
+ objerror("No reference entity found, so there is nothing to move. Aborting.");
+
+ self.destvec = self.origin - func_vectormamamam_origin(self, 0);
+
+ entity controller;
+ controller = spawn();
+ controller.classname = "func_vectormamamam_controller";
+ controller.owner = self;
+ controller.nextthink = time + 1;
+ controller.think = func_vectormamamam_controller_think;
+}
+
+void spawnfunc_func_vectormamamam()
+{
+ if (self.noise != "")
+ {
+ precache_sound(self.noise);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+ }
+
+ if(!self.targetfactor)
+ self.targetfactor = 1;
+
+ if(!self.target2factor)
+ self.target2factor = 1;
+
+ if(!self.target3factor)
+ self.target3factor = 1;
+
+ if(!self.target4factor)
+ self.target4factor = 1;
+
+ if(vlen(self.targetnormal))
+ self.targetnormal = normalize(self.targetnormal);
+
+ if(vlen(self.target2normal))
+ self.target2normal = normalize(self.target2normal);
+
+ if(vlen(self.target3normal))
+ self.target3normal = normalize(self.target3normal);
+
+ if(vlen(self.target4normal))
+ self.target4normal = normalize(self.target4normal);
+
+ self.blocked = generic_plat_blocked;
+ if(self.dmg && (self.message == ""))
+ self.message = " was squished";
+ if(self.dmg && (self.message == ""))
+ self.message2 = "was squished by";
+ if(self.dmg && (!self.dmgtime))
+ self.dmgtime = 0.25;
+ self.dmgtime2 = time;
+
+ if(self.netname == "")
+ self.netname = "1 0 0 0 1";
+
+ if (!InitMovingBrushTrigger())
+ return;
+
+ // wait for targets to spawn
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 999999999;
+ self.SUB_THINK = SUB_NullThink; // for PushMove
+
+ // Savage: Reduce bandwith, critical on e.g. nexdm02
+ self.effects |= EF_LOWPRECISION;
+
+ self.active = ACTIVE_ACTIVE;
+
+ InitializeEntity(self, func_vectormamamam_findtarget, INITPRIO_FINDTARGET);
+}
+#endif
--- /dev/null
+#include "include.qh"
+
+// some required common stuff
+#include "subs.qc"
+#include "triggers.qc"
+#include "platforms.qc"
+#include "teleporters.qc"
+
+// func
+#include "func/include.qc"
+
+// misc
+#include "misc/include.qc"
+
+// target
+#include "target/include.qc"
+
+// trigger
+#include "trigger/include.qc"
+
--- /dev/null
+#ifndef TRIGGERS_INCLUDE_H
+#define TRIGGERS_INCLUDE_H
+
+// some required common stuff
+#ifdef CSQC
+ #include "../../server/item_key.qh"
+#endif
+#include "triggers.qh"
+#include "subs.qh"
+#include "platforms.qh"
+#include "teleporters.qh"
+
+// func
+#include "func/include.qh"
+
+// misc
+#include "misc/include.qh"
+
+// target
+#include "target/include.qh"
+
+// trigger
+#include "trigger/include.qh"
+
+#endif
--- /dev/null
+#ifdef SVQC
+bool corner_send(entity to, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_CORNER);
+
+ WriteString(MSG_ENTITY, self.platmovetype);
+
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteString(MSG_ENTITY, self.target);
+ WriteString(MSG_ENTITY, self.target2);
+ WriteString(MSG_ENTITY, self.target3);
+ WriteString(MSG_ENTITY, self.target4);
+ WriteString(MSG_ENTITY, self.targetname);
+ WriteByte(MSG_ENTITY, self.target_random);
+
+ WriteByte(MSG_ENTITY, self.wait);
+
+ return true;
+}
+
+void corner_link()
+{
+ //Net_LinkEntity(self, false, 0, corner_send);
+}
+
+void spawnfunc_path_corner()
+{
+ // setup values for overriding train movement
+ // if a second value does not exist, both start and end speeds are the single value specified
+ set_platmovetype(self, self.platmovetype);
+
+ corner_link();
+}
+#elif defined(CSQC)
+
+void corner_remove()
+{
+ if(self.target) { strunzone(self.target); }
+ self.target = string_null;
+
+ if(self.target2) { strunzone(self.target2); }
+ self.target2 = string_null;
+
+ if(self.target3) { strunzone(self.target3); }
+ self.target3 = string_null;
+
+ if(self.target4) { strunzone(self.target4); }
+ self.target4 = string_null;
+
+ if(self.targetname) { strunzone(self.targetname); }
+ self.targetname = string_null;
+
+ if(self.platmovetype) { strunzone(self.platmovetype); }
+ self.platmovetype = string_null;
+}
+
+void ent_corner()
+{
+ self.platmovetype = strzone(ReadString());
+
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+
+ self.target = strzone(ReadString());
+ self.target2 = strzone(ReadString());
+ self.target3 = strzone(ReadString());
+ self.target4 = strzone(ReadString());
+ self.targetname = strzone(ReadString());
+ self.target_random = ReadByte();
+
+ self.wait = ReadByte();
+
+ self.classname = "path_corner";
+ self.drawmask = MASK_NORMAL;
+ self.entremove = corner_remove;
+
+ set_platmovetype(self, self.platmovetype);
+}
+
+#endif
--- /dev/null
+#ifdef CSQC
+void ent_corner();
+#endif
--- /dev/null
+// the way this entity works makes it no use to CSQC, as it removes itself instantly
+
+#ifdef SVQC
+void follow_init()
+{
+ entity src, dst;
+ src = world;
+ dst = world;
+ if(self.killtarget != "")
+ src = find(world, targetname, self.killtarget);
+ if(self.target != "")
+ dst = find(world, targetname, self.target);
+
+ if(!src && !dst)
+ {
+ objerror("follow: could not find target/killtarget");
+ return;
+ }
+
+ if(self.jointtype)
+ {
+ // already done :P entity must stay
+ self.aiment = src;
+ self.enemy = dst;
+ }
+ else if(!src || !dst)
+ {
+ objerror("follow: could not find target/killtarget");
+ return;
+ }
+ else if(self.spawnflags & 1)
+ {
+ // attach
+ if(self.spawnflags & 2)
+ {
+ setattachment(dst, src, self.message);
+ }
+ else
+ {
+ attach_sameorigin(dst, src, self.message);
+ }
+
+ dst.solid = SOLID_NOT; // solid doesn't work with attachment
+ remove(self);
+ }
+ else
+ {
+ if(self.spawnflags & 2)
+ {
+ dst.movetype = MOVETYPE_FOLLOW;
+ dst.aiment = src;
+ // dst.punchangle = '0 0 0'; // keep unchanged
+ dst.view_ofs = dst.origin;
+ dst.v_angle = dst.angles;
+ }
+ else
+ {
+ follow_sameorigin(dst, src);
+ }
+
+ remove(self);
+ }
+}
+
+void spawnfunc_misc_follow()
+{
+ InitializeEntity(self, follow_init, INITPRIO_FINDTARGET);
+}
+#endif
--- /dev/null
+#include "include.qh"
+
+#include "corner.qc"
+#include "follow.qc"
+#include "laser.qc"
+#include "teleport_dest.qc"
--- /dev/null
+#ifndef TRIGGERS_MISC_INCLUDE_H
+#define TRIGGERS_MISC_INCLUDE_H
+
+#include "corner.qh"
+#include "laser.qh"
+
+#endif
--- /dev/null
+#if defined(CSQC)
+ #include "../../../client/_all.qh"
+ #include "../../buffs.qh"
+ #include "../../../csqcmodellib/interpolate.qh"
+ #include "../../../client/main.qh"
+ #include "../../../csqcmodellib/cl_model.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+#ifdef SVQC
+.float modelscale;
+void misc_laser_aim()
+{
+ vector a;
+ if(self.enemy)
+ {
+ if(self.spawnflags & 2)
+ {
+ if(self.enemy.origin != self.mangle)
+ {
+ self.mangle = self.enemy.origin;
+ self.SendFlags |= 2;
+ }
+ }
+ else
+ {
+ a = vectoangles(self.enemy.origin - self.origin);
+ a_x = -a_x;
+ if(a != self.mangle)
+ {
+ self.mangle = a;
+ self.SendFlags |= 2;
+ }
+ }
+ }
+ else
+ {
+ if(self.angles != self.mangle)
+ {
+ self.mangle = self.angles;
+ self.SendFlags |= 2;
+ }
+ }
+ if(self.origin != self.oldorigin)
+ {
+ self.SendFlags |= 1;
+ self.oldorigin = self.origin;
+ }
+}
+
+void misc_laser_init()
+{
+ if(self.target != "")
+ self.enemy = find(world, targetname, self.target);
+}
+
+.entity pusher;
+void misc_laser_think()
+{
+ vector o;
+ entity oldself;
+ entity hitent;
+ vector hitloc;
+
+ self.nextthink = time;
+
+ if(!self.state)
+ return;
+
+ misc_laser_aim();
+
+ if(self.enemy)
+ {
+ o = self.enemy.origin;
+ if (!(self.spawnflags & 2))
+ o = self.origin + normalize(o - self.origin) * 32768;
+ }
+ else
+ {
+ makevectors(self.mangle);
+ o = self.origin + v_forward * 32768;
+ }
+
+ if(self.dmg || self.enemy.target != "")
+ {
+ traceline(self.origin, o, MOVE_NORMAL, self);
+ }
+ hitent = trace_ent;
+ hitloc = trace_endpos;
+
+ if(self.enemy.target != "") // DETECTOR laser
+ {
+ if(trace_ent.iscreature)
+ {
+ self.pusher = hitent;
+ if(!self.count)
+ {
+ self.count = 1;
+
+ oldself = self;
+ self = self.enemy;
+ activator = self.pusher;
+ SUB_UseTargets();
+ self = oldself;
+ }
+ }
+ else
+ {
+ if(self.count)
+ {
+ self.count = 0;
+
+ oldself = self;
+ self = self.enemy;
+ activator = self.pusher;
+ SUB_UseTargets();
+ self = oldself;
+ }
+ }
+ }
+
+ if(self.dmg)
+ {
+ if(self.team)
+ if(((self.spawnflags & 8) == 0) == (self.team != hitent.team))
+ return;
+ if(hitent.takedamage)
+ Damage(hitent, self, self, ((self.dmg < 0) ? 100000 : (self.dmg * frametime)), DEATH_HURTTRIGGER, hitloc, '0 0 0');
+ }
+}
+
+float laser_SendEntity(entity to, float fl)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
+ fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
+ if(self.spawnflags & 2)
+ fl |= 0x80;
+ if(self.alpha)
+ fl |= 0x40;
+ if(self.scale != 1 || self.modelscale != 1)
+ fl |= 0x20;
+ if(self.spawnflags & 4)
+ fl |= 0x10;
+ WriteByte(MSG_ENTITY, fl);
+ if(fl & 1)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+ }
+ if(fl & 8)
+ {
+ WriteByte(MSG_ENTITY, self.colormod_x * 255.0);
+ WriteByte(MSG_ENTITY, self.colormod_y * 255.0);
+ WriteByte(MSG_ENTITY, self.colormod_z * 255.0);
+ if(fl & 0x40)
+ WriteByte(MSG_ENTITY, self.alpha * 255.0);
+ if(fl & 0x20)
+ {
+ WriteByte(MSG_ENTITY, bound(0, self.scale * 16.0, 255));
+ WriteByte(MSG_ENTITY, bound(0, self.modelscale * 16.0, 255));
+ }
+ if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
+ WriteShort(MSG_ENTITY, self.cnt + 1);
+ }
+ if(fl & 2)
+ {
+ if(fl & 0x80)
+ {
+ WriteCoord(MSG_ENTITY, self.enemy.origin_x);
+ WriteCoord(MSG_ENTITY, self.enemy.origin_y);
+ WriteCoord(MSG_ENTITY, self.enemy.origin_z);
+ }
+ else
+ {
+ WriteAngle(MSG_ENTITY, self.mangle_x);
+ WriteAngle(MSG_ENTITY, self.mangle_y);
+ }
+ }
+ if(fl & 4)
+ WriteByte(MSG_ENTITY, self.state);
+ return 1;
+}
+
+/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
+Any object touching the beam will be hurt
+Keys:
+"target"
+ spawnfunc_target_position where the laser ends
+"mdl"
+ name of beam end effect to use
+"colormod"
+ color of the beam (default: red)
+"dmg"
+ damage per second (-1 for a laser that kills immediately)
+*/
+void laser_use()
+{
+ self.state = !self.state;
+ self.SendFlags |= 4;
+ misc_laser_aim();
+}
+
+void laser_reset()
+{
+ if(self.spawnflags & 1)
+ self.state = 1;
+ else
+ self.state = 0;
+}
+
+void spawnfunc_misc_laser()
+{
+ if(self.mdl)
+ {
+ if(self.mdl == "none")
+ self.cnt = -1;
+ else
+ {
+ self.cnt = particleeffectnum(self.mdl);
+ if(self.cnt < 0)
+ if(self.dmg)
+ self.cnt = particleeffectnum("laser_deadly");
+ }
+ }
+ else if(!self.cnt)
+ {
+ if(self.dmg)
+ self.cnt = particleeffectnum("laser_deadly");
+ else
+ self.cnt = -1;
+ }
+ if(self.cnt < 0)
+ self.cnt = -1;
+
+ if(self.colormod == '0 0 0')
+ if(!self.alpha)
+ self.colormod = '1 0 0';
+ if(self.message == "")
+ self.message = "saw the light";
+ if (self.message2 == "")
+ self.message2 = "was pushed into a laser by";
+ if(!self.scale)
+ self.scale = 1;
+ if(!self.modelscale)
+ self.modelscale = 1;
+ else if(self.modelscale < 0)
+ self.modelscale = 0;
+ self.think = misc_laser_think;
+ self.nextthink = time;
+ InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
+
+ self.mangle = self.angles;
+
+ Net_LinkEntity(self, false, 0, laser_SendEntity);
+
+ IFTARGETED
+ {
+ self.reset = laser_reset;
+ laser_reset();
+ self.use = laser_use;
+ }
+ else
+ self.state = 1;
+}
+#elif defined(CSQC)
+
+// a laser goes from origin in direction angles
+// it has color 'colormod'
+// and stops when something is in the way
+entityclass(Laser);
+class(Laser) .int cnt; // end effect
+class(Laser) .vector colormod;
+class(Laser) .int state; // on-off
+class(Laser) .int count; // flags for the laser
+class(Laser) .vector velocity;
+class(Laser) .float alpha;
+class(Laser) .float scale; // scaling factor of the thickness
+class(Laser) .float modelscale; // scaling factor of the dlight
+
+void Draw_Laser()
+{
+ if(!self.state)
+ return;
+ InterpolateOrigin_Do();
+ if(self.count & 0x80)
+ {
+ if(self.count & 0x10)
+ {
+ trace_endpos = self.velocity;
+ trace_dphitq3surfaceflags = 0;
+ }
+ else
+ traceline(self.origin, self.velocity, 0, self);
+ }
+ else
+ {
+ if(self.count & 0x10)
+ {
+ makevectors(self.angles);
+ trace_endpos = self.origin + v_forward * 1048576;
+ trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
+ }
+ else
+ {
+ makevectors(self.angles);
+ traceline(self.origin, self.origin + v_forward * 32768, 0, self);
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
+ trace_endpos = self.origin + v_forward * 1048576;
+ }
+ }
+ if(self.scale != 0)
+ {
+ if(self.alpha)
+ {
+ Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, self.alpha, DRAWFLAG_NORMAL, view_origin);
+ }
+ else
+ {
+ Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin);
+ }
+ }
+ if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
+ {
+ if(self.cnt >= 0)
+ pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
+ if(self.colormod != '0 0 0' && self.modelscale != 0)
+ adddynamiclight(trace_endpos + trace_plane_normal * 1, self.modelscale, self.colormod * 5);
+ }
+}
+
+void Ent_Laser()
+{
+ InterpolateOrigin_Undo();
+
+ // 30 bytes, or 13 bytes for just moving
+ int f = ReadByte();
+ self.count = (f & 0xF0);
+
+ if(self.count & 0x80)
+ self.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
+ else
+ self.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
+
+ if(f & 1)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+ }
+ if(f & 8)
+ {
+ self.colormod_x = ReadByte() / 255.0;
+ self.colormod_y = ReadByte() / 255.0;
+ self.colormod_z = ReadByte() / 255.0;
+ if(f & 0x40)
+ self.alpha = ReadByte() / 255.0;
+ else
+ self.alpha = 0;
+ self.scale = 2;
+ self.modelscale = 50;
+ if(f & 0x20)
+ {
+ self.scale *= ReadByte() / 16.0; // beam radius
+ self.modelscale *= ReadByte() / 16.0; // dlight radius
+ }
+ if((f & 0x80) || !(f & 0x10))
+ self.cnt = ReadShort() - 1; // effect number
+ else
+ self.cnt = 0;
+ }
+ if(f & 2)
+ {
+ if(f & 0x80)
+ {
+ self.velocity_x = ReadCoord();
+ self.velocity_y = ReadCoord();
+ self.velocity_z = ReadCoord();
+ }
+ else
+ {
+ self.angles_x = ReadAngle();
+ self.angles_y = ReadAngle();
+ }
+ }
+ if(f & 4)
+ self.state = ReadByte();
+ InterpolateOrigin_Note();
+ self.draw = Draw_Laser;
+}
+#endif
--- /dev/null
+#ifdef CSQC
+void Ent_Laser();
+#endif
--- /dev/null
+#ifdef SVQC
+
+void spawnfunc_info_teleport_destination (void)
+{
+ self.classname = "info_teleport_destination";
+
+ self.mangle = self.angles;
+ self.angles = '0 0 0';
+
+ //setorigin (self, self.origin + '0 0 27'); // To fix a mappers' habit as old as Quake
+ setorigin (self, self.origin);
+
+ IFTARGETED
+ {
+ }
+ else
+ objerror ("^3Teleport destination without a targetname");
+}
+
+void spawnfunc_misc_teleporter_dest (void)
+{
+ spawnfunc_info_teleport_destination();
+}
+
+void spawnfunc_target_teleporter (void)
+{
+ spawnfunc_info_teleport_destination();
+}
+
+#endif
--- /dev/null
+void generic_plat_blocked()
+{
+#ifdef SVQC
+ if(self.dmg && other.takedamage != DAMAGE_NO)
+ {
+ if(self.dmgtime2 < time)
+ {
+ Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ self.dmgtime2 = time + self.dmgtime;
+ }
+
+ // Gib dead/dying stuff
+ if(other.deadflag != DEAD_NO)
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ }
+#endif
+}
+
+void plat_spawn_inside_trigger()
+{
+ entity trigger;
+ vector tmin, tmax;
+
+ trigger = spawn();
+ trigger.touch = plat_center_touch;
+ trigger.movetype = MOVETYPE_NONE;
+ trigger.solid = SOLID_TRIGGER;
+ trigger.enemy = self;
+
+#ifdef CSQC
+ trigger.drawmask = MASK_NORMAL;
+ trigger.trigger_touch = plat_center_touch;
+ trigger.draw = trigger_draw_generic;
+#endif
+
+ tmin = self.absmin + '25 25 0';
+ tmax = self.absmax - '25 25 -8';
+ tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
+ if (self.spawnflags & PLAT_LOW_TRIGGER)
+ tmax_z = tmin_z + 8;
+
+ if (self.size_x <= 50)
+ {
+ tmin_x = (self.mins_x + self.maxs_x) / 2;
+ tmax_x = tmin_x + 1;
+ }
+ if (self.size_y <= 50)
+ {
+ tmin_y = (self.mins_y + self.maxs_y) / 2;
+ tmax_y = tmin_y + 1;
+ }
+
+ if(tmin_x < tmax_x)
+ if(tmin_y < tmax_y)
+ if(tmin_z < tmax_z)
+ {
+ setsize (trigger, tmin, tmax);
+ return;
+ }
+
+ // otherwise, something is fishy...
+ remove(trigger);
+ objerror("plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
+}
+
+void plat_hit_top()
+{
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ self.state = 1;
+
+ self.SUB_THINK = plat_go_down;
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 3;
+}
+
+void plat_hit_bottom()
+{
+ sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+ self.state = 2;
+}
+
+void plat_go_down()
+{
+ sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
+ self.state = 3;
+ SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, plat_hit_bottom);
+}
+
+void plat_go_up()
+{
+ sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
+ self.state = 4;
+ SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, plat_hit_top);
+}
+
+void plat_center_touch()
+{
+#ifdef SVQC
+ if (!other.iscreature)
+ return;
+
+ if (other.health <= 0)
+ return;
+#elif defined(CSQC)
+ if (!IS_PLAYER(other))
+ return;
+ if(PHYS_DEAD(other))
+ return;
+#endif
+
+ self = self.enemy;
+ if (self.state == 2)
+ plat_go_up ();
+ else if (self.state == 1)
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 1;
+}
+
+void plat_outside_touch()
+{
+#ifdef SVQC
+ if (!other.iscreature)
+ return;
+
+ if (other.health <= 0)
+ return;
+#elif defined(CSQC)
+ if (!IS_PLAYER(other))
+ return;
+#endif
+
+ self = self.enemy;
+ if (self.state == 1)
+ plat_go_down ();
+}
+
+void plat_trigger_use()
+{
+#ifdef SVQC
+ if (self.think)
+ return; // already activated
+#elif defined(CSQC)
+ if(self.move_think)
+ return;
+#endif
+ plat_go_down();
+}
+
+
+void plat_crush()
+{
+ if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO))
+ { // KIll Kill Kill!!
+#ifdef SVQC
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+#endif
+ }
+ else
+ {
+#ifdef SVQC
+ if((self.dmg) && (other.takedamage != DAMAGE_NO))
+ { // Shall we bite?
+ Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ // Gib dead/dying stuff
+ if(other.deadflag != DEAD_NO)
+ Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ }
+#endif
+
+ if (self.state == 4)
+ plat_go_down ();
+ else if (self.state == 3)
+ plat_go_up ();
+ // when in other states, then the plat_crush event came delayed after
+ // plat state already had changed
+ // this isn't a bug per se!
+ }
+}
+
+void plat_use()
+{
+ self.use = func_null;
+ if (self.state != 4)
+ objerror ("plat_use: not in up state");
+ plat_go_down();
+}
+
+.string sound1, sound2;
+
+void plat_reset()
+{
+ IFTARGETED
+ {
+ setorigin (self, self.pos1);
+ self.state = 4;
+ self.use = plat_use;
+ }
+ else
+ {
+ setorigin (self, self.pos2);
+ self.state = 2;
+ self.use = plat_trigger_use;
+ }
+
+#ifdef SVQC
+ self.SendFlags |= SF_TRIGGER_RESET;
+#endif
+}
+
+.float platmovetype_start_default, platmovetype_end_default;
+bool set_platmovetype(entity e, string s)
+{
+ // sets platmovetype_start and platmovetype_end based on a string consisting of two values
+
+ int n = tokenize_console(s);
+ if(n > 0)
+ e.platmovetype_start = stof(argv(0));
+ else
+ e.platmovetype_start = 0;
+
+ if(n > 1)
+ e.platmovetype_end = stof(argv(1));
+ else
+ e.platmovetype_end = e.platmovetype_start;
+
+ if(n > 2)
+ if(argv(2) == "force")
+ return true; // no checking, return immediately
+
+ if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
+ {
+ objerror("Invalid platform move type; platform would go in reverse, which is not allowed.");
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+#ifndef PLATFORMS_H
+#define PLATFORMS_H
+
+.float dmgtime2;
+
+void() plat_center_touch;
+void() plat_outside_touch;
+void() plat_trigger_use;
+void() plat_go_up;
+void() plat_go_down;
+void() plat_crush;
+const float PLAT_LOW_TRIGGER = 1;
+
+.float dmg;
+
+#endif
--- /dev/null
+void SUB_NullThink(void) { }
+
+void() SUB_CalcMoveDone;
+void() SUB_CalcAngleMoveDone;
+//void() SUB_UseTargets;
+
+/*
+==================
+SUB_Remove
+
+Remove self
+==================
+*/
+void SUB_Remove()
+{
+ remove (self);
+}
+
+/*
+==================
+SUB_Friction
+
+Applies some friction to self
+==================
+*/
+.float friction;
+void SUB_Friction (void)
+{
+ self.SUB_NEXTTHINK = time;
+ if(self.SUB_FLAGS & FL_ONGROUND)
+ self.SUB_VELOCITY = self.SUB_VELOCITY * (1 - frametime * self.friction);
+}
+
+/*
+==================
+SUB_VanishOrRemove
+
+Makes client invisible or removes non-client
+==================
+*/
+void SUB_VanishOrRemove (entity ent)
+{
+ if (IS_CLIENT(ent))
+ {
+ // vanish
+ ent.alpha = -1;
+ ent.effects = 0;
+#ifdef SVQC
+ ent.glow_size = 0;
+ ent.pflags = 0;
+#endif
+ }
+ else
+ {
+ // remove
+ remove (ent);
+ }
+}
+
+void SUB_SetFade_Think (void)
+{
+ if(self.alpha == 0)
+ self.alpha = 1;
+ self.SUB_THINK = SUB_SetFade_Think;
+ self.SUB_NEXTTHINK = time;
+ self.alpha -= frametime * self.fade_rate;
+ if (self.alpha < 0.01)
+ SUB_VanishOrRemove(self);
+ else
+ self.SUB_NEXTTHINK = time;
+}
+
+/*
+==================
+SUB_SetFade
+
+Fade 'ent' out when time >= 'when'
+==================
+*/
+void SUB_SetFade (entity ent, float when, float fading_time)
+{
+ ent.fade_rate = 1/fading_time;
+ ent.SUB_THINK = SUB_SetFade_Think;
+ ent.SUB_NEXTTHINK = when;
+}
+
+/*
+=============
+SUB_CalcMove
+
+calculate self.SUB_VELOCITY and self.SUB_NEXTTHINK to reach dest from
+self.SUB_ORIGIN traveling at speed
+===============
+*/
+void SUB_CalcMoveDone (void)
+{
+ // After moving, set origin to exact final destination
+
+ SUB_SETORIGIN (self, self.finaldest);
+ self.SUB_VELOCITY = '0 0 0';
+ self.SUB_NEXTTHINK = -1;
+ if (self.think1)
+ self.think1 ();
+}
+
+.float platmovetype_turn;
+void SUB_CalcMove_controller_think (void)
+{
+ entity oldself;
+ float traveltime;
+ float phasepos;
+ float nexttick;
+ vector delta;
+ vector delta2;
+ vector veloc;
+ vector angloc;
+ vector nextpos;
+ delta = self.destvec;
+ delta2 = self.destvec2;
+ if(time < self.animstate_endtime)
+ {
+ nexttick = time + PHYS_INPUT_FRAMETIME;
+
+ traveltime = self.animstate_endtime - self.animstate_starttime;
+ phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
+ phasepos = cubic_speedfunc(self.platmovetype_start, self.platmovetype_end, phasepos);
+ nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
+ // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
+
+ if(self.owner.platmovetype_turn)
+ {
+ vector destangle;
+ destangle = delta + 2 * delta2 * phasepos;
+ destangle = vectoangles(destangle);
+ destangle_x = -destangle_x; // flip up / down orientation
+
+ // take the shortest distance for the angles
+ SUB_ANGLES(self.owner)_x -= 360 * floor((SUB_ANGLES(self.owner)_x - destangle_x) / 360 + 0.5);
+ SUB_ANGLES(self.owner)_y -= 360 * floor((SUB_ANGLES(self.owner)_y - destangle_y) / 360 + 0.5);
+ SUB_ANGLES(self.owner)_z -= 360 * floor((SUB_ANGLES(self.owner)_z - destangle_z) / 360 + 0.5);
+ angloc = destangle - SUB_ANGLES(self.owner);
+ angloc = angloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
+ self.owner.SUB_AVELOCITY = angloc;
+ }
+ if(nexttick < self.animstate_endtime)
+ veloc = nextpos - self.owner.SUB_ORIGIN;
+ else
+ veloc = self.finaldest - self.owner.SUB_ORIGIN;
+ veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
+
+ self.owner.SUB_VELOCITY = veloc;
+ self.nextthink = nexttick;
+ }
+ else
+ {
+ // derivative: delta + 2 * delta2 (e.g. for angle positioning)
+ oldself = self;
+ self.owner.SUB_THINK = self.think1;
+ self = self.owner;
+ remove(oldself);
+ self.SUB_THINK();
+ }
+}
+
+void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
+{
+ // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
+ // 2 * control * t - 2 * control * t * t + destin * t * t
+ // 2 * control * t + (destin - 2 * control) * t * t
+
+ setorigin(controller, org);
+ control -= org;
+ destin -= org;
+
+ controller.destvec = 2 * control; // control point
+ controller.destvec2 = destin - 2 * control; // quadratic part required to reach end point
+ // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (destin - control)
+}
+
+void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
+{
+ // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
+ // 2 * control * t - 2 * control * t * t + destin * t * t
+ // 2 * control * t + (destin - 2 * control) * t * t
+
+ setorigin(controller, org);
+ destin -= org;
+
+ controller.destvec = destin; // end point
+ controller.destvec2 = '0 0 0';
+}
+
+float TSPEED_TIME = -1;
+float TSPEED_LINEAR = 0;
+float TSPEED_START = 1;
+float TSPEED_END = 2;
+// TODO average too?
+
+void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
+{
+ float traveltime;
+ entity controller;
+
+ if (!tspeed)
+ objerror ("No speed is defined!");
+
+ self.think1 = func;
+ self.finaldest = tdest;
+ self.SUB_THINK = SUB_CalcMoveDone;
+
+ switch(tspeedtype)
+ {
+ default:
+ case TSPEED_START:
+ traveltime = 2 * vlen(tcontrol - self.SUB_ORIGIN) / tspeed;
+ break;
+ case TSPEED_END:
+ traveltime = 2 * vlen(tcontrol - tdest) / tspeed;
+ break;
+ case TSPEED_LINEAR:
+ traveltime = vlen(tdest - self.SUB_ORIGIN) / tspeed;
+ break;
+ case TSPEED_TIME:
+ traveltime = tspeed;
+ break;
+ }
+
+ if (traveltime < 0.1) // useless anim
+ {
+ self.SUB_VELOCITY = '0 0 0';
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
+ return;
+ }
+
+ controller = spawn();
+ controller.classname = "SUB_CalcMove_controller";
+ controller.owner = self;
+ controller.platmovetype = self.platmovetype;
+ controller.platmovetype_start = self.platmovetype_start;
+ controller.platmovetype_end = self.platmovetype_end;
+ SUB_CalcMove_controller_setbezier(controller, self.SUB_ORIGIN, tcontrol, tdest);
+ controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
+ controller.animstate_starttime = time;
+ controller.animstate_endtime = time + traveltime;
+ controller.think = SUB_CalcMove_controller_think;
+ controller.think1 = self.SUB_THINK;
+
+ // the thinking is now done by the controller
+ self.SUB_THINK = SUB_NullThink; // for PushMove
+ self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
+
+ // invoke controller
+ self = controller;
+ self.think();
+ self = self.owner;
+}
+
+void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
+{
+ vector delta;
+ float traveltime;
+
+ if (!tspeed)
+ objerror ("No speed is defined!");
+
+ self.think1 = func;
+ self.finaldest = tdest;
+ self.SUB_THINK = SUB_CalcMoveDone;
+
+ if (tdest == self.SUB_ORIGIN)
+ {
+ self.SUB_VELOCITY = '0 0 0';
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
+ return;
+ }
+
+ delta = tdest - self.SUB_ORIGIN;
+
+ switch(tspeedtype)
+ {
+ default:
+ case TSPEED_START:
+ case TSPEED_END:
+ case TSPEED_LINEAR:
+ traveltime = vlen (delta) / tspeed;
+ break;
+ case TSPEED_TIME:
+ traveltime = tspeed;
+ break;
+ }
+
+ // Very short animations don't really show off the effect
+ // of controlled animation, so let's just use linear movement.
+ // Alternatively entities can choose to specify non-controlled movement.
+ // The only currently implemented alternative movement is linear (value 1)
+ if (traveltime < 0.15 || (self.platmovetype_start == 1 && self.platmovetype_end == 1)) // is this correct?
+ {
+ self.SUB_VELOCITY = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
+ self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
+ return;
+ }
+
+ // now just run like a bezier curve...
+ SUB_CalcMove_Bezier((self.SUB_ORIGIN + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
+}
+
+void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
+{
+ entity oldself;
+
+ oldself = self;
+ self = ent;
+
+ SUB_CalcMove (tdest, tspeedtype, tspeed, func);
+
+ self = oldself;
+}
+
+/*
+=============
+SUB_CalcAngleMove
+
+calculate self.SUB_AVELOCITY and self.SUB_NEXTTHINK to reach destangle from
+self.angles rotating
+
+The calling function should make sure self.SUB_THINK is valid
+===============
+*/
+void SUB_CalcAngleMoveDone (void)
+{
+ // After rotating, set angle to exact final angle
+ self.angles = self.finalangle;
+ self.SUB_AVELOCITY = '0 0 0';
+ self.SUB_NEXTTHINK = -1;
+ if (self.think1)
+ self.think1 ();
+}
+
+// FIXME: I fixed this function only for rotation around the main axes
+void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
+{
+ vector delta;
+ float traveltime;
+
+ if (!tspeed)
+ objerror ("No speed is defined!");
+
+ // take the shortest distance for the angles
+ self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
+ self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
+ self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
+ delta = destangle - self.angles;
+
+ switch(tspeedtype)
+ {
+ default:
+ case TSPEED_START:
+ case TSPEED_END:
+ case TSPEED_LINEAR:
+ traveltime = vlen (delta) / tspeed;
+ break;
+ case TSPEED_TIME:
+ traveltime = tspeed;
+ break;
+ }
+
+ self.think1 = func;
+ self.finalangle = destangle;
+ self.SUB_THINK = SUB_CalcAngleMoveDone;
+
+ if (traveltime < 0.1)
+ {
+ self.SUB_AVELOCITY = '0 0 0';
+ self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
+ return;
+ }
+
+ self.SUB_AVELOCITY = delta * (1 / traveltime);
+ self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
+}
+
+void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
+{
+ entity oldself;
+
+ oldself = self;
+ self = ent;
+
+ SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);
+
+ self = oldself;
+}
--- /dev/null
+#ifndef SUBS_H
+#define SUBS_H
+
+#ifdef SVQC
+
+ #define SUB_ANGLES(s) (s).angles
+ #define SUB_VELOCITY velocity
+ #define SUB_AVELOCITY avelocity
+ #define SUB_ORIGIN origin
+ #define SUB_SETORIGIN(s,v) setorigin((s), (v))
+ #define SUB_NEXTTHINK nextthink
+ #define SUB_THINK think
+ #define SUB_LTIME ltime
+ #define SUB_FLAGS flags
+
+#elif defined(CSQC)
+
+ void _Movetype_LinkEdict(float touch_triggers);
+
+ #define SUB_ANGLES(s) (s).move_angles
+ #define SUB_VELOCITY move_velocity
+ #define SUB_AVELOCITY move_avelocity
+ #define SUB_ORIGIN move_origin
+ #define SUB_NEXTTHINK move_nextthink
+ #define SUB_THINK move_think
+ #define SUB_LTIME move_ltime
+ #define SUB_FLAGS move_flags
+
+ void SUB_SETORIGIN(entity s, vector v)
+ {
+ s.move_origin = v;
+ entity oldself = self;
+ self = s;
+ _Movetype_LinkEdict(true);
+ self = oldself;
+ }
+
+#endif
+
+void SUB_Remove();
+void SUB_SetFade (entity ent, float when, float fading_time);
+void SUB_VanishOrRemove (entity ent);
+
+.vector finaldest, finalangle; //plat.qc stuff
+.void() think1;
+.float state;
+.float t_length, t_width;
+
+.vector destvec;
+.vector destvec2;
+
+// player animation state
+.float animstate_startframe;
+.float animstate_numframes;
+.float animstate_framerate;
+.float animstate_starttime;
+.float animstate_endtime;
+.float animstate_override;
+.float animstate_looping;
+
+.float delay;
+.float wait;
+.float lip;
+.float speed;
+.float sounds;
+.string platmovetype;
+.float platmovetype_start, platmovetype_end;
+
+entity activator;
+
+.string killtarget;
+
+.vector pos1, pos2;
+.vector mangle;
+
+.string target2;
+.string target3;
+.string target4;
+.string curvetarget;
+.float target_random;
+.float trigger_reverse;
+
+// Keys player is holding
+.float itemkeys;
+// message delay for func_door locked by keys and key locks
+// this field is used on player entities
+.float key_door_messagetime;
+
+.vector dest1, dest2;
+
+#ifdef CSQC
+// this stuff is defined in the server side engine VM, so we must define it separately here
+.float takedamage;
+const float DAMAGE_NO = 0;
+const float DAMAGE_YES = 1;
+const float DAMAGE_AIM = 2;
+
+float STATE_TOP = 0;
+float STATE_BOTTOM = 1;
+float STATE_UP = 2;
+float STATE_DOWN = 3;
+
+.string noise, noise1, noise2, noise3; // contains names of wavs to play
+
+.float max_health; // players maximum health is stored here
+#endif
+
+#endif
--- /dev/null
+#ifdef SVQC
+.string chmap, gametype;
+void spawnfunc_target_changelevel_use()
+{
+ if(self.gametype != "")
+ MapInfo_SwitchGameType(MapInfo_Type_FromString(self.gametype));
+
+ if (self.chmap == "")
+ localcmd("endmatch\n");
+ else
+ localcmd(strcat("changelevel ", self.chmap, "\n"));
+}
+
+void spawnfunc_target_changelevel()
+{
+ self.use = spawnfunc_target_changelevel_use;
+}
+#endif
--- /dev/null
+#include "include.qh"
+
+#include "changelevel.qc"
+#include "location.qc"
+#include "music.qc"
+#include "spawn.qc"
+#include "speaker.qc"
+#include "voicescript.qc"
--- /dev/null
+#ifndef TRIGGERS_TARGET_INCLUDE_H
+#define TRIGGERS_TARGET_INCLUDE_H
+
+#include "music.qh"
+
+#endif
--- /dev/null
+#ifdef SVQC
+void spawnfunc_target_location()
+{
+ self.classname = "target_location";
+ // location name in netname
+ // eventually support: count, teamgame selectors, line of sight?
+}
+
+void spawnfunc_info_location()
+{
+ self.classname = "target_location";
+ self.message = self.netname;
+}
+#endif
--- /dev/null
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../../server/_all.qh"
+ #include "../../constants.qh"
+ #include "../../../server/constants.qh"
+ #include "../../../server/defs.qh"
+#endif
+
+#ifdef SVQC
+
+// values:
+// volume
+// noise
+// targetname
+// lifetime
+// fade_time
+// fade_rate
+// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
+// when targetname is not set, THIS ONE is default
+void target_music_sendto(float to, float is)
+{
+ WriteByte(to, SVC_TEMPENTITY);
+ WriteByte(to, TE_CSQC_TARGET_MUSIC);
+ WriteShort(to, num_for_edict(self));
+ WriteByte(to, self.volume * 255.0 * is);
+ WriteByte(to, self.fade_time * 16.0);
+ WriteByte(to, self.fade_rate * 16.0);
+ WriteByte(to, self.lifetime);
+ WriteString(to, self.noise);
+}
+void target_music_reset()
+{
+ if(self.targetname == "")
+ target_music_sendto(MSG_ALL, 1);
+}
+void target_music_use()
+{
+ if(!activator)
+ return;
+ if(IS_REAL_CLIENT(activator))
+ {
+ msg_entity = activator;
+ target_music_sendto(MSG_ONE, 1);
+ }
+ entity head;
+ FOR_EACH_SPEC(head) if(head.enemy == activator) { msg_entity = head; target_music_sendto(MSG_ONE, 1); }
+}
+void spawnfunc_target_music()
+{
+ self.use = target_music_use;
+ self.reset = target_music_reset;
+ if(!self.volume)
+ self.volume = 1;
+ if(self.targetname == "")
+ target_music_sendto(MSG_INIT, 1);
+ else
+ target_music_sendto(MSG_INIT, 0);
+}
+void TargetMusic_RestoreGame()
+{
+ for(self = world; (self = find(self, classname, "target_music")); )
+ {
+ if(self.targetname == "")
+ target_music_sendto(MSG_INIT, 1);
+ else
+ target_music_sendto(MSG_INIT, 0);
+ }
+}
+// values:
+// volume
+// noise
+// targetname
+// fade_time
+// spawnflags:
+// 1 = START_OFF
+// when triggered, it is disabled/enabled for everyone
+float trigger_music_SendEntity(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
+ sf &= ~0x80;
+ if(self.cnt)
+ sf |= 0x80;
+ WriteByte(MSG_ENTITY, sf);
+ if(sf & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.origin.x);
+ WriteCoord(MSG_ENTITY, self.origin.y);
+ WriteCoord(MSG_ENTITY, self.origin.z);
+ }
+ if(sf & 1)
+ {
+ if(self.model != "null")
+ {
+ WriteShort(MSG_ENTITY, self.modelindex);
+ WriteCoord(MSG_ENTITY, self.mins.x);
+ WriteCoord(MSG_ENTITY, self.mins.y);
+ WriteCoord(MSG_ENTITY, self.mins.z);
+ WriteCoord(MSG_ENTITY, self.maxs.x);
+ WriteCoord(MSG_ENTITY, self.maxs.y);
+ WriteCoord(MSG_ENTITY, self.maxs.z);
+ }
+ else
+ {
+ WriteShort(MSG_ENTITY, 0);
+ WriteCoord(MSG_ENTITY, self.maxs.x);
+ WriteCoord(MSG_ENTITY, self.maxs.y);
+ WriteCoord(MSG_ENTITY, self.maxs.z);
+ }
+ WriteByte(MSG_ENTITY, self.volume * 255.0);
+ WriteByte(MSG_ENTITY, self.fade_time * 16.0);
+ WriteByte(MSG_ENTITY, self.fade_rate * 16.0);
+ WriteString(MSG_ENTITY, self.noise);
+ }
+ return 1;
+}
+void trigger_music_reset()
+{
+ self.cnt = !(self.spawnflags & 1);
+ self.SendFlags |= 0x80;
+}
+void trigger_music_use()
+{
+ self.cnt = !self.cnt;
+ self.SendFlags |= 0x80;
+}
+void spawnfunc_trigger_music()
+{
+ if(self.model != "")
+ setmodel(self, self.model);
+ if(!self.volume)
+ self.volume = 1;
+ if(!self.modelindex)
+ {
+ setorigin(self, self.origin + self.mins);
+ setsize(self, '0 0 0', self.maxs - self.mins);
+ }
+ trigger_music_reset();
+
+ self.use = trigger_music_use;
+ self.reset = trigger_music_reset;
+
+ Net_LinkEntity(self, false, 0, trigger_music_SendEntity);
+}
+#elif defined(CSQC)
+
+void TargetMusic_Advance()
+{
+ // run AFTER all the thinks!
+ entity best, e;
+ float vol, vol0;
+ best = music_default;
+ if(music_target && time < music_target.lifetime)
+ best = music_target;
+ if(music_trigger)
+ best = music_trigger;
+ for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); ) if(e.noise)
+ {
+ vol0 = e.lastvol;
+ if(getsoundtime(e, CH_BGM_SINGLE) < 0)
+ {
+ vol0 = -1;
+ }
+ if(e == best)
+ {
+ // increase volume
+ if(e.fade_time > 0)
+ e.state = bound(0, e.state + frametime / e.fade_time, 1);
+ else
+ e.state = 1;
+ }
+ else
+ {
+ // decrease volume
+ if(e.fade_rate > 0)
+ e.state = bound(0, e.state - frametime / e.fade_rate, 1);
+ else
+ e.state = 0;
+ }
+ vol = e.state * e.volume * autocvar_bgmvolume;
+ if(vol != vol0)
+ {
+ if(vol0 < 0)
+ sound(e, CH_BGM_SINGLE, e.noise, vol, ATTEN_NONE); // restart
+ else
+ sound(e, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
+ e.lastvol = vol;
+ }
+ }
+ music_trigger = world;
+
+ if(best)
+ bgmtime = getsoundtime(best, CH_BGM_SINGLE);
+ else
+ bgmtime = gettime(GETTIME_CDTRACK);
+}
+
+void Net_TargetMusic()
+{
+ int id = ReadShort();
+ float vol = ReadByte() / 255.0;
+ float fai = ReadByte() / 16.0;
+ float fao = ReadByte() / 16.0;
+ float tim = ReadByte();
+ string noi = ReadString();
+
+ entity e;
+ for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); )
+ {
+ if(e.count == id)
+ break;
+ }
+ if(!e)
+ {
+ e = spawn();
+ e.enttype = ENT_CLIENT_TRIGGER_MUSIC;
+ e.count = id;
+ }
+ if(e.noise != noi)
+ {
+ if(e.noise)
+ strunzone(e.noise);
+ e.noise = strzone(noi);
+ precache_sound(e.noise);
+ sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
+ if(getsoundtime(e, CH_BGM_SINGLE) < 0)
+ {
+ dprintf("Cannot initialize sound %s\n", e.noise);
+ strunzone(e.noise);
+ e.noise = string_null;
+ }
+ }
+ e.volume = vol;
+ e.fade_time = fai;
+ e.fade_rate = fao;
+ if(vol > 0)
+ {
+ if(tim == 0)
+ {
+ music_default = e;
+ if(!music_disabled)
+ {
+ e.state = 2;
+ cvar_settemp("music_playlist_index", "-1"); // don't use playlists
+ localcmd("cd stop\n"); // just in case
+ music_disabled = 1;
+ }
+ }
+ else
+ {
+ music_target = e;
+ e.lifetime = time + tim;
+ }
+ }
+}
+
+void Ent_TriggerMusic_Think()
+{
+ if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, self, world))
+ {
+ music_trigger = self;
+ }
+ self.nextthink = time;
+}
+
+void Ent_TriggerMusic_Remove()
+{
+ if(self.noise)
+ strunzone(self.noise);
+ self.noise = string_null;
+}
+
+void Ent_ReadTriggerMusic()
+{
+ int f = ReadByte();
+ if(f & 4)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ }
+ if(f & 1)
+ {
+ self.modelindex = ReadShort();
+ if(self.modelindex)
+ {
+ self.mins_x = ReadCoord();
+ self.mins_y = ReadCoord();
+ self.mins_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ }
+ else
+ {
+ self.mins = '0 0 0';
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ }
+
+ self.volume = ReadByte() / 255.0;
+ self.fade_time = ReadByte() / 16.0;
+ self.fade_rate = ReadByte() / 16.0;
+ string s = self.noise;
+ if(self.noise)
+ strunzone(self.noise);
+ self.noise = strzone(ReadString());
+ if(self.noise != s)
+ {
+ precache_sound(self.noise);
+ sound(self, CH_BGM_SINGLE, self.noise, 0, ATTEN_NONE);
+ if(getsoundtime(self, CH_BGM_SINGLE) < 0)
+ {
+ dprintf("Cannot initialize sound %s\n", self.noise);
+ strunzone(self.noise);
+ self.noise = string_null;
+ }
+ }
+ }
+
+ setorigin(self, self.origin);
+ setsize(self, self.mins, self.maxs);
+ self.cnt = 1;
+ self.think = Ent_TriggerMusic_Think;
+ self.nextthink = time;
+}
+
+#endif
--- /dev/null
+#ifndef TARGET_MUSIC_H
+#define TARGET_MUSIC_H
+
+.float lifetime;
+
+#ifdef CSQC
+float music_disabled;
+entity music_default;
+entity music_target;
+entity music_trigger;
+// FIXME also control bgmvolume here, to not require a target_music for the default track.
+
+entityclass(TargetMusic);
+class(TargetMusic) .int state;
+class(TargetMusic) .float lastvol;
+
+void TargetMusic_Advance();
+
+void Net_TargetMusic();
+
+void Ent_TriggerMusic_Think();
+
+void Ent_TriggerMusic_Remove();
+
+void Ent_ReadTriggerMusic();
+#endif
+
+#endif
--- /dev/null
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../../server/_all.qh"
+ #include "../../util.qh"
+ #include "../../../server/defs.qh"
+#endif
+
+#ifdef SVQC
+
+// spawner entity
+// "classname" "target_spawn"
+// "message" "fieldname value fieldname value ..."
+// "spawnflags"
+// 1 = call the spawn function
+// 2 = trigger on map load
+
+float target_spawn_initialized;
+.void() target_spawn_spawnfunc;
+float target_spawn_spawnfunc_field;
+.entity target_spawn_activator;
+.float target_spawn_id;
+float target_spawn_count;
+
+void target_spawn_helper_setmodel()
+{
+ setmodel(self, self.model);
+}
+
+void target_spawn_helper_setsize()
+{
+ setsize(self, self.mins, self.maxs);
+}
+
+void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
+{
+ float i, n, valuefieldpos;
+ string key, value, valuefield, valueoffset, valueoffsetrandom;
+ entity valueent;
+ vector data, data2;
+ entity oldself;
+ entity oldactivator;
+
+ n = tokenize_console(msg);
+
+ for(i = 0; i < n-1; i += 2)
+ {
+ key = argv(i);
+ value = argv(i+1);
+ if(key == "$")
+ {
+ data.x = -1;
+ data.y = FIELD_STRING;
+ }
+ else
+ {
+ data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
+ if(data.y == 0) // undefined field, i.e., invalid type
+ {
+ print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
+ continue;
+ }
+ }
+ if(substring(value, 0, 1) == "$")
+ {
+ value = substring(value, 1, strlen(value) - 1);
+ if(substring(value, 0, 1) == "$")
+ {
+ // deferred replacement
+ // do nothing
+ // useful for creating target_spawns with this!
+ }
+ else
+ {
+ // replace me!
+ valuefieldpos = strstrofs(value, "+", 0);
+ valueoffset = "";
+ if(valuefieldpos != -1)
+ {
+ valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
+ value = substring(value, 0, valuefieldpos);
+ }
+
+ valuefieldpos = strstrofs(valueoffset, "+", 0);
+ valueoffsetrandom = "";
+ if(valuefieldpos != -1)
+ {
+ valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
+ valueoffset = substring(valueoffset, 0, valuefieldpos);
+ }
+
+ valuefieldpos = strstrofs(value, ".", 0);
+ valuefield = "";
+ if(valuefieldpos != -1)
+ {
+ valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
+ value = substring(value, 0, valuefieldpos);
+ }
+
+ if(value == "self")
+ {
+ valueent = self;
+ value = "";
+ }
+ else if(value == "activator")
+ {
+ valueent = act;
+ value = "";
+ }
+ else if(value == "other")
+ {
+ valueent = other;
+ value = "";
+ }
+ else if(value == "pusher")
+ {
+ if(time < act.pushltime)
+ valueent = act.pusher;
+ else
+ valueent = world;
+ value = "";
+ }
+ else if(value == "target")
+ {
+ valueent = e;
+ value = "";
+ }
+ else if(value == "killtarget")
+ {
+ valueent = kt;
+ value = "";
+ }
+ else if(value == "target2")
+ {
+ valueent = t2;
+ value = "";
+ }
+ else if(value == "target3")
+ {
+ valueent = t3;
+ value = "";
+ }
+ else if(value == "target4")
+ {
+ valueent = t4;
+ value = "";
+ }
+ else if(value == "time")
+ {
+ valueent = world;
+ value = ftos(time);
+ }
+ else
+ {
+ print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
+ continue;
+ }
+
+ if(valuefield == "")
+ {
+ if(value == "")
+ value = ftos(num_for_edict(valueent));
+ }
+ else
+ {
+ if(value != "")
+ {
+ print("target_spawn: try to get a field of a non-entity, ignored!\n");
+ continue;
+ }
+ data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
+ if(data2_y == 0) // undefined field, i.e., invalid type
+ {
+ print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
+ continue;
+ }
+ value = getentityfieldstring(data2_x, valueent);
+ }
+
+ if(valueoffset != "")
+ {
+ switch(data.y)
+ {
+ case FIELD_STRING:
+ value = strcat(value, valueoffset);
+ break;
+ case FIELD_FLOAT:
+ value = ftos(stof(value) + stof(valueoffset));
+ break;
+ case FIELD_VECTOR:
+ value = vtos(stov(value) + stov(valueoffset));
+ break;
+ default:
+ print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
+ break;
+ }
+ }
+
+ if(valueoffsetrandom != "")
+ {
+ switch(data.y)
+ {
+ case FIELD_FLOAT:
+ value = ftos(stof(value) + random() * stof(valueoffsetrandom));
+ break;
+ case FIELD_VECTOR:
+ data2 = stov(valueoffsetrandom);
+ value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
+ break;
+ default:
+ print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
+ break;
+ }
+ }
+ }
+ }
+ if(key == "$")
+ {
+ if(substring(value, 0, 1) == "_")
+ value = strcat("target_spawn_helper", value);
+ putentityfieldstring(target_spawn_spawnfunc_field, e, value);
+
+ oldself = self;
+ oldactivator = activator;
+
+ self = e;
+ activator = act;
+
+ self.target_spawn_spawnfunc();
+
+ self = oldself;
+ activator = oldactivator;
+
+ // We called an external function, so we have to re-tokenize msg.
+ n = tokenize_console(msg);
+ }
+ else
+ {
+ if(data.y == FIELD_VECTOR)
+ value = strreplace("'", "", value); // why?!?
+ putentityfieldstring(data.x, e, value);
+ }
+ }
+}
+
+void target_spawn_useon(entity e)
+{
+ self.target_spawn_activator = activator;
+ target_spawn_edit_entity(
+ e,
+ self.message,
+ find(world, targetname, self.killtarget),
+ find(world, targetname, self.target2),
+ find(world, targetname, self.target3),
+ find(world, targetname, self.target4),
+ activator
+ );
+}
+
+float target_spawn_cancreate()
+{
+ float c;
+ entity e;
+
+ c = self.count;
+ if(c == 0) // no limit?
+ return 1;
+
+ ++c; // increase count to not include MYSELF
+ for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
+ ;
+
+ // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
+ if(c == 0)
+ return 0;
+ return 1;
+}
+
+void target_spawn_use()
+{
+ entity e;
+
+ if(self.target == "")
+ {
+ // spawn new entity
+ if(!target_spawn_cancreate())
+ return;
+ e = spawn();
+ target_spawn_useon(e);
+ e.target_spawn_id = self.target_spawn_id;
+ }
+ else if(self.target == "*activator")
+ {
+ // edit entity
+ if(activator)
+ target_spawn_useon(activator);
+ }
+ else
+ {
+ // edit entity
+ for(e = world; (e = find(e, targetname, self.target)); )
+ target_spawn_useon(e);
+ }
+}
+
+void target_spawn_spawnfirst()
+{
+ activator = self.target_spawn_activator;
+ if(self.spawnflags & 2)
+ target_spawn_use();
+}
+
+void initialize_field_db()
+{
+ if(!target_spawn_initialized)
+ {
+ float n, i;
+ string fn;
+ vector prev, next;
+ float ft;
+
+ n = numentityfields();
+ for(i = 0; i < n; ++i)
+ {
+ fn = entityfieldname(i);
+ ft = entityfieldtype(i);
+ next = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
+ prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
+ if(prev.y == 0)
+ {
+ db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(next));
+ if(fn == "target_spawn_spawnfunc")
+ target_spawn_spawnfunc_field = i;
+ }
+ }
+
+ target_spawn_initialized = 1;
+ }
+}
+
+void spawnfunc_target_spawn()
+{
+ initialize_field_db();
+ self.use = target_spawn_use;
+ self.message = strzone(strreplace("'", "\"", self.message));
+ self.target_spawn_id = ++target_spawn_count;
+ InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
+}
+#endif
--- /dev/null
+#ifdef SVQC
+// TODO add a way to do looped sounds with sound(); then complete this entity
+void target_speaker_use_off();
+void target_speaker_use_activator()
+{
+ if (!IS_REAL_CLIENT(activator))
+ return;
+ string snd;
+ if(substring(self.noise, 0, 1) == "*")
+ {
+ var .string sample;
+ sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
+ if(GetPlayerSoundSampleField_notFound)
+ snd = "misc/null.wav";
+ else if(activator.sample == "")
+ snd = "misc/null.wav";
+ else
+ {
+ tokenize_console(activator.sample);
+ float n;
+ n = stof(argv(1));
+ if(n > 0)
+ snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+ else
+ snd = strcat(argv(0), ".wav"); // randomization
+ }
+ }
+ else
+ snd = self.noise;
+ msg_entity = activator;
+ soundto(MSG_ONE, self, CH_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
+}
+void target_speaker_use_on()
+{
+ string snd;
+ if(substring(self.noise, 0, 1) == "*")
+ {
+ var .string sample;
+ sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
+ if(GetPlayerSoundSampleField_notFound)
+ snd = "misc/null.wav";
+ else if(activator.sample == "")
+ snd = "misc/null.wav";
+ else
+ {
+ tokenize_console(activator.sample);
+ float n;
+ n = stof(argv(1));
+ if(n > 0)
+ snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+ else
+ snd = strcat(argv(0), ".wav"); // randomization
+ }
+ }
+ else
+ snd = self.noise;
+ sound(self, CH_TRIGGER_SINGLE, snd, VOL_BASE * self.volume, self.atten);
+ if(self.spawnflags & 3)
+ self.use = target_speaker_use_off;
+}
+void target_speaker_use_off()
+{
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASE * self.volume, self.atten);
+ self.use = target_speaker_use_on;
+}
+void target_speaker_reset()
+{
+ if(self.spawnflags & 1) // LOOPED_ON
+ {
+ if(self.use == target_speaker_use_on)
+ target_speaker_use_on();
+ }
+ else if(self.spawnflags & 2)
+ {
+ if(self.use == target_speaker_use_off)
+ target_speaker_use_off();
+ }
+}
+
+void spawnfunc_target_speaker()
+{
+ // TODO: "*" prefix to sound file name
+ // TODO: wait and random (just, HOW? random is not a field)
+ if(self.noise)
+ precache_sound (self.noise);
+
+ if(!self.atten && !(self.spawnflags & 4))
+ {
+ IFTARGETED
+ self.atten = ATTEN_NORM;
+ else
+ self.atten = ATTEN_STATIC;
+ }
+ else if(self.atten < 0)
+ self.atten = 0;
+
+ if(!self.volume)
+ self.volume = 1;
+
+ IFTARGETED
+ {
+ if(self.spawnflags & 8) // ACTIVATOR
+ self.use = target_speaker_use_activator;
+ else if(self.spawnflags & 1) // LOOPED_ON
+ {
+ target_speaker_use_on();
+ self.reset = target_speaker_reset;
+ }
+ else if(self.spawnflags & 2) // LOOPED_OFF
+ {
+ self.use = target_speaker_use_on;
+ self.reset = target_speaker_reset;
+ }
+ else
+ self.use = target_speaker_use_on;
+ }
+ else if(self.spawnflags & 1) // LOOPED_ON
+ {
+ ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
+ remove(self);
+ }
+ else if(self.spawnflags & 2) // LOOPED_OFF
+ {
+ objerror("This sound entity can never be activated");
+ }
+ else
+ {
+ // Quake/Nexuiz fallback
+ ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
+ remove(self);
+ }
+}
+#endif
--- /dev/null
+#ifdef SVQC
+.entity voicescript; // attached voice script
+.float voicescript_index; // index of next voice, or -1 to use the randomized ones
+.float voicescript_nextthink; // time to play next voice
+.float voicescript_voiceend; // time when this voice ends
+
+void target_voicescript_clear(entity pl)
+{
+ pl.voicescript = world;
+}
+
+void target_voicescript_use()
+{
+ if(activator.voicescript != self)
+ {
+ activator.voicescript = self;
+ activator.voicescript_index = 0;
+ activator.voicescript_nextthink = time + self.delay;
+ }
+}
+
+void target_voicescript_next(entity pl)
+{
+ entity vs;
+ float i, n, dt;
+
+ vs = pl.voicescript;
+ if(!vs)
+ return;
+ if(vs.message == "")
+ return;
+ if (!IS_PLAYER(pl))
+ return;
+ if(gameover)
+ return;
+
+ if(time >= pl.voicescript_voiceend)
+ {
+ if(time >= pl.voicescript_nextthink)
+ {
+ // get the next voice...
+ n = tokenize_console(vs.message);
+
+ if(pl.voicescript_index < vs.cnt)
+ i = pl.voicescript_index * 2;
+ else if(n > vs.cnt * 2)
+ i = ((pl.voicescript_index - vs.cnt) % ((n - vs.cnt * 2 - 1) / 2)) * 2 + vs.cnt * 2 + 1;
+ else
+ i = -1;
+
+ if(i >= 0)
+ {
+ play2(pl, strcat(vs.netname, "/", argv(i), ".wav"));
+ dt = stof(argv(i + 1));
+ if(dt >= 0)
+ {
+ pl.voicescript_voiceend = time + dt;
+ pl.voicescript_nextthink = pl.voicescript_voiceend + vs.wait * (0.5 + random());
+ }
+ else
+ {
+ pl.voicescript_voiceend = time - dt;
+ pl.voicescript_nextthink = pl.voicescript_voiceend;
+ }
+
+ pl.voicescript_index += 1;
+ }
+ else
+ {
+ pl.voicescript = world; // stop trying then
+ }
+ }
+ }
+}
+
+void spawnfunc_target_voicescript()
+{
+ // netname: directory of the sound files
+ // message: list of "sound file" duration "sound file" duration, a *, and again a list
+ // foo1 4.1 foo2 4.0 foo3 -3.1 * fool1 1.1 fool2 7.1 fool3 9.1 fool4 3.7
+ // Here, a - in front of the duration means that no delay is to be
+ // added after this message
+ // wait: average time between messages
+ // delay: initial delay before the first message
+
+ float i, n;
+ self.use = target_voicescript_use;
+
+ n = tokenize_console(self.message);
+ self.cnt = n / 2;
+ for(i = 0; i+1 < n; i += 2)
+ {
+ if(argv(i) == "*")
+ {
+ self.cnt = i / 2;
+ ++i;
+ }
+ precache_sound(strcat(self.netname, "/", argv(i), ".wav"));
+ }
+}
+#endif
--- /dev/null
+#include "teleporters.qh"
+
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../server/_all.qh"
+ #include "../../warpzonelib/common.qh"
+ #include "../../warpzonelib/util_server.qh"
+ #include "../../warpzonelib/server.qh"
+ #include "../constants.qh"
+ #include "../triggers/subs.qh"
+ #include "../util.qh"
+ #include "../../server/weapons/csqcprojectile.qh"
+ #include "../../server/autocvars.qh"
+ #include "../../server/constants.qh"
+ #include "../../server/defs.qh"
+ #include "../deathtypes.qh"
+ #include "../../server/tturrets/include/turrets_early.qh"
+ #include "../../server/vehicles/all.qh"
+ #include "../mapinfo.qh"
+ #include "../../server/anticheat.qh"
+#endif
+
+#ifdef SVQC
+
+float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
+{
+ if (IS_PLAYER(player) && player.health >= 1)
+ {
+ TDEATHLOOP(org)
+ {
+ if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+ if(IS_PLAYER(head))
+ if(head.health >= 1)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
+{
+ TDEATHLOOP(player.origin)
+ {
+ if (IS_PLAYER(player) && player.health >= 1)
+ {
+ if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+ {
+ if(IS_PLAYER(head))
+ if(head.health >= 1)
+ ++tdeath_hit;
+ Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG, head.origin, '0 0 0');
+ }
+ }
+ else // dead bodies and monsters gib themselves instead of telefragging
+ Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG, telefragger.origin, '0 0 0');
+ }
+}
+
+void spawn_tdeath(vector v0, entity e, vector v)
+{
+ tdeath(e, e, e, '0 0 0', '0 0 0');
+}
+
+void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
+{
+ entity telefragger;
+ vector from;
+
+ if(teleporter.owner)
+ telefragger = teleporter.owner;
+ else
+ telefragger = player;
+
+ makevectors (to_angles);
+
+ if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
+ {
+ if(self.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
+ {
+ if(tflags & TELEPORT_FLAG_SOUND)
+ sound (player, CH_TRIGGER, "misc/teleport.wav", VOL_BASE, ATTEN_NORM);
+ if(tflags & TELEPORT_FLAG_PARTICLES)
+ {
+ pointparticles(particleeffectnum("teleport"), player.origin, '0 0 0', 1);
+ pointparticles(particleeffectnum("teleport"), to + v_forward * 32, '0 0 0', 1);
+ }
+ self.pushltime = time + 0.2;
+ }
+ }
+
+ // Relocate the player
+ // assuming to allows PL_MIN to PL_MAX box and some more
+ from = player.origin;
+ setorigin (player, to);
+ player.oldorigin = to; // don't undo the teleport by unsticking
+ player.angles = to_angles;
+ player.fixangle = true;
+ player.velocity = to_velocity;
+ BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
+
+ makevectors(player.angles);
+ Reset_ArcBeam(player, v_forward);
+ UpdateCSQCProjectileAfterTeleport(player);
+
+ if(IS_PLAYER(player))
+ {
+ if(tflags & TELEPORT_FLAG_TDEATH)
+ if(player.takedamage && player.deadflag == DEAD_NO && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH)))
+ tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
+
+ // player no longer is on ground
+ player.flags &= ~FL_ONGROUND;
+
+ // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+ player.oldvelocity = player.velocity;
+
+ // reset tracking of who pushed you into a hazard (for kill credit)
+ if(teleporter.owner)
+ {
+ player.pusher = teleporter.owner;
+ player.pushltime = time + autocvar_g_maxpushtime;
+ player.istypefrag = player.BUTTON_CHAT;
+ }
+ else
+ {
+ player.pushltime = 0;
+ player.istypefrag = 0;
+ }
+
+ player.lastteleporttime = time;
+ }
+}
+
+entity Simple_TeleportPlayer(entity teleporter, entity player)
+{
+ vector locout;
+ entity e;
+ float p;
+
+ // Find the output teleporter
+ if(teleporter.enemy)
+ {
+ e = teleporter.enemy;
+ }
+ else
+ {
+ RandomSelection_Init();
+ for(e = world; (e = find(e, targetname, teleporter.target)); )
+ {
+ p = 1;
+ if(autocvar_g_telefrags_avoid)
+ {
+ locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+ if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
+ p = 0;
+ }
+ RandomSelection_Add(e, 0, string_null, (e.cnt ? e.cnt : 1), p);
+ }
+ e = RandomSelection_chosen_ent;
+ }
+
+ if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
+
+ makevectors(e.mangle);
+
+ if(e.speed)
+ if(vlen(player.velocity) > e.speed)
+ player.velocity = normalize(player.velocity) * max(0, e.speed);
+
+ if(autocvar_g_teleport_maxspeed)
+ if(vlen(player.velocity) > autocvar_g_teleport_maxspeed)
+ player.velocity = normalize(player.velocity) * max(0, autocvar_g_teleport_maxspeed);
+
+ locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+ TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+
+ return e;
+}
+
+void teleport_findtarget (void)
+{
+ entity e;
+ float n;
+
+ n = 0;
+ for(e = world; (e = find(e, targetname, self.target)); )
+ {
+ ++n;
+ if(e.movetype == MOVETYPE_NONE)
+ waypoint_spawnforteleporter(self, e.origin, 0);
+ if(e.classname != "info_teleport_destination")
+ print("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.\n");
+ }
+
+ if(n == 0)
+ {
+ // no dest!
+ objerror ("Teleporter with nonexistant target");
+ return;
+ }
+ else if(n == 1)
+ {
+ // exactly one dest - bots love that
+ self.enemy = find(e, targetname, self.target);
+ }
+ else
+ {
+ // have to use random selection every single time
+ self.enemy = world;
+ }
+
+ // now enable touch
+ self.touch = Teleport_Touch;
+}
+
+entity Teleport_Find(vector mi, vector ma)
+{
+ entity e;
+ for(e = world; (e = find(e, classname, "trigger_teleport")); )
+ if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
+ return e;
+ return world;
+}
+
+void WarpZone_PostTeleportPlayer_Callback(entity pl)
+{
+ makevectors(pl.angles);
+ Reset_ArcBeam(pl, v_forward);
+ UpdateCSQCProjectileAfterTeleport(pl);
+ {
+ entity oldself = self;
+ self = pl;
+ anticheat_fixangle();
+ self = oldself;
+ }
+ // "disown" projectiles after teleport
+ if(pl.owner)
+ if(pl.owner == pl.realowner)
+ {
+ if(!(pl.flags & FL_PROJECTILE))
+ print("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".\n");
+ pl.owner = world;
+ }
+ if(IS_PLAYER(pl))
+ {
+ // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+ pl.oldvelocity = pl.velocity;
+ // reset teleport time tracking too (or multijump can cause insane speeds)
+ pl.lastteleporttime = time;
+ }
+}
+#endif
--- /dev/null
+#ifndef T_TELEPORTERS_H
+#define T_TELEPORTERS_H
+
+#ifdef SVQC
+
+void trigger_teleport_use();
+
+#define TDEATHLOOP(o) \
+ entity head; \
+ vector deathmin; \
+ vector deathmax; \
+ float deathradius; \
+ deathmin = (o) + player.mins; \
+ deathmax = (o) + player.maxs; \
+ if(telefragmin != telefragmax) \
+ { \
+ if(deathmin.x > telefragmin.x) deathmin.x = telefragmin.x; \
+ if(deathmin.y > telefragmin.y) deathmin.y = telefragmin.y; \
+ if(deathmin.z > telefragmin.z) deathmin.z = telefragmin.z; \
+ if(deathmax.x < telefragmax.x) deathmax.x = telefragmax.x; \
+ if(deathmax.y < telefragmax.y) deathmax.y = telefragmax.y; \
+ if(deathmax.z < telefragmax.z) deathmax.z = telefragmax.z; \
+ } \
+ deathradius = max(vlen(deathmin), vlen(deathmax)); \
+ for(head = findradius(o, deathradius); head; head = head.chain) \
+ if(head != player) \
+ if(head.takedamage) \
+ if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
+
+
+float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax);
+float tdeath_hit;
+void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax);
+
+void spawn_tdeath(vector v0, entity e, vector v);
+
+.entity pusher;
+const float TELEPORT_FLAG_SOUND = 1;
+const float TELEPORT_FLAG_PARTICLES = 2;
+const float TELEPORT_FLAG_TDEATH = 4;
+const float TELEPORT_FLAG_FORCE_TDEATH = 8;
+
+#define TELEPORT_FLAGS_WARPZONE 0
+#define TELEPORT_FLAGS_PORTAL (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH)
+#define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH)
+
+// types for .teleportable entity setting
+const float TELEPORT_NORMAL = 1; // play sounds/effects etc
+const float TELEPORT_SIMPLE = 2; // only do teleport, nothing special
+
+void Reset_ArcBeam(entity player, vector forward);
+void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags);
+
+entity Simple_TeleportPlayer(entity teleporter, entity player);
+
+void Teleport_Touch (void);
+
+void teleport_findtarget (void);
+
+entity Teleport_Find(vector mi, vector ma);
+
+entity teleport_first;
+.entity teleport_next;
+
+void WarpZone_PostTeleportPlayer_Callback(entity pl);
+#endif
+
+#endif
--- /dev/null
+#ifdef SVQC
+void counter_use()
+{
+ self.count -= 1;
+ if (self.count < 0)
+ return;
+
+ if (self.count == 0)
+ {
+ if(IS_PLAYER(activator) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
+ Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COMPLETED);
+
+ self.enemy = activator;
+ multi_trigger ();
+ }
+ else
+ {
+ if(IS_PLAYER(activator) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
+ if(self.count >= 4)
+ Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COUNTER);
+ else
+ Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, self.count);
+ }
+}
+
+void counter_reset()
+{
+ self.count = self.cnt;
+ multi_reset();
+}
+
+/*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage
+Acts as an intermediary for an action that takes multiple inputs.
+
+If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
+
+After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
+*/
+void spawnfunc_trigger_counter()
+{
+ self.wait = -1;
+ if (!self.count)
+ self.count = 2;
+ self.cnt = self.count;
+
+ self.use = counter_use;
+ self.reset = counter_reset;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void delay_use()
+{
+ self.think = SUB_UseTargets;
+ self.nextthink = self.wait;
+}
+
+void delay_reset()
+{
+ self.think = func_null;
+ self.nextthink = 0;
+}
+
+void spawnfunc_trigger_delay()
+{
+ if(!self.wait)
+ self.wait = 1;
+
+ self.use = delay_use;
+ self.reset = delay_reset;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void trigger_disablerelay_use()
+{
+ entity e;
+
+ float a, b;
+ a = b = 0;
+
+ for(e = world; (e = find(e, targetname, self.target)); )
+ {
+ if(e.use == SUB_UseTargets)
+ {
+ e.use = SUB_DontUseTargets;
+ ++a;
+ }
+ else if(e.use == SUB_DontUseTargets)
+ {
+ e.use = SUB_UseTargets;
+ ++b;
+ }
+ }
+
+ if((!a) == (!b))
+ print("Invalid use of trigger_disablerelay: ", ftos(a), " relays were on, ", ftos(b), " relays were off!\n");
+}
+
+void spawnfunc_trigger_disablerelay()
+{
+ self.use = trigger_disablerelay_use;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+/*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
+"Flip-flop" trigger gate... lets only every second trigger event through
+*/
+void flipflop_use()
+{
+ self.state = !self.state;
+ if(self.state)
+ SUB_UseTargets();
+}
+
+void spawnfunc_trigger_flipflop()
+{
+ if(self.spawnflags & 1)
+ self.state = 1;
+ self.use = flipflop_use;
+ self.reset = spawnfunc_trigger_flipflop; // perfect resetter
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void gamestart_use()
+{
+ activator = self;
+ SUB_UseTargets();
+ remove(self);
+}
+
+void spawnfunc_trigger_gamestart()
+{
+ self.use = gamestart_use;
+ self.reset2 = spawnfunc_trigger_gamestart;
+
+ if(self.wait)
+ {
+ self.think = self.use;
+ self.nextthink = game_starttime + self.wait;
+ }
+ else
+ InitializeEntity(self, gamestart_use, INITPRIO_FINDTARGET);
+}
+#endif
--- /dev/null
+#ifdef SVQC
+.entity trigger_gravity_check;
+void trigger_gravity_remove(entity own)
+{
+ if(own.trigger_gravity_check.owner == own)
+ {
+ UpdateCSQCProjectile(own);
+ own.gravity = own.trigger_gravity_check.gravity;
+ remove(own.trigger_gravity_check);
+ }
+ else
+ backtrace("Removing a trigger_gravity_check with no valid owner");
+ own.trigger_gravity_check = world;
+}
+void trigger_gravity_check_think()
+{
+ // This spawns when a player enters the gravity zone and checks if he left.
+ // Each frame, self.count is set to 2 by trigger_gravity_touch() and decreased by 1 here.
+ // It the player has left the gravity trigger, this will be allowed to reach 0 and indicate that.
+ if(self.count <= 0)
+ {
+ if(self.owner.trigger_gravity_check == self)
+ trigger_gravity_remove(self.owner);
+ else
+ remove(self);
+ return;
+ }
+ else
+ {
+ self.count -= 1;
+ self.nextthink = time;
+ }
+}
+
+void trigger_gravity_use()
+{
+ self.state = !self.state;
+}
+
+void trigger_gravity_touch()
+{
+ float g;
+
+ if(self.state != true)
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ g = self.gravity;
+
+ if (!(self.spawnflags & 1))
+ {
+ if(other.trigger_gravity_check)
+ {
+ if(self == other.trigger_gravity_check.enemy)
+ {
+ // same?
+ other.trigger_gravity_check.count = 2; // gravity one more frame...
+ return;
+ }
+
+ // compare prio
+ if(self.cnt > other.trigger_gravity_check.enemy.cnt)
+ trigger_gravity_remove(other);
+ else
+ return;
+ }
+ other.trigger_gravity_check = spawn();
+ other.trigger_gravity_check.enemy = self;
+ other.trigger_gravity_check.owner = other;
+ other.trigger_gravity_check.gravity = other.gravity;
+ other.trigger_gravity_check.think = trigger_gravity_check_think;
+ other.trigger_gravity_check.nextthink = time;
+ other.trigger_gravity_check.count = 2;
+ if(other.gravity)
+ g *= other.gravity;
+ }
+
+ if (other.gravity != g)
+ {
+ other.gravity = g;
+ if(self.noise != "")
+ sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+ UpdateCSQCProjectile(self.owner);
+ }
+}
+
+void spawnfunc_trigger_gravity()
+{
+ if(self.gravity == 1)
+ return;
+
+ EXACTTRIGGER_INIT;
+ self.touch = trigger_gravity_touch;
+ if(self.noise != "")
+ precache_sound(self.noise);
+
+ self.state = true;
+ IFTARGETED
+ {
+ self.use = trigger_gravity_use;
+ if(self.spawnflags & 2)
+ self.state = false;
+ }
+}
+#endif
--- /dev/null
+#ifdef SVQC
+.float triggerhealtime;
+void trigger_heal_touch()
+{
+ if (self.active != ACTIVE_ACTIVE)
+ return;
+
+ // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
+ if (other.iscreature)
+ {
+ if (other.takedamage)
+ if (!other.deadflag)
+ if (other.triggerhealtime < time)
+ {
+ EXACTTRIGGER_TOUCH;
+ other.triggerhealtime = time + 1;
+
+ if (other.health < self.max_health)
+ {
+ other.health = min(other.health + self.health, self.max_health);
+ other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+ sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+ }
+ }
+ }
+}
+
+void spawnfunc_trigger_heal()
+{
+ self.active = ACTIVE_ACTIVE;
+
+ EXACTTRIGGER_INIT;
+ self.touch = trigger_heal_touch;
+ if (!self.health)
+ self.health = 10;
+ if (!self.max_health)
+ self.max_health = 200; //Max health topoff for field
+ if(self.noise == "")
+ self.noise = "misc/mediumhealth.wav";
+ precache_sound(self.noise);
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void trigger_hurt_use()
+{
+ if(IS_PLAYER(activator))
+ self.enemy = activator;
+ else
+ self.enemy = world; // let's just destroy it, if taking over is too much work
+}
+
+.float triggerhurttime;
+void trigger_hurt_touch()
+{
+ if (self.active != ACTIVE_ACTIVE)
+ return;
+
+ if(self.team)
+ if(((self.spawnflags & 4) == 0) == (self.team != other.team))
+ return;
+
+ // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
+ if (other.iscreature)
+ {
+ if (other.takedamage)
+ if (other.triggerhurttime < time)
+ {
+ EXACTTRIGGER_TOUCH;
+ other.triggerhurttime = time + 1;
+
+ entity own;
+ own = self.enemy;
+ if (!IS_PLAYER(own))
+ {
+ own = self;
+ self.enemy = world; // I still hate you all
+ }
+
+ Damage (other, self, own, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ }
+ }
+ else if(other.damagedbytriggers)
+ {
+ if(other.takedamage)
+ {
+ EXACTTRIGGER_TOUCH;
+ Damage(other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+ }
+ }
+
+ return;
+}
+
+/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
+Any object touching this will be hurt
+set dmg to damage amount
+defalt dmg = 5
+*/
+.entity trigger_hurt_next;
+entity trigger_hurt_last;
+entity trigger_hurt_first;
+void spawnfunc_trigger_hurt()
+{
+ EXACTTRIGGER_INIT;
+ self.active = ACTIVE_ACTIVE;
+ self.touch = trigger_hurt_touch;
+ self.use = trigger_hurt_use;
+ self.enemy = world; // I hate you all
+ if (!self.dmg)
+ self.dmg = 1000;
+ if (self.message == "")
+ self.message = "was in the wrong place";
+ if (self.message2 == "")
+ self.message2 = "was thrown into a world of hurt by";
+ // self.message = "someone like %s always gets wrongplaced";
+
+ if(!trigger_hurt_first)
+ trigger_hurt_first = self;
+ if(trigger_hurt_last)
+ trigger_hurt_last.trigger_hurt_next = self;
+ trigger_hurt_last = self;
+}
+
+float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
+{
+ entity th;
+
+ for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
+ if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
+ return true;
+
+ return false;
+}
+#endif
--- /dev/null
+// targeted (directional) mode
+void trigger_impulse_touch1()
+{
+ entity targ;
+ float pushdeltatime;
+ float str;
+
+ if (self.active != ACTIVE_ACTIVE)
+ return;
+
+ if (!isPushable(other))
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ targ = find(world, targetname, self.target);
+ if(!targ)
+ {
+ objerror("trigger_force without a (valid) .target!\n");
+ remove(self);
+ return;
+ }
+
+ str = min(self.radius, vlen(self.origin - other.origin));
+
+ if(self.falloff == 1)
+ str = (str / self.radius) * self.strength;
+ else if(self.falloff == 2)
+ str = (1 - (str / self.radius)) * self.strength;
+ else
+ str = self.strength;
+
+ pushdeltatime = time - other.lastpushtime;
+ if (pushdeltatime > 0.15) pushdeltatime = 0;
+ other.lastpushtime = time;
+ if(!pushdeltatime) return;
+
+ other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
+ other.flags &= ~FL_ONGROUND;
+#ifdef SVQC
+ UpdateCSQCProjectile(other);
+#endif
+}
+
+// Directionless (accelerator/decelerator) mode
+void trigger_impulse_touch2()
+{
+ float pushdeltatime;
+
+ if (self.active != ACTIVE_ACTIVE)
+ return;
+
+ if (!isPushable(other))
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ pushdeltatime = time - other.lastpushtime;
+ if (pushdeltatime > 0.15) pushdeltatime = 0;
+ other.lastpushtime = time;
+ if(!pushdeltatime) return;
+
+ // div0: ticrate independent, 1 = identity (not 20)
+ other.velocity = other.velocity * pow(self.strength, pushdeltatime);
+#ifdef SVQC
+ UpdateCSQCProjectile(other);
+#endif
+}
+
+// Spherical (gravity/repulsor) mode
+void trigger_impulse_touch3()
+{
+ float pushdeltatime;
+ float str;
+
+ if (self.active != ACTIVE_ACTIVE)
+ return;
+
+ if (!isPushable(other))
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ pushdeltatime = time - other.lastpushtime;
+ if (pushdeltatime > 0.15) pushdeltatime = 0;
+ other.lastpushtime = time;
+ if(!pushdeltatime) return;
+
+ setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
+
+ str = min(self.radius, vlen(self.origin - other.origin));
+
+ if(self.falloff == 1)
+ str = (1 - str / self.radius) * self.strength; // 1 in the inside
+ else if(self.falloff == 2)
+ str = (str / self.radius) * self.strength; // 0 in the inside
+ else
+ str = self.strength;
+
+ other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
+#ifdef SVQC
+ UpdateCSQCProjectile(other);
+#endif
+}
+
+/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
+-------- KEYS --------
+target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
+ If not, this trigger acts like a damper/accelerator field.
+
+strength : This is how mutch force to add in the direction of .target each second
+ when .target is set. If not, this is hoe mutch to slow down/accelerate
+ someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
+
+radius : If set, act as a spherical device rather then a liniar one.
+
+falloff : 0 = none, 1 = liniar, 2 = inverted liniar
+
+-------- NOTES --------
+Use a brush textured with common/origin in the trigger entity to determine the origin of the force
+in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
+*/
+#ifdef SVQC
+bool trigger_impulse_send(entity to, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
+
+ WriteCoord(MSG_ENTITY, self.radius);
+ WriteCoord(MSG_ENTITY, self.strength);
+ WriteByte(MSG_ENTITY, self.falloff);
+ WriteByte(MSG_ENTITY, self.active);
+
+ trigger_common_write(true);
+
+ return true;
+}
+
+void trigger_impulse_link()
+{
+ //Net_LinkEntity(self, 0, false, trigger_impulse_send);
+}
+
+void spawnfunc_trigger_impulse()
+{
+ self.active = ACTIVE_ACTIVE;
+
+ EXACTTRIGGER_INIT;
+ if(self.radius)
+ {
+ if(!self.strength) self.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
+ setorigin(self, self.origin);
+ setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
+ self.touch = trigger_impulse_touch3;
+ }
+ else
+ {
+ if(self.target)
+ {
+ if(!self.strength) self.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
+ self.touch = trigger_impulse_touch1;
+ }
+ else
+ {
+ if(!self.strength) self.strength = 0.9;
+ self.strength = pow(self.strength, autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
+ self.touch = trigger_impulse_touch2;
+ }
+ }
+
+ trigger_impulse_link();
+}
+#elif defined(CSQC)
+void ent_trigger_impulse()
+{
+ self.radius = ReadCoord();
+ self.strength = ReadCoord();
+ self.falloff = ReadByte();
+ self.active = ReadByte();
+
+ trigger_common_read(true);
+
+
+ self.classname = "trigger_impulse";
+ self.solid = SOLID_TRIGGER;
+ self.entremove = trigger_remove_generic;
+ self.draw = trigger_draw_generic;
+ self.drawmask = MASK_NORMAL;
+ self.move_time = time;
+
+ if(self.radius) { self.trigger_touch = trigger_impulse_touch3; }
+ else if(self.target) { self.trigger_touch = trigger_impulse_touch1; }
+ else { self.trigger_touch = trigger_impulse_touch2; }
+}
+#endif
--- /dev/null
+#ifndef TRIGGER_IMPULSE_H
+#define TRIGGER_IMPULSE_H
+
+// tZorks trigger impulse / gravity
+.float radius;
+.float falloff;
+.float strength;
+.float lastpushtime;
+
+#ifdef CSQC
+void ent_trigger_impulse();
+#endif
+
+#endif
--- /dev/null
+#include "include.qh"
+
+#include "counter.qc"
+#include "delay.qc"
+#include "disablerelay.qc"
+#include "flipflop.qc"
+#include "gamestart.qc"
+#include "gravity.qc"
+#include "heal.qc"
+#include "hurt.qc"
+#include "impulse.qc"
+#include "jumppads.qc"
+#include "keylock.qc"
+#include "magicear.qc"
+#include "monoflop.qc"
+#include "multi.qc"
+#include "multivibrator.qc"
+#include "relay.qc"
+#include "relay_activators.qc"
+#include "relay_if.qc"
+#include "relay_teamcheck.qc"
+#include "secret.qc"
+#include "swamp.qc"
+#include "teleport.qc"
--- /dev/null
+#ifndef TRIGGERS_TRIGGER_INCLUDE_H
+#define TRIGGERS_TRIGGER_INCLUDE_H
+
+#include "multi.qh"
+#include "jumppads.qh"
+#include "secret.qh"
+#include "swamp.qh"
+#include "keylock.qh"
+#include "impulse.qh"
+
+#endif
--- /dev/null
+// TODO: split target_push and put it in the target folder
+#ifdef SVQC
+#include "../../../server/_all.qh"
+#include "jumppads.qh"
+#include "../../movetypes/movetypes.qh"
+
+void trigger_push_use()
+{
+ if(teamplay)
+ {
+ self.team = activator.team;
+ self.SendFlags |= 2;
+ }
+}
+#endif
+
+/*
+ trigger_push_calculatevelocity
+
+ Arguments:
+ org - origin of the object which is to be pushed
+ tgt - target entity (can be either a point or a model entity; if it is
+ the latter, its midpoint is used)
+ ht - jump height, measured from the higher one of org and tgt's midpoint
+
+ Returns: velocity for the jump
+ the global trigger_push_calculatevelocity_flighttime is set to the total
+ jump time
+ */
+
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht)
+{
+ float grav, sdist, zdist, vs, vz, jumpheight;
+ vector sdir, torg;
+
+ torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
+
+ grav = PHYS_GRAVITY;
+ if(PHYS_ENTGRAVITY(other))
+ grav *= PHYS_ENTGRAVITY(other);
+
+ zdist = torg.z - org.z;
+ sdist = vlen(torg - org - zdist * '0 0 1');
+ sdir = normalize(torg - org - zdist * '0 0 1');
+
+ // how high do we need to push the player?
+ jumpheight = fabs(ht);
+ if(zdist > 0)
+ jumpheight = jumpheight + zdist;
+
+ /*
+ STOP.
+
+ You will not understand the following equations anyway...
+ But here is what I did to get them.
+
+ I used the functions
+
+ s(t) = t * vs
+ z(t) = t * vz - 1/2 grav t^2
+
+ and solved for:
+
+ s(ti) = sdist
+ z(ti) = zdist
+ max(z, ti) = jumpheight
+
+ From these three equations, you will find the three parameters vs, vz
+ and ti.
+ */
+
+ // push him so high...
+ vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
+
+ // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
+ if(ht < 0)
+ if(zdist < 0)
+ vz = -vz;
+
+ vector solution;
+ solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
+ // ALWAYS solvable because jumpheight >= zdist
+ if(!solution.z)
+ solution_y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
+ if(zdist == 0)
+ solution_x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
+
+ if(zdist < 0)
+ {
+ // down-jump
+ if(ht < 0)
+ {
+ // almost straight line type
+ // jump apex is before the jump
+ // we must take the larger one
+ trigger_push_calculatevelocity_flighttime = solution.y;
+ }
+ else
+ {
+ // regular jump
+ // jump apex is during the jump
+ // we must take the larger one too
+ trigger_push_calculatevelocity_flighttime = solution.y;
+ }
+ }
+ else
+ {
+ // up-jump
+ if(ht < 0)
+ {
+ // almost straight line type
+ // jump apex is after the jump
+ // we must take the smaller one
+ trigger_push_calculatevelocity_flighttime = solution.x;
+ }
+ else
+ {
+ // regular jump
+ // jump apex is during the jump
+ // we must take the larger one
+ trigger_push_calculatevelocity_flighttime = solution.y;
+ }
+ }
+ vs = sdist / trigger_push_calculatevelocity_flighttime;
+
+ // finally calculate the velocity
+ return sdir * vs + '0 0 1' * vz;
+}
+
+void trigger_push_touch()
+{
+ if (self.active == ACTIVE_NOT)
+ return;
+
+#ifdef SVQC
+ if (!isPushable(other))
+ return;
+#endif
+
+ if(self.team)
+ if(((self.spawnflags & 4) == 0) == (DIFF_TEAM(self, other)))
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ if(self.enemy)
+ {
+ other.velocity = trigger_push_calculatevelocity(other.origin, self.enemy, self.height);
+ other.move_velocity = other.velocity;
+ }
+ else if(self.target)
+ {
+ entity e;
+ RandomSelection_Init();
+ for(e = world; (e = find(e, targetname, self.target)); )
+ {
+ if(e.cnt)
+ RandomSelection_Add(e, 0, string_null, e.cnt, 1);
+ else
+ RandomSelection_Add(e, 0, string_null, 1, 1);
+ }
+ other.velocity = trigger_push_calculatevelocity(other.origin, RandomSelection_chosen_ent, self.height);
+ other.move_velocity = other.velocity;
+ }
+ else
+ {
+ other.velocity = self.movedir;
+ other.move_velocity = other.velocity;
+ }
+
+ UNSET_ONGROUND(other);
+
+ other.move_flags &= ~FL_ONGROUND;
+
+#ifdef SVQC
+ if (IS_PLAYER(other))
+ {
+ // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+ other.oldvelocity = other.velocity;
+
+ if(self.pushltime < time) // prevent "snorring" sound when a player hits the jumppad more than once
+ {
+ // flash when activated
+ pointparticles(particleeffectnum("jumppad_activate"), other.origin, other.velocity, 1);
+ sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+ self.pushltime = time + 0.2;
+ }
+ if(IS_REAL_CLIENT(other) || IS_BOT_CLIENT(other))
+ {
+ bool found = false;
+ for(int i = 0; i < other.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
+ if(other.(jumppadsused[i]) == self)
+ found = true;
+ if(!found)
+ {
+ other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = self;
+ other.jumppadcount = other.jumppadcount + 1;
+ }
+
+ if(IS_REAL_CLIENT(other))
+ {
+ if(self.message)
+ centerprint(other, self.message);
+ }
+ else
+ other.lastteleporttime = time;
+
+ if (other.deadflag == DEAD_NO)
+ animdecide_setaction(other, ANIMACTION_JUMP, true);
+ }
+ else
+ other.jumppadcount = true;
+
+ // reset tracking of who pushed you into a hazard (for kill credit)
+ other.pushltime = 0;
+ other.istypefrag = 0;
+ }
+
+ if(self.enemy.target)
+ {
+ entity oldself;
+ oldself = self;
+ activator = other;
+ self = self.enemy;
+ SUB_UseTargets();
+ self = oldself;
+ }
+
+ if (other.flags & FL_PROJECTILE)
+ {
+ other.angles = vectoangles (other.velocity);
+ switch(other.movetype)
+ {
+ case MOVETYPE_FLY:
+ other.movetype = MOVETYPE_TOSS;
+ other.gravity = 1;
+ break;
+ case MOVETYPE_BOUNCEMISSILE:
+ other.movetype = MOVETYPE_BOUNCE;
+ other.gravity = 1;
+ break;
+ }
+ UpdateCSQCProjectile(other);
+ }
+
+ if (self.spawnflags & PUSH_ONCE)
+ {
+ self.touch = func_null;
+ self.think = SUB_Remove;
+ self.nextthink = time;
+ }
+#endif
+}
+
+#ifdef SVQC
+void trigger_push_link();
+void trigger_push_updatelink();
+#endif
+void trigger_push_findtarget()
+{
+ entity t;
+ vector org;
+
+ // first calculate a typical start point for the jump
+ org = (self.absmin + self.absmax) * 0.5;
+ org_z = self.absmax.z - PL_MIN.z;
+
+ if (self.target)
+ {
+ float n = 0;
+ for(t = world; (t = find(t, targetname, self.target)); )
+ {
+ ++n;
+#ifdef SVQC
+ entity e = spawn();
+ setorigin(e, org);
+ setsize(e, PL_MIN, PL_MAX);
+ e.velocity = trigger_push_calculatevelocity(org, t, self.height);
+ tracetoss(e, e);
+ if(e.movetype == MOVETYPE_NONE)
+ waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
+ remove(e);
+#endif
+ }
+
+ if(!n)
+ {
+ // no dest!
+#ifdef SVQC
+ objerror ("Jumppad with nonexistant target");
+#endif
+ return;
+ }
+ else if(n == 1)
+ {
+ // exactly one dest - bots love that
+ self.enemy = find(world, targetname, self.target);
+ }
+ else
+ {
+ // have to use random selection every single time
+ self.enemy = world;
+ }
+ }
+#ifdef SVQC
+ else
+ {
+ entity e = spawn();
+ setorigin(e, org);
+ setsize(e, PL_MIN, PL_MAX);
+ e.velocity = self.movedir;
+ tracetoss(e, e);
+ waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
+ remove(e);
+ }
+
+ trigger_push_link();
+ defer(0.1, trigger_push_updatelink);
+#endif
+}
+
+#ifdef SVQC
+float trigger_push_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & 1)
+ {
+ WriteByte(MSG_ENTITY, self.team);
+ WriteInt24_t(MSG_ENTITY, self.spawnflags);
+ WriteByte(MSG_ENTITY, self.active);
+ WriteByte(MSG_ENTITY, self.height);
+
+ trigger_common_write(true);
+ }
+
+ if(sf & 2)
+ {
+ WriteByte(MSG_ENTITY, self.team);
+ WriteByte(MSG_ENTITY, self.active);
+ }
+
+ return true;
+}
+
+void trigger_push_updatelink()
+{
+ self.SendFlags |= 1;
+}
+
+void trigger_push_link()
+{
+ //Net_LinkEntity(self, false, 0, trigger_push_send);
+}
+#endif
+#ifdef SVQC
+/*
+ * ENTITY PARAMETERS:
+ *
+ * target: target of jump
+ * height: the absolute value is the height of the highest point of the jump
+ * trajectory above the higher one of the player and the target.
+ * the sign indicates whether the highest point is INSIDE (positive)
+ * or OUTSIDE (negative) of the jump trajectory. General rule: use
+ * positive values for targets mounted on the floor, and use negative
+ * values to target a point on the ceiling.
+ * movedir: if target is not set, this * speed * 10 is the velocity to be reached.
+ */
+void spawnfunc_trigger_push()
+{
+ SetMovedir ();
+
+ EXACTTRIGGER_INIT;
+
+ self.active = ACTIVE_ACTIVE;
+ self.use = trigger_push_use;
+ self.touch = trigger_push_touch;
+
+ // normal push setup
+ if (!self.speed)
+ self.speed = 1000;
+ self.movedir = self.movedir * self.speed * 10;
+
+ if (!self.noise)
+ self.noise = "misc/jumppad.wav";
+ precache_sound (self.noise);
+
+ // this must be called to spawn the teleport waypoints for bots
+ InitializeEntity(self, trigger_push_findtarget, INITPRIO_FINDTARGET);
+}
+
+
+float target_push_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
+
+ WriteByte(MSG_ENTITY, self.cnt);
+ WriteString(MSG_ENTITY, self.targetname);
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ return true;
+}
+
+void target_push_link()
+{
+ Net_LinkEntity(self, false, 0, target_push_send);
+ self.SendFlags |= 1; // update
+}
+
+void spawnfunc_target_push() { target_push_link(); }
+void spawnfunc_info_notnull() { target_push_link(); }
+void spawnfunc_target_position() { target_push_link(); }
+
+#endif
+
+#ifdef CSQC
+
+void ent_trigger_push()
+{
+ float sf = ReadByte();
+
+ if(sf & 1)
+ {
+ self.classname = "jumppad";
+ int mytm = ReadByte(); if(mytm) { self.team = mytm - 1; }
+ self.spawnflags = ReadInt24_t();
+ self.active = ReadByte();
+ self.height = ReadByte();
+
+ trigger_common_read(true);
+
+ self.entremove = trigger_remove_generic;
+ self.solid = SOLID_TRIGGER;
+ self.draw = trigger_draw_generic;
+ self.trigger_touch = trigger_push_touch;
+ self.drawmask = MASK_NORMAL;
+ self.move_time = time;
+ trigger_push_findtarget();
+ }
+
+ if(sf & 2)
+ {
+ self.team = ReadByte();
+ self.active = ReadByte();
+ }
+}
+
+void target_push_remove()
+{
+ if(self.classname)
+ strunzone(self.classname);
+ self.classname = string_null;
+
+ if(self.targetname)
+ strunzone(self.targetname);
+ self.targetname = string_null;
+}
+
+void ent_target_push()
+{
+ self.classname = "push_target";
+ self.cnt = ReadByte();
+ self.targetname = strzone(ReadString());
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+
+ self.drawmask = MASK_NORMAL;
+ self.entremove = target_push_remove;
+}
+#endif
--- /dev/null
+#ifndef T_JUMPPADS_H
+#define T_JUMPPADS_H
+
+const float PUSH_ONCE = 1;
+const float PUSH_SILENT = 2;
+
+.float pushltime;
+.float istypefrag;
+.float height;
+
+const int NUM_JUMPPADSUSED = 3;
+.float jumppadcount;
+.entity jumppadsused[NUM_JUMPPADSUSED];
+
+float trigger_push_calculatevelocity_flighttime;
+
+#ifdef SVQC
+void() SUB_UseTargets;
+void trigger_push_use();
+#endif
+
+#ifdef CSQC
+void ent_trigger_push();
+
+void ent_target_push();
+#endif
+
+/*
+ trigger_push_calculatevelocity
+
+ Arguments:
+ org - origin of the object which is to be pushed
+ tgt - target entity (can be either a point or a model entity; if it is
+ the latter, its midpoint is used)
+ ht - jump height, measured from the higher one of org and tgt's midpoint
+
+ Returns: velocity for the jump
+ the global trigger_push_calculatevelocity_flighttime is set to the total
+ jump time
+ */
+
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
+
+void trigger_push_touch();
+
+.vector dest;
+void trigger_push_findtarget();
+
+/*
+ * ENTITY PARAMETERS:
+ *
+ * target: target of jump
+ * height: the absolute value is the height of the highest point of the jump
+ * trajectory above the higher one of the player and the target.
+ * the sign indicates whether the highest point is INSIDE (positive)
+ * or OUTSIDE (negative) of the jump trajectory. General rule: use
+ * positive values for targets mounted on the floor, and use negative
+ * values to target a point on the ceiling.
+ * movedir: if target is not set, this * speed * 10 is the velocity to be reached.
+ */
+#ifdef SVQC
+void spawnfunc_trigger_push();
+
+void spawnfunc_target_push();
+void spawnfunc_info_notnull();
+void spawnfunc_target_position();
+#endif
+#endif
--- /dev/null
+/**
+ * trigger given targets
+ */
+void trigger_keylock_trigger(string s)
+{
+ entity stemp = self;
+ entity otemp = other;
+ entity atemp = activator;
+
+ entity t;
+ for(t = world; (t = find(t, targetname, s)); )
+ if(t.use)
+ {
+ self = t;
+ other = stemp;
+ activator = atemp;
+ self.use();
+ }
+
+ self = stemp;
+ other = otemp;
+ activator = atemp;
+}
+
+/**
+ * kill killtarget of trigger keylock.
+ */
+void trigger_keylock_kill(string s)
+{
+ entity t;
+ for(t = world; (t = find(t, targetname, s)); )
+ remove(t);
+}
+
+void trigger_keylock_touch()
+{
+ bool key_used = false;
+ bool started_delay = false;
+
+ // only player may trigger the lock
+ if(!IS_PLAYER(other))
+ return;
+
+ // check silver key
+ if(self.itemkeys)
+ key_used = item_keys_usekey(self, other);
+
+ activator = other;
+
+ if(self.itemkeys)
+ {
+#ifdef SVQC
+ // at least one of the keys is missing
+ if(key_used)
+ {
+ // one or more keys were given, but others are still missing!
+ play2(other, self.noise1);
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(self.itemkeys));
+ other.key_door_messagetime = time + 2;
+ }
+ else if(other.key_door_messagetime <= time)
+ {
+ // no keys were given
+ play2(other, self.noise2);
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(self.itemkeys));
+ other.key_door_messagetime = time + 2;
+ }
+#endif
+
+ // trigger target2
+ if(self.delay <= time || started_delay == true)
+ if(self.target2)
+ {
+ trigger_keylock_trigger(self.target2);
+ started_delay = true;
+ self.delay = time + self.wait;
+ }
+ }
+ else
+ {
+#ifdef SVQC
+ // all keys were given!
+ play2(other, self.noise);
+ centerprint(other, self.message);
+#endif
+
+ if(self.target)
+ trigger_keylock_trigger(self.target);
+
+ if(self.killtarget)
+ trigger_keylock_kill(self.killtarget);
+
+ remove(self);
+ }
+
+}
+
+#ifdef SVQC
+bool trigger_keylock_send(entity to, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
+
+ WriteInt24_t(MSG_ENTITY, self.itemkeys);
+ WriteByte(MSG_ENTITY, self.height);
+
+ trigger_common_write(true);
+
+ return true;
+}
+
+void trigger_keylock_link()
+{
+ // uncomment to network keylocks
+ //Net_LinkEntity(self, false, 0, trigger_keylock_send);
+}
+
+/*QUAKED trigger_keylock (.0 .5 .8) ?
+Keylock trigger. Must target other entities.
+This trigger will trigger target entities when all required keys are provided.
+-------- KEYS --------
+itemkeys: A bit field with key IDs that are needed to open this lock.
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (3 is default)
+target: trigger all entities with this targetname when triggered and all keys have been given to it, then remove this trigger
+target2: trigger all entities with this targetname when triggered without giving it all the required keys.
+killtarget: remove all entities with this targetname when triggered with all the needed keys.
+message: print this message to the player who activated the trigger when all needed keys have been given.
+message2: print this message to the player who activated the trigger when not all of the needed keys have been given.
+noise: sound to play when lock gets unlocked (default: see sounds)
+noise1: sound to play when only some of the needed key were used but not all (default: misc/decreasevalue.wav)
+noise2: sound to play when a key is missing (default: misc/talk.wav)
+wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4.
+---------NOTES----------
+If spawned without any key specified in itemkeys, this trigger will display an error and remove itself.
+message2 and noise2 will be resent to the player every 2 seconds while he is in the trigger zone.
+*/
+void spawnfunc_trigger_keylock(void)
+{
+ if(!self.itemkeys) { remove(self); return; }
+
+ // set unlocked message
+ if(self.message == "")
+ self.message = "Unlocked!";
+
+ // set default unlock noise
+ if(self.noise == "")
+ {
+ if(self.sounds == 1)
+ self.noise = "misc/secret.wav";
+ else if(self.sounds == 2)
+ self.noise = "misc/talk.wav";
+ else //if (self.sounds == 3) {
+ self.noise = "misc/trigger1.wav";
+ }
+
+ // set default use key sound
+ if(self.noise1 == "")
+ self.noise1 = "misc/decreasevalue.wav";
+
+ // set closed sourd
+ if(self.noise2 == "")
+ self.noise2 = "misc/talk.wav";
+
+ // delay between triggering message2 and trigger2
+ if(!self.wait) { self.wait = 5; }
+
+ // precache sounds
+ precache_sound(self.noise);
+ precache_sound(self.noise1);
+ precache_sound(self.noise2);
+
+ EXACTTRIGGER_INIT;
+
+ self.touch = trigger_keylock_touch;
+
+ trigger_keylock_link();
+}
+#elif defined(CSQC)
+void keylock_remove()
+{
+ if(self.target) { strunzone(self.target); }
+ self.target = string_null;
+
+ if(self.target2) { strunzone(self.target2); }
+ self.target2 = string_null;
+
+ if(self.target3) { strunzone(self.target3); }
+ self.target3 = string_null;
+
+ if(self.target4) { strunzone(self.target4); }
+ self.target4 = string_null;
+
+ if(self.killtarget) { strunzone(self.killtarget); }
+ self.killtarget = string_null;
+
+ if(self.targetname) { strunzone(self.targetname); }
+ self.targetname = string_null;
+}
+
+void ent_keylock()
+{
+ self.itemkeys = ReadInt24_t();
+ self.height = ReadByte();
+
+ trigger_common_read(true);
+
+ self.classname = "trigger_keylock";
+ self.drawmask = MASK_NORMAL;
+ self.draw = trigger_draw_generic;
+ self.trigger_touch = trigger_keylock_touch;
+ self.entremove = keylock_remove;
+}
+#endif
--- /dev/null
+#ifdef CSQC
+void ent_keylock();
+bool item_keys_usekey(entity l, entity p)
+{
+ float valid = l.itemkeys & p.itemkeys;
+
+ if (!valid) {
+ // other has none of the needed keys
+ return false;
+ } else if (l.itemkeys == valid) {
+ // ALL needed keys were given
+ l.itemkeys = 0;
+ return true;
+ } else {
+ // only some of the needed keys were given
+ l.itemkeys &= ~valid;
+ return true;
+ }
+}
+#endif
--- /dev/null
+#ifdef SVQC
+float magicear_matched;
+float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
+string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
+{
+ float domatch, dotrigger, matchstart, l;
+ string s, msg;
+ entity oldself;
+ string savemessage;
+
+ magicear_matched = false;
+
+ dotrigger = ((IS_PLAYER(source)) && (source.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius)));
+ domatch = ((ear.spawnflags & 32) || dotrigger);
+
+ if (!domatch)
+ return msgin;
+
+ if (!msgin)
+ {
+ // we are in TUBA mode!
+ if (!(ear.spawnflags & 256))
+ return msgin;
+
+ if(!W_Tuba_HasPlayed(source, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z))
+ return msgin;
+
+ magicear_matched = true;
+
+ if(dotrigger)
+ {
+ oldself = self;
+ activator = source;
+ self = ear;
+ savemessage = self.message;
+ self.message = string_null;
+ SUB_UseTargets();
+ self.message = savemessage;
+ self = oldself;
+ }
+
+ if(ear.netname != "")
+ return ear.netname;
+
+ return msgin;
+ }
+
+ if(ear.spawnflags & 256) // ENOTUBA
+ return msgin;
+
+ if(privatesay)
+ {
+ if(ear.spawnflags & 4)
+ return msgin;
+ }
+ else
+ {
+ if(!teamsay)
+ if(ear.spawnflags & 1)
+ return msgin;
+ if(teamsay > 0)
+ if(ear.spawnflags & 2)
+ return msgin;
+ if(teamsay < 0)
+ if(ear.spawnflags & 8)
+ return msgin;
+ }
+
+ matchstart = -1;
+ l = strlen(ear.message);
+
+ if(ear.spawnflags & 128)
+ msg = msgin;
+ else
+ msg = strdecolorize(msgin);
+
+ if(substring(ear.message, 0, 1) == "*")
+ {
+ if(substring(ear.message, -1, 1) == "*")
+ {
+ // two wildcards
+ // as we need multi-replacement here...
+ s = substring(ear.message, 1, -2);
+ l -= 2;
+ if(strstrofs(msg, s, 0) >= 0)
+ matchstart = -2; // we use strreplace on s
+ }
+ else
+ {
+ // match at start
+ s = substring(ear.message, 1, -1);
+ l -= 1;
+ if(substring(msg, -l, l) == s)
+ matchstart = strlen(msg) - l;
+ }
+ }
+ else
+ {
+ if(substring(ear.message, -1, 1) == "*")
+ {
+ // match at end
+ s = substring(ear.message, 0, -2);
+ l -= 1;
+ if(substring(msg, 0, l) == s)
+ matchstart = 0;
+ }
+ else
+ {
+ // full match
+ s = ear.message;
+ if(msg == ear.message)
+ matchstart = 0;
+ }
+ }
+
+ if(matchstart == -1) // no match
+ return msgin;
+
+ magicear_matched = true;
+
+ if(dotrigger)
+ {
+ oldself = self;
+ activator = source;
+ self = ear;
+ savemessage = self.message;
+ self.message = string_null;
+ SUB_UseTargets();
+ self.message = savemessage;
+ self = oldself;
+ }
+
+ if(ear.spawnflags & 16)
+ {
+ return ear.netname;
+ }
+ else if(ear.netname != "")
+ {
+ if(matchstart < 0)
+ return strreplace(s, ear.netname, msg);
+ else
+ return strcat(
+ substring(msg, 0, matchstart),
+ ear.netname,
+ substring(msg, matchstart + l, -1)
+ );
+ }
+ else
+ return msgin;
+}
+
+entity magicears;
+string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin)
+{
+ entity ear;
+ string msgout;
+ for(ear = magicears; ear; ear = ear.enemy)
+ {
+ msgout = trigger_magicear_processmessage(ear, source, teamsay, privatesay, msgin);
+ if(!(ear.spawnflags & 64))
+ if(magicear_matched)
+ return msgout;
+ msgin = msgout;
+ }
+ return msgin;
+}
+
+void spawnfunc_trigger_magicear()
+{
+ self.enemy = magicears;
+ magicears = self;
+
+ // actually handled in "say" processing
+ // spawnflags:
+ // 1 = ignore say
+ // 2 = ignore teamsay
+ // 4 = ignore tell
+ // 8 = ignore tell to unknown player
+ // 16 = let netname replace the whole message (otherwise, netname is a word replacement if set)
+ // 32 = perform the replacement even if outside the radius or dead
+ // 64 = continue replacing/triggering even if this one matched
+ // 128 = don't decolorize message before matching
+ // 256 = message is a tuba note sequence (pitch.duration pitch.duration ...)
+ // 512 = tuba notes must be exact right pitch, no transposing
+ // message: either
+ // *pattern*
+ // or
+ // *pattern
+ // or
+ // pattern*
+ // or
+ // pattern
+ // netname:
+ // if set, replacement for the matched text
+ // radius:
+ // "hearing distance"
+ // target:
+ // what to trigger
+ // movedir:
+ // for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter)
+
+ self.movedir_x -= 1; // map to tuba instrument numbers
+}
+#endif
--- /dev/null
+#ifdef SVQC
+/*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
+"Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
+*/
+void monoflop_use()
+{
+ self.nextthink = time + self.wait;
+ self.enemy = activator;
+ if(self.state)
+ return;
+ self.state = 1;
+ SUB_UseTargets();
+}
+void monoflop_fixed_use()
+{
+ if(self.state)
+ return;
+ self.nextthink = time + self.wait;
+ self.state = 1;
+ self.enemy = activator;
+ SUB_UseTargets();
+}
+
+void monoflop_think()
+{
+ self.state = 0;
+ activator = self.enemy;
+ SUB_UseTargets();
+}
+
+void monoflop_reset()
+{
+ self.state = 0;
+ self.nextthink = 0;
+}
+
+void spawnfunc_trigger_monoflop()
+{
+ if(!self.wait)
+ self.wait = 1;
+ if(self.spawnflags & 1)
+ self.use = monoflop_fixed_use;
+ else
+ self.use = monoflop_use;
+ self.think = monoflop_think;
+ self.state = 0;
+ self.reset = monoflop_reset;
+}
+#endif
--- /dev/null
+// NOTE: also contains trigger_once at bottom
+
+#ifdef SVQC
+// the wait time has passed, so set back up for another activation
+void multi_wait()
+{
+ if (self.max_health)
+ {
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_YES;
+ self.solid = SOLID_BBOX;
+ }
+}
+
+
+// the trigger was just touched/killed/used
+// self.enemy should be set to the activator so it can be held through a delay
+// so wait for the delay time before firing
+void multi_trigger()
+{
+ if (self.nextthink > time)
+ {
+ return; // allready been triggered
+ }
+
+ if (self.classname == "trigger_secret")
+ {
+ if (!IS_PLAYER(self.enemy))
+ return;
+ found_secrets = found_secrets + 1;
+ WriteByte (MSG_ALL, SVC_FOUNDSECRET);
+ }
+
+ if (self.noise)
+ sound (self.enemy, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+
+// don't trigger again until reset
+ self.takedamage = DAMAGE_NO;
+
+ activator = self.enemy;
+ other = self.goalentity;
+ SUB_UseTargets();
+
+ if (self.wait > 0)
+ {
+ self.think = multi_wait;
+ self.nextthink = time + self.wait;
+ }
+ else if (self.wait == 0)
+ {
+ multi_wait(); // waiting finished
+ }
+ else
+ { // we can't just remove (self) here, because this is a touch function
+ // called wheil C code is looping through area links...
+ self.touch = func_null;
+ }
+}
+
+void multi_use()
+{
+ self.goalentity = other;
+ self.enemy = activator;
+ multi_trigger();
+}
+
+void multi_touch()
+{
+ if(!(self.spawnflags & 2))
+ if(!other.iscreature)
+ return;
+
+ if(self.team)
+ if(((self.spawnflags & 4) == 0) == (self.team != other.team))
+ return;
+
+// if the trigger has an angles field, check player's facing direction
+ if (self.movedir != '0 0 0')
+ {
+ makevectors (other.angles);
+ if (v_forward * self.movedir < 0)
+ return; // not facing the right way
+ }
+
+ EXACTTRIGGER_TOUCH;
+
+ self.enemy = other;
+ self.goalentity = other;
+ multi_trigger ();
+}
+
+void multi_eventdamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ if (!self.takedamage)
+ return;
+ if(self.spawnflags & DOOR_NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ self.health = self.health - damage;
+ if (self.health <= 0)
+ {
+ self.enemy = attacker;
+ self.goalentity = inflictor;
+ multi_trigger();
+ }
+}
+
+void multi_reset()
+{
+ if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
+ self.touch = multi_touch;
+ if (self.max_health)
+ {
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_YES;
+ self.solid = SOLID_BBOX;
+ }
+ self.think = func_null;
+ self.nextthink = 0;
+ self.team = self.team_saved;
+}
+
+/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
+Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
+If "delay" is set, the trigger waits some time after activating before firing.
+"wait" : Seconds between triggerings. (.2 default)
+If notouch is set, the trigger is only fired by other entities, not by touching.
+NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
+sounds
+1) secret
+2) beep beep
+3) large switch
+4)
+set "message" to text string
+*/
+void spawnfunc_trigger_multiple()
+{
+ self.reset = multi_reset;
+ if (self.sounds == 1)
+ {
+ precache_sound ("misc/secret.wav");
+ self.noise = "misc/secret.wav";
+ }
+ else if (self.sounds == 2)
+ {
+ precache_sound ("misc/talk.wav");
+ self.noise = "misc/talk.wav";
+ }
+ else if (self.sounds == 3)
+ {
+ precache_sound ("misc/trigger1.wav");
+ self.noise = "misc/trigger1.wav";
+ }
+
+ if (!self.wait)
+ self.wait = 0.2;
+ else if(self.wait < -1)
+ self.wait = 0;
+ self.use = multi_use;
+
+ EXACTTRIGGER_INIT;
+
+ self.team_saved = self.team;
+
+ if (self.health)
+ {
+ if (self.spawnflags & SPAWNFLAG_NOTOUCH)
+ objerror ("health and notouch don't make sense\n");
+ self.max_health = self.health;
+ self.event_damage = multi_eventdamage;
+ self.takedamage = DAMAGE_YES;
+ self.solid = SOLID_BBOX;
+ setorigin (self, self.origin); // make sure it links into the world
+ }
+ else
+ {
+ if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
+ {
+ self.touch = multi_touch;
+ setorigin (self, self.origin); // make sure it links into the world
+ }
+ }
+}
+
+
+/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
+Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
+"targetname". If "health" is set, the trigger must be killed to activate.
+If notouch is set, the trigger is only fired by other entities, not by touching.
+if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
+if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
+sounds
+1) secret
+2) beep beep
+3) large switch
+4)
+set "message" to text string
+*/
+void spawnfunc_trigger_once()
+{
+ self.wait = -1;
+ spawnfunc_trigger_multiple();
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void multi_trigger();
+void multi_reset();
+
+void spawnfunc_trigger_once();
+#endif
--- /dev/null
+#ifdef SVQC
+void multivibrator_send()
+{
+ float newstate;
+ float cyclestart;
+
+ cyclestart = floor((time + self.phase) / (self.wait + self.respawntime)) * (self.wait + self.respawntime) - self.phase;
+
+ newstate = (time < cyclestart + self.wait);
+
+ activator = self;
+ if(self.state != newstate)
+ SUB_UseTargets();
+ self.state = newstate;
+
+ if(self.state)
+ self.nextthink = cyclestart + self.wait + 0.01;
+ else
+ self.nextthink = cyclestart + self.wait + self.respawntime + 0.01;
+}
+
+void multivibrator_toggle()
+{
+ if(self.nextthink == 0)
+ {
+ multivibrator_send();
+ }
+ else
+ {
+ if(self.state)
+ {
+ SUB_UseTargets();
+ self.state = 0;
+ }
+ self.nextthink = 0;
+ }
+}
+
+void multivibrator_reset()
+{
+ if(!(self.spawnflags & 1))
+ self.nextthink = 0; // wait for a trigger event
+ else
+ self.nextthink = max(1, time);
+}
+
+/*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
+"Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
+-------- KEYS --------
+target: trigger all entities with this targetname when it goes off
+targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
+phase: offset of the timing
+wait: "on" cycle time (default: 1)
+respawntime: "off" cycle time (default: same as wait)
+-------- SPAWNFLAGS --------
+START_ON: assume it is already turned on (when targeted)
+*/
+void spawnfunc_trigger_multivibrator()
+{
+ if(!self.wait)
+ self.wait = 1;
+ if(!self.respawntime)
+ self.respawntime = self.wait;
+
+ self.state = 0;
+ self.use = multivibrator_toggle;
+ self.think = multivibrator_send;
+ self.nextthink = max(1, time);
+
+ IFTARGETED
+ multivibrator_reset();
+}
+#endif
--- /dev/null
+#ifdef SVQC
+/*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
+This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
+*/
+void spawnfunc_trigger_relay()
+{
+ self.use = SUB_UseTargets;
+ self.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void relay_activators_use()
+{
+ entity trg, os;
+
+ os = self;
+
+ for(trg = world; (trg = find(trg, targetname, os.target)); )
+ {
+ self = trg;
+ if (trg.setactive)
+ trg.setactive(os.cnt);
+ else
+ {
+ //bprint("Not using setactive\n");
+ if(os.cnt == ACTIVE_TOGGLE)
+ if(trg.active == ACTIVE_ACTIVE)
+ trg.active = ACTIVE_NOT;
+ else
+ trg.active = ACTIVE_ACTIVE;
+ else
+ trg.active = os.cnt;
+ }
+ }
+ self = os;
+}
+
+void spawnfunc_relay_activate()
+{
+ self.cnt = ACTIVE_ACTIVE;
+ self.use = relay_activators_use;
+}
+
+void spawnfunc_relay_deactivate()
+{
+ self.cnt = ACTIVE_NOT;
+ self.use = relay_activators_use;
+}
+
+void spawnfunc_relay_activatetoggle()
+{
+ self.cnt = ACTIVE_TOGGLE;
+ self.use = relay_activators_use;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void trigger_relay_if_use()
+{
+ float n;
+ n = self.count;
+
+ // TODO make this generic AND faster than nextent()ing through all, if somehow possible
+ n = (cvar_string(self.netname) == cvar_string(self.message));
+ if(self.spawnflags & 1)
+ n = !n;
+
+ if(n)
+ SUB_UseTargets();
+}
+
+void spawnfunc_trigger_relay_if()
+{
+ self.use = trigger_relay_if_use;
+}
+#endif
--- /dev/null
+#ifdef SVQC
+void trigger_relay_teamcheck_use()
+{
+ if(activator.team)
+ {
+ if(self.spawnflags & 2)
+ {
+ if(DIFF_TEAM(activator, self))
+ SUB_UseTargets();
+ }
+ else
+ {
+ if(SAME_TEAM(activator, self))
+ SUB_UseTargets();
+ }
+ }
+ else
+ {
+ if(self.spawnflags & 1)
+ SUB_UseTargets();
+ }
+}
+
+void trigger_relay_teamcheck_reset()
+{
+ self.team = self.team_saved;
+}
+
+void spawnfunc_trigger_relay_teamcheck()
+{
+ self.team_saved = self.team;
+ self.use = trigger_relay_teamcheck_use;
+ self.reset = trigger_relay_teamcheck_reset;
+}
+#endif
--- /dev/null
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../../server/_all.qh"
+ #include "../../util.qh"
+ #include "../../../server/defs.qh"
+ #include "secret.qh"
+#endif
+
+#ifdef SVQC
+
+void secrets_setstatus() {
+ self.stat_secrets_total = secrets_total;
+ self.stat_secrets_found = secrets_found;
+}
+
+/**
+ * A secret has been found (maybe :P)
+ */
+void trigger_secret_touch() {
+ // only a player can trigger this
+ if (!IS_PLAYER(other))
+ return;
+
+ // update secrets found counter
+ secrets_found += 1;
+ //print("Secret found: ", ftos(secret_counter.cnt), "/");
+ //print(ftos(secret_counter.count), "\n");
+
+ // centerprint message (multi_touch() doesn't always call centerprint())
+ centerprint(other, self.message);
+ self.message = "";
+
+ // handle normal trigger features
+ multi_touch();
+ remove(self);
+}
+
+/*QUAKED trigger_secret (.5 .5 .5) ?
+Variable sized secret trigger. Can be targeted at one or more entities.
+Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
+-------- KEYS --------
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
+noise: path to sound file, if you want to play something else
+target: trigger all entities with this targetname when triggered
+message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
+killtarget: remove all entities with this targetname when triggered
+-------- NOTES --------
+You should create a common/trigger textured brush covering the entrance to a secret room/area.
+Trigger secret can only be trigger by a player's touch and can not be a target itself.
+*/
+void spawnfunc_trigger_secret() {
+ // FIXME: should it be disabled in most modes?
+
+ // update secrets count
+ secrets_total += 1;
+
+ // add default message
+ if (self.message == "")
+ self.message = "You found a secret!";
+
+ // set default sound
+ if (self.noise == "")
+ if (!self.sounds)
+ self.sounds = 1; // misc/secret.wav
+
+ // this entity can't be a target itself!!!!
+ self.targetname = "";
+
+ // you can't just shoot a room to find it, can you?
+ self.health = 0;
+
+ // a secret can not be delayed
+ self.delay = 0;
+
+ // convert this trigger to trigger_once
+ self.classname = "trigger_once";
+ spawnfunc_trigger_once();
+
+ // take over the touch() function, so we can mark secret as found
+ self.touch = trigger_secret_touch;
+ // ignore triggering;
+ self.use = func_null;
+}
+#endif
--- /dev/null
+#ifndef SECRET_H
+#define SECRET_H
+#ifdef SVQC
+
+/**
+ * Total number of secrets on the map.
+ */
+float secrets_total;
+
+/**
+ * Total numbe of secrets found on the map.
+ */
+float secrets_found;
+
+
+.float stat_secrets_total;
+.float stat_secrets_found;
+
+/**
+ * update secrets status.
+ */
+void secrets_setstatus();
+#endif
+#endif
--- /dev/null
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../../server/_all.qh"
+ #include "../../../warpzonelib/util_server.qh"
+ #include "../../weapons/all.qh"
+ #include "../../../server/defs.qh"
+ #include "../../deathtypes.qh"
+#endif
+
+/*
+* t_swamp.c
+* Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
+* Author tZork (Jakob MG)
+* jakob@games43.se
+* 2005 11 29
+*/
+
+.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 (!?)
+.entity swampslug;
+
+#ifdef SVQC
+void spawnfunc_trigger_swamp(void);
+#endif
+void swamp_touch(void);
+void swampslug_think();
+
+
+/*
+* Uses a entity calld swampslug to handle players in the swamp
+* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
+* attaches a new "swampslug" to the player. As long as the plyer is inside
+* the swamp the swamp gives the slug new health. But the slug slowly kills itself
+* so when the player goes outside the swamp, it dies and releases the player from the
+* swamps curses (dmg/slowdown)
+*
+* I do it this way becuz there is no "untouch" event.
+*/
+void swampslug_think(void)
+{
+ //Slowly kill the slug
+ self.health = self.health - 1;
+
+ //Slug dead? then remove curses.
+ if(self.health <= 0)
+ {
+ self.owner.in_swamp = 0;
+ remove(self);
+ //centerprint(self.owner,"Killing slug...\n");
+ return;
+ }
+
+ // Slug still alive, so we are still in the swamp
+ // Or we have exited it very recently.
+ // Do the damage and renew the timer.
+#ifdef SVQC
+ Damage (self.owner, self, self, self.dmg, DEATH_SWAMP, other.origin, '0 0 0');
+#endif
+
+ self.nextthink = time + self.swamp_interval;
+}
+
+void swamp_touch(void)
+{
+ // If whatever thats touching the swamp is not a player
+ // or if its a dead player, just dont care abt it.
+ if(!IS_PLAYER(other) || PHYS_DEAD(other))
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ // Chech if player alredy got a swampslug.
+ if(other.in_swamp != 1)
+ {
+ // If not attach one.
+ //centerprint(other,"Entering swamp!\n");
+ other.swampslug = spawn();
+ other.swampslug.health = 2;
+ other.swampslug.think = swampslug_think;
+ other.swampslug.nextthink = time;
+ other.swampslug.owner = other;
+ other.swampslug.dmg = self.dmg;
+ other.swampslug.swamp_interval = self.swamp_interval;
+ other.swamp_slowdown = self.swamp_slowdown;
+ other.in_swamp = 1;
+ return;
+ }
+
+ //other.in_swamp = 1;
+
+ //Revitalize players swampslug
+ other.swampslug.health = 2;
+}
+
+#ifdef SVQC
+float swamp_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
+
+ WriteByte(MSG_ENTITY, self.dmg); // can probably get away with using a single byte here
+ WriteByte(MSG_ENTITY, self.swamp_slowdown);
+ WriteByte(MSG_ENTITY, self.swamp_interval);
+
+ trigger_common_write(false);
+
+ return true;
+}
+
+void swamp_link()
+{
+ Net_LinkEntity(self, false, 0, func_ladder_send);
+}
+
+/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
+Players gettin into the swamp will
+get slowd down and damaged
+*/
+void spawnfunc_trigger_swamp(void)
+{
+ // Init stuff
+ EXACTTRIGGER_INIT;
+ self.touch = swamp_touch;
+
+ // Setup default keys, if missing
+ if(self.dmg <= 0)
+ self.dmg = 5;
+ if(self.swamp_interval <= 0)
+ self.swamp_interval = 1;
+ if(self.swamp_slowdown <= 0)
+ self.swamp_slowdown = 0.5;
+
+ swamp_link();
+}
+
+#elif defined(CSQC)
+
+void ent_swamp()
+{
+ self.dmg = ReadByte();
+ self.swamp_slowdown = ReadByte();
+ self.swamp_interval = ReadByte();
+
+ trigger_common_read(false);
+
+ self.classname = "trigger_swamp";
+ self.solid = SOLID_TRIGGER;
+ self.draw = trigger_draw_generic;
+ self.trigger_touch = swamp_touch;
+ self.drawmask = MASK_NORMAL;
+ self.move_time = time;
+ self.entremove = trigger_remove_generic;
+}
+#endif
--- /dev/null
+#ifndef TRIGGER_SWAMP_H
+#define TRIGGER_SWAMP_H
+
+.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 (!?)
+.entity swampslug;
+
+.float in_swamp; // bool
+.entity swampslug; // Uses this to release from swamp ("untouch" fix)
+
+#ifdef CSQC
+void ent_swamp();
+#endif
+
+#endif
--- /dev/null
+#ifdef SVQC
+void trigger_teleport_use()
+{
+ if(teamplay)
+ self.team = activator.team;
+#ifdef SVQC
+ self.SendFlags |= SF_TRIGGER_UPDATE;
+#endif
+}
+
+void Teleport_Touch (void)
+{
+ entity oldself;
+ string s;
+
+ if (self.active != ACTIVE_ACTIVE)
+ return;
+
+ if (!other.teleportable)
+ return;
+
+ if(other.vehicle)
+ if(!other.vehicle.teleportable)
+ return;
+
+ if(other.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
+ return;
+
+ if(other.deadflag != DEAD_NO)
+ return;
+
+ if(self.team)
+ if(((self.spawnflags & 4) == 0) == (self.team != other.team))
+ return;
+
+ EXACTTRIGGER_TOUCH;
+
+ if(IS_PLAYER(other))
+ RemoveGrapplingHook(other);
+
+ entity e;
+ e = Simple_TeleportPlayer(self, other);
+
+ activator = other;
+ s = self.target; self.target = string_null;
+ SUB_UseTargets();
+ if (!self.target) self.target = s;
+
+ oldself = self;
+ self = e;
+ SUB_UseTargets();
+ self = oldself;
+}
+
+void spawnfunc_trigger_teleport()
+{
+ self.angles = '0 0 0';
+
+ EXACTTRIGGER_INIT;
+
+ self.active = ACTIVE_ACTIVE;
+
+ self.use = trigger_teleport_use;
+
+ // this must be called to spawn the teleport waypoints for bots
+ InitializeEntity(self, teleport_findtarget, INITPRIO_FINDTARGET);
+
+ if (self.target == "")
+ {
+ objerror ("Teleporter with no target");
+ return;
+ }
+
+ self.teleport_next = teleport_first;
+ teleport_first = self;
+}
+#endif
--- /dev/null
+void SUB_DontUseTargets() { }
+
+void() SUB_UseTargets;
+
+void DelayThink()
+{
+ activator = self.enemy;
+ SUB_UseTargets ();
+ remove(self);
+}
+
+void FixSize(entity e)
+{
+ e.mins_x = rint(e.mins_x);
+ e.mins_y = rint(e.mins_y);
+ e.mins_z = rint(e.mins_z);
+
+ e.maxs_x = rint(e.maxs_x);
+ e.maxs_y = rint(e.maxs_y);
+ e.maxs_z = rint(e.maxs_z);
+}
+
+#ifdef SVQC
+void trigger_common_write(bool withtarget)
+{
+ WriteByte(MSG_ENTITY, self.warpzone_isboxy);
+ WriteByte(MSG_ENTITY, self.scale);
+
+ if(withtarget)
+ {
+ WriteString(MSG_ENTITY, self.target);
+ WriteString(MSG_ENTITY, self.target2);
+ WriteString(MSG_ENTITY, self.target3);
+ WriteString(MSG_ENTITY, self.target4);
+ WriteString(MSG_ENTITY, self.targetname);
+ WriteString(MSG_ENTITY, self.killtarget);
+ }
+
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteCoord(MSG_ENTITY, self.mins_x);
+ WriteCoord(MSG_ENTITY, self.mins_y);
+ WriteCoord(MSG_ENTITY, self.mins_z);
+ WriteCoord(MSG_ENTITY, self.maxs_x);
+ WriteCoord(MSG_ENTITY, self.maxs_y);
+ WriteCoord(MSG_ENTITY, self.maxs_z);
+
+ WriteCoord(MSG_ENTITY, self.movedir_x);
+ WriteCoord(MSG_ENTITY, self.movedir_y);
+ WriteCoord(MSG_ENTITY, self.movedir_z);
+
+ WriteCoord(MSG_ENTITY, self.angles_x);
+ WriteCoord(MSG_ENTITY, self.angles_y);
+ WriteCoord(MSG_ENTITY, self.angles_z);
+}
+
+#elif defined(CSQC)
+
+void trigger_common_read(bool withtarget)
+{
+ self.warpzone_isboxy = ReadByte();
+ self.scale = ReadByte();
+
+ if(withtarget)
+ {
+ self.target = strzone(ReadString());
+ self.target2 = strzone(ReadString());
+ self.target3 = strzone(ReadString());
+ self.target4 = strzone(ReadString());
+ self.targetname = strzone(ReadString());
+ self.killtarget = strzone(ReadString());
+ }
+
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+
+ self.mins_x = ReadCoord();
+ self.mins_y = ReadCoord();
+ self.mins_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ setsize(self, self.mins, self.maxs);
+
+ self.movedir_x = ReadCoord();
+ self.movedir_y = ReadCoord();
+ self.movedir_z = ReadCoord();
+
+ self.angles_x = ReadCoord();
+ self.angles_y = ReadCoord();
+ self.angles_z = ReadCoord();
+}
+
+void trigger_remove_generic()
+{
+ if(self.target) { strunzone(self.target); }
+ self.target = string_null;
+
+ if(self.target2) { strunzone(self.target2); }
+ self.target2 = string_null;
+
+ if(self.target3) { strunzone(self.target3); }
+ self.target3 = string_null;
+
+ if(self.target4) { strunzone(self.target4); }
+ self.target4 = string_null;
+
+ if(self.targetname) { strunzone(self.targetname); }
+ self.target = string_null;
+
+ if(self.killtarget) { strunzone(self.killtarget); }
+ self.killtarget = string_null;
+}
+#endif
+
+/*
+==============================
+SUB_UseTargets
+
+the global "activator" should be set to the entity that initiated the firing.
+
+If self.delay is set, a DelayedUse entity will be created that will actually
+do the SUB_UseTargets after that many seconds have passed.
+
+Centerprints any self.message to the activator.
+
+Removes all entities with a targetname that match self.killtarget,
+and removes them, so some events can remove other triggers.
+
+Search for (string)targetname in all entities that
+match (string)self.target and call their .use function
+
+==============================
+*/
+void SUB_UseTargets()
+{
+ entity t, stemp, otemp, act;
+ string s;
+ float i;
+
+//
+// check for a delay
+//
+ if (self.delay)
+ {
+ // create a temp object to fire at a later time
+ t = spawn();
+ t.classname = "DelayedUse";
+ t.nextthink = time + self.delay;
+ t.think = DelayThink;
+ t.enemy = activator;
+ t.message = self.message;
+ t.killtarget = self.killtarget;
+ t.target = self.target;
+ t.target2 = self.target2;
+ t.target3 = self.target3;
+ t.target4 = self.target4;
+ return;
+ }
+
+
+//
+// print the message
+//
+#ifdef SVQC
+ if(self)
+ if(IS_PLAYER(activator) && self.message != "")
+ if(IS_REAL_CLIENT(activator))
+ {
+ centerprint(activator, self.message);
+ if (self.noise == "")
+ play2(activator, "misc/talk.wav");
+ }
+
+//
+// kill the killtagets
+//
+ s = self.killtarget;
+ if (s != "")
+ {
+ for(t = world; (t = find(t, targetname, s)); )
+ remove(t);
+ }
+#endif
+
+//
+// fire targets
+//
+ act = activator;
+ stemp = self;
+ otemp = other;
+
+ if(stemp.target_random)
+ RandomSelection_Init();
+
+ for(i = 0; i < 4; ++i)
+ {
+ switch(i)
+ {
+ default:
+ case 0: s = stemp.target; break;
+ case 1: s = stemp.target2; break;
+ case 2: s = stemp.target3; break;
+ case 3: s = stemp.target4; break;
+ }
+ if (s != "")
+ {
+ // Flag to set func_clientwall state
+ // 1 == deactivate, 2 == activate, 0 == do nothing
+ float aw_flag = self.antiwall_flag;
+ for(t = world; (t = find(t, targetname, s)); )
+ if(t.use)
+ {
+ if(stemp.target_random)
+ {
+ RandomSelection_Add(t, 0, string_null, 1, 0);
+ }
+ else
+ {
+ if (t.classname == "func_clientwall" || t.classname == "func_clientillusionary")
+ t.antiwall_flag = aw_flag;
+ self = t;
+ other = stemp;
+ activator = act;
+ self.use();
+ }
+ }
+ }
+ }
+
+ if(stemp.target_random && RandomSelection_chosen_ent)
+ {
+ self = RandomSelection_chosen_ent;
+ other = stemp;
+ activator = act;
+ self.use();
+ }
+
+ activator = act;
+ self = stemp;
+ other = otemp;
+}
+
+#ifdef CSQC
+void trigger_touch_generic(void() touchfunc)
+{
+ entity e;
+ for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
+ if(e.isplayermodel || e.classname == "csqcprojectile")
+ {
+ vector emin = e.absmin, emax = e.absmax;
+ if(self.solid == SOLID_BSP)
+ {
+ emin -= '1 1 1';
+ emax += '1 1 1';
+ }
+ if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
+ if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
+ {
+ other = e;
+ touchfunc();
+ }
+ }
+}
+void trigger_draw_generic()
+{
+ float dt = time - self.move_time;
+ self.move_time = time;
+ if(dt <= 0) { return; }
+
+ if(self.trigger_touch) { trigger_touch_generic(self.trigger_touch); }
+}
+#endif
--- /dev/null
+#ifndef TRIGGERS_H
+#define TRIGGERS_H
+
+const float SF_TRIGGER_INIT = 1;
+const float SF_TRIGGER_UPDATE = 2;
+const float SF_TRIGGER_RESET = 4;
+
+const float SPAWNFLAG_NOMESSAGE = 1;
+const float SPAWNFLAG_NOTOUCH = 1;
+
+.void() trigger_touch;
+
+.float antiwall_flag; // Variable to define what to do with func_clientwall
+// 0 == do nothing, 1 == deactivate, 2 == activate
+
+.float height;
+
+.float nottargeted;
+#define IFTARGETED if(!self.nottargeted && self.targetname != "")
+
+.float lip;
+
+// used elsewhere (will fix)
+#ifdef SVQC
+void trigger_common_write(bool withtarget);
+
+string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin);
+
+void target_voicescript_next(entity pl);
+void target_voicescript_clear(entity pl);
+#endif
+
+.float volume, atten;
+
+.vector dest;
+
+#ifdef CSQC
+void trigger_common_read(bool withtarget);
+void trigger_remove_generic();
+
+.float active;
+.string target;
+.string targetname;
+
+const int ACTIVE_NOT = 0;
+const int ACTIVE_ACTIVE = 1;
+const int ACTIVE_IDLE = 2;
+const int ACTIVE_BUSY = 2;
+const int ACTIVE_TOGGLE = 3;
+#endif
+
+#endif
#define int float
#define stoi(s) stof(s)
- #define itos(s) ftos(s)
+ #define stob(s) stof(s)
+ #define itos(i) ftos(i)
+#else
+ #define stoi(s) ((int) stof(s))
+ #define stob(s) ((bool) stof(s))
+ #define itos(i) ftos(i)
#endif
#ifndef QCC_SUPPORT_BOOL
const int false = 0;
#endif
+#ifndef QCC_SUPPORT_ENTITYCLASS
+ #define entityclass(name) typedef entity name
+ #define class(name)
+ #define new(class) spawn()
+#else
+ #define entityclass(name) entityclass name {}
+ #define class(name) [[class(name)]]
+ #define new(class) ((class) spawn())
+#endif
+
// Transitional aliases
[[deprecated("use true")]] [[alias("true")]] const bool TRUE;
[[deprecated("use false")]] [[alias("false")]] const bool FALSE;
+#ifdef GMQCC
+ #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+#else
+ #define OVERLOAD_(F,_9,_8,_7,_6,_5,_4,_3,_2,_1,n,...) F##_##n
+ #define OVERLOAD(F, ...) OVERLOAD_(F,__VA_ARGS__,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)
+#endif
+
+#define LAMBDA(...) { __VA_ARGS__ ; }
+
+#define MAP(f, ...) OVERLOAD(MAP, f, __VA_ARGS__)
+#define MAP_2(f, it) f(it)
+#define MAP_3(f, it, ...) f(it)MAP_2(f, __VA_ARGS__)
+#define MAP_4(f, it, ...) f(it)MAP_3(f, __VA_ARGS__)
+#define MAP_5(f, it, ...) f(it)MAP_4(f, __VA_ARGS__)
+#define MAP_6(f, it, ...) f(it)MAP_5(f, __VA_ARGS__)
+#define MAP_7(f, it, ...) f(it)MAP_6(f, __VA_ARGS__)
+#define MAP_8(f, it, ...) f(it)MAP_7(f, __VA_ARGS__)
+#define MAP_9(f, it, ...) f(it)MAP_8(f, __VA_ARGS__)
+#define MAP_10(f, it, ...) f(it)MAP_9(f, __VA_ARGS__)
+#define MAP_11(f, it, ...) f(it)MAP_10(f, __VA_ARGS__)
+#define MAP_12(f, it, ...) f(it)MAP_11(f, __VA_ARGS__)
+#define MAP_13(f, it, ...) f(it)MAP_12(f, __VA_ARGS__)
+#define MAP_14(f, it, ...) f(it)MAP_13(f, __VA_ARGS__)
+#define MAP_15(f, it, ...) f(it)MAP_14(f, __VA_ARGS__)
+#define MAP_16(f, it, ...) f(it)MAP_15(f, __VA_ARGS__)
+#define MAP_17(f, it, ...) f(it)MAP_16(f, __VA_ARGS__)
+#define MAP_18(f, it, ...) f(it)MAP_17(f, __VA_ARGS__)
+#define MAP_19(f, it, ...) f(it)MAP_18(f, __VA_ARGS__)
+#define MAP_20(f, it, ...) f(it)MAP_19(f, __VA_ARGS__)
+
+#define IDENTITY(it) it
+
+#define UNWORDS(...) MAP(IDENTITY, __VA_ARGS__)
+
+#define APPLY(f, ...) f(__VA_ARGS__)
+
+#ifdef SVQC
+ #define SV(f, ...) f(__VA_ARGS__)
+#else
+ #define SV(f, ...)
+#endif
+
+#ifdef CSQC
+ #define CL(f, ...) f(__VA_ARGS__)
+#else
+ #define CL(f, ...)
+#endif
+
+#define IF(cond, f, ...) cond(f, __VA_ARGS__)
+
+#define GET(name) name##get
+#define GETTER(type, name) type GET(name)() { return name; }
+
+#define BIT(n) (1 << (n))
+#ifndef BRANCHLESS_BITSET
+ #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask))
+#else
+ #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask))
+#endif
+
#endif
entity e;
e = start;
funcPre(pass, e);
- while(e.downleft)
+ while (e.(downleft))
{
- e = e.downleft;
+ e = e.(downleft);
funcPre(pass, e);
}
funcPost(pass, e);
while(e != start)
{
- if(e.right)
+ if (e.(right))
{
- e = e.right;
+ e = e.(right);
funcPre(pass, e);
- while(e.downleft)
+ while (e.(downleft))
{
- e = e.downleft;
+ e = e.(downleft);
funcPre(pass, e);
}
}
else
- e = e.up;
+ e = e.(up);
funcPost(pass, e);
}
}
}
#ifndef MENUQC
-vector healtharmor_maxdamage(float h, float a, float armorblock, float deathtype)
+vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype)
{
// NOTE: we'll always choose the SMALLER value...
float healthdamage, armordamage, armorideal;
return v;
}
-vector healtharmor_applydamage(float a, float armorblock, float deathtype, float damage)
+vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage)
{
vector v;
if (deathtype == DEATH_DROWN) // Why should armor help here...
return ((a * 22 + b) * 22 + c) * 22 + d;
}
-float lowestbit(int f)
+int lowestbit(int f)
{
f &= ~(f * 2);
f &= ~(f * 4);
// start with a 1-element queue
queue_start = queue_end = e;
- queue_end.fld = world;
+ queue_end.(fld) = world;
queue_end.FindConnectedComponent_processing = 1;
// for each queued item:
- for (; queue_start; queue_start = queue_start.fld)
+ for (; queue_start; queue_start = queue_start.(fld))
{
// find all neighbors of queue_start
entity t;
if(iscon(t, queue_start, pass))
{
// it is connected? ADD IT. It will look for neighbors soon too.
- queue_end.fld = t;
+ queue_end.(fld) = t;
queue_end = t;
- queue_end.fld = world;
+ queue_end.(fld) = world;
queue_end.FindConnectedComponent_processing = 1;
}
}
}
// unmark
- for(queue_start = e; queue_start; queue_start = queue_start.fld)
+ for (queue_start = e; queue_start; queue_start = queue_start.(fld))
queue_start.FindConnectedComponent_processing = 0;
}
#ifdef SVQC
vector combine_to_vector(float x, float y, float z)
{
- vector result; result.x = x; result.y = y; result.z = z;
+ vector result; result_x = x; result_y = y; result_z = z;
return result;
}
void RandomSelection_Add(entity e, float f, string s, float weight, float priority);
#ifndef MENUQC
-vector healtharmor_maxdamage(float h, float a, float armorblock, float deathtype); // returns vector: maxdamage, armorideal, 1 if fully armored
-vector healtharmor_applydamage(float a, float armorblock, float deathtype, float damage); // returns vector: take, save, 0
+vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype); // returns vector: maxdamage, armorideal, 1 if fully armored
+vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage); // returns vector: take, save, 0
#endif
string getcurrentmod();
// Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
#define sound(e,c,s,v,a) sound7(e,c,s,v,a,0,0)
-float lowestbit(float f);
+int lowestbit(float f);
#ifdef CSQC
entity ReadCSQCEntity();
string CCR(string input);
#ifndef MENUQC
-#ifdef CSQC
-#define GENTLE (autocvar_cl_gentle || autocvar_cl_gentle_messages)
-#else
-#define GENTLE autocvar_sv_gentle
-#endif
-#define normal_or_gentle(normal,gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal)
+ #ifdef CSQC
+ #define GENTLE (autocvar_cl_gentle || autocvar_cl_gentle_messages)
+ #else
+ #define GENTLE autocvar_sv_gentle
+ #endif
+ #define normal_or_gentle(normal, gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal)
#endif
// allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example)
--- /dev/null
+// ONLY EVER ADD NEW WEAPONS AT THE END. IF YOU REMOVE ONE, PUT THE LAST ONE ON
+// ITS PLACE. THIS IS TO AVOID UNNECESSARY RENUMBERING OF WEAPON IMPULSES.
+// IF YOU DISREGARD THIS NOTICE, I'LL KILL YOU WITH THE @!#%'N TUBA
+
+// core weapons
+#include "w_blaster.qc"
+#include "w_shotgun.qc"
+#include "w_machinegun.qc"
+#include "w_mortar.qc"
+#include "w_minelayer.qc"
+#include "w_electro.qc"
+#include "w_crylink.qc"
+#include "w_vortex.qc"
+#include "w_hagar.qc"
+#include "w_devastator.qc"
+
+// other weapons
+#include "w_porto.qc"
+#include "w_vaporizer.qc"
+#include "w_hook.qc"
+#include "w_hlac.qc"
+#include "w_tuba.qc"
+#include "w_rifle.qc"
+#include "w_fireball.qc"
+#include "w_seeker.qc"
+#include "w_shockwave.qc"
+#include "w_arc.qc"
+#include "w_hmg.qc"
+#include "w_rpc.qc"
--- /dev/null
+#ifndef WEAPONS_ALL_C
+#define WEAPONS_ALL_C
+
+#include "all.qh"
+
+#if defined(CSQC)
+ #include "../../dpdefs/csprogsdefs.qh"
+ #include "../../client/defs.qh"
+ #include "../constants.qh"
+ #include "../stats.qh"
+ #include "../../warpzonelib/anglestransform.qh"
+ #include "../../warpzonelib/mathlib.qh"
+ #include "../../warpzonelib/common.qh"
+ #include "../../warpzonelib/client.qh"
+ #include "../util.qh"
+ #include "../buffs.qh"
+ #include "../../client/autocvars.qh"
+ #include "../deathtypes.qh"
+ #include "../../csqcmodellib/interpolate.qh"
+ #include "../movetypes/movetypes.qh"
+ #include "../../client/main.qh"
+ #include "../../csqcmodellib/cl_model.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../dpdefs/progsdefs.qh"
+ #include "../../dpdefs/dpextensions.qh"
+ #include "../../warpzonelib/anglestransform.qh"
+ #include "../../warpzonelib/mathlib.qh"
+ #include "../../warpzonelib/common.qh"
+ #include "../../warpzonelib/util_server.qh"
+ #include "../../warpzonelib/server.qh"
+ #include "../constants.qh"
+ #include "../stats.qh"
+ #include "../teams.qh"
+ #include "../util.qh"
+ #include "../buffs.qh"
+ #include "../monsters/all.qh"
+ #include "config.qh"
+ #include "../../server/weapons/csqcprojectile.qh"
+ #include "../../server/weapons/tracing.qh"
+ #include "../../server/t_items.qh"
+ #include "../../server/autocvars.qh"
+ #include "../../server/constants.qh"
+ #include "../../server/defs.qh"
+ #include "../notifications.qh"
+ #include "../deathtypes.qh"
+ #include "../../server/mutators/mutators_include.qh"
+ #include "../mapinfo.qh"
+ #include "../../server/command/common.qh"
+ #include "../../csqcmodellib/sv_model.qh"
+ #include "../../server/portals.qh"
+ #include "../../server/g_hook.qh"
+#endif
+#ifndef MENUQC
+#include "calculations.qc"
+#endif
+#include "all.inc"
+
+// WEAPON PLUGIN SYSTEM
+entity weapon_info[WEP_MAXCOUNT];
+entity dummy_weapon_info;
+
+#if WEP_MAXCOUNT > 72
+# error Kein Weltraum links auf dem Gerät
+#endif
+
+WepSet WepSet_FromWeapon(int a) {
+ a -= WEP_FIRST;
+#if WEP_MAXCOUNT > 24
+ if(a >= 24) {
+ a -= 24;
+#if WEP_MAXCOUNT > 48
+ if(a >= 24) {
+ a -= 24;
+ return '0 0 1' * power2of(a);
+ }
+#endif
+ return '0 1 0' * power2of(a);
+ }
+#endif
+ return '1 0 0' * power2of(a);
+}
+#ifdef SVQC
+void WepSet_AddStat()
+{
+ addstat(STAT_WEAPONS, AS_INT, weapons_x);
+#if WEP_MAXCOUNT > 24
+ addstat(STAT_WEAPONS2, AS_INT, weapons_y);
+#if WEP_MAXCOUNT > 48
+ addstat(STAT_WEAPONS3, AS_INT, weapons_z);
+#endif
+#endif
+}
+void WriteWepSet(float dst, WepSet w)
+{
+#if WEP_MAXCOUNT > 48
+ WriteInt72_t(dst, w);
+#elif WEP_MAXCOUNT > 24
+ WriteInt48_t(dst, w);
+#else
+ WriteInt24_t(dst, w.x);
+#endif
+}
+#endif
+#ifdef CSQC
+WepSet WepSet_GetFromStat()
+{
+ WepSet w = '0 0 0';
+ w.x = getstati(STAT_WEAPONS);
+#if WEP_MAXCOUNT > 24
+ w.y = getstati(STAT_WEAPONS2);
+#if WEP_MAXCOUNT > 48
+ w.z = getstati(STAT_WEAPONS3);
+#endif
+#endif
+ return w;
+}
+WepSet ReadWepSet()
+{
+#if WEP_MAXCOUNT > 48
+ return ReadInt72_t();
+#elif WEP_MAXCOUNT > 24
+ return ReadInt48_t();
+#else
+ return ReadInt24_t() * '1 0 0';
+#endif
+}
+#endif
+
+void register_weapon(
+ int id,
+ WepSet bit,
+ bool(int) func,
+ .int ammotype,
+ int i,
+ int weapontype,
+ float pickupbasevalue,
+ vector clr,
+ string modelname,
+ string simplemdl,
+ string crosshair,
+ string wepimg,
+ string refname,
+ string wepname)
+{
+ entity e;
+ weapon_info[id - 1] = e = spawn();
+ e.classname = "weapon_info";
+ e.weapon = id;
+ e.weapons = bit;
+ e.weapon_func = func;
+ e.ammo_field = ammotype;
+ e.impulse = i;
+ e.spawnflags = weapontype;
+ e.bot_pickupbasevalue = pickupbasevalue;
+ e.wpcolor = clr;
+ e.wpmodel = strzone(strcat("wpn-", ftos(id)));
+ e.mdl = modelname;
+ e.model = strzone(strcat("models/weapons/g_", modelname, ".md3"));
+ e.w_simplemdl = strzone(simplemdl); // simpleitems weapon model/image
+ e.w_crosshair = strzone(car(crosshair));
+ string s = cdr(crosshair);
+ e.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
+ e.model2 = strzone(wepimg);
+ e.netname = refname;
+ e.message = wepname;
+
+ #ifdef CSQC
+ func(WR_INIT);
+ #endif
+}
+bool w_null(int dummy)
+{
+ return 0;
+}
+void register_weapons_done()
+{
+ dummy_weapon_info = spawn();
+ dummy_weapon_info.classname = "weapon_info";
+ dummy_weapon_info.weapon = 0; // you can recognize dummies by this
+ dummy_weapon_info.weapons = '0 0 0';
+ dummy_weapon_info.netname = "";
+ dummy_weapon_info.message = "AOL CD Thrower";
+ dummy_weapon_info.weapon_func = w_null;
+ dummy_weapon_info.wpmodel = "";
+ dummy_weapon_info.mdl = "";
+ dummy_weapon_info.model = "";
+ dummy_weapon_info.spawnflags = 0;
+ dummy_weapon_info.impulse = -1;
+ dummy_weapon_info.bot_pickupbasevalue = 0;
+ dummy_weapon_info.ammo_field = ammo_none;
+
+ dummy_weapon_info.w_crosshair = "gfx/crosshair1";
+ dummy_weapon_info.w_crosshair_size = 1;
+ dummy_weapon_info.model2 = "";
+
+ int i;
+ weaponorder_byid = "";
+ for(i = WEP_MAXCOUNT; i >= 1; --i)
+ if(weapon_info[i-1])
+ weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
+ weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
+}
+entity get_weaponinfo(int id)
+{
+ entity w;
+ if(id < WEP_FIRST || id > WEP_LAST)
+ return dummy_weapon_info;
+ w = weapon_info[id - 1];
+ if(w)
+ return w;
+ return dummy_weapon_info;
+}
+string W_FixWeaponOrder(string order, float complete)
+{
+ return fixPriorityList(order, WEP_FIRST, WEP_LAST, 230 - WEP_FIRST, complete);
+}
+string W_NameWeaponOrder_MapFunc(string s)
+{
+ entity wi;
+ if(s == "0" || stof(s))
+ {
+ wi = get_weaponinfo(stof(s));
+ if(wi != dummy_weapon_info)
+ return wi.netname;
+ }
+ return s;
+}
+
+string W_UndeprecateName(string s)
+{
+ switch ( s )
+ {
+ case "nex" : return "vortex";
+ case "rocketlauncher" : return "devastator";
+ case "laser" : return "blaster";
+ case "minstanex" : return "vaporizer";
+ case "grenadelauncher": return "mortar";
+ case "uzi" : return "machinegun";
+ default : return s;
+ }
+}
+string W_NameWeaponOrder(string order)
+{
+ return mapPriorityList(order, W_NameWeaponOrder_MapFunc);
+}
+string W_NumberWeaponOrder_MapFunc(string s)
+{
+ int i;
+ if(s == "0" || stof(s))
+ return s;
+ s = W_UndeprecateName(s);
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ if(s == get_weaponinfo(i).netname)
+ return ftos(i);
+ return s;
+}
+string W_NumberWeaponOrder(string order)
+{
+ return mapPriorityList(order, W_NumberWeaponOrder_MapFunc);
+}
+
+float W_FixWeaponOrder_BuildImpulseList_buf[WEP_MAXCOUNT];
+string W_FixWeaponOrder_BuildImpulseList_order;
+void W_FixWeaponOrder_BuildImpulseList_swap(int i, int j, entity pass)
+{
+ float h;
+ h = W_FixWeaponOrder_BuildImpulseList_buf[i];
+ W_FixWeaponOrder_BuildImpulseList_buf[i] = W_FixWeaponOrder_BuildImpulseList_buf[j];
+ W_FixWeaponOrder_BuildImpulseList_buf[j] = h;
+}
+float W_FixWeaponOrder_BuildImpulseList_cmp(int i, int j, entity pass)
+{
+ entity e1, e2;
+ float d;
+ e1 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[i]);
+ e2 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[j]);
+ d = (e1.impulse + 9) % 10 - (e2.impulse + 9) % 10;
+ if(d != 0)
+ return -d; // high impulse first!
+ return
+ strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0)
+ -
+ strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0)
+ ; // low char index first!
+}
+string W_FixWeaponOrder_BuildImpulseList(string o)
+{
+ int i;
+ W_FixWeaponOrder_BuildImpulseList_order = o;
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST] = i;
+ heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, world);
+ o = "";
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ o = strcat(o, " ", ftos(W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST]));
+ W_FixWeaponOrder_BuildImpulseList_order = string_null;
+ return substring(o, 1, -1);
+}
+
+string W_FixWeaponOrder_AllowIncomplete(string order)
+{
+ return W_FixWeaponOrder(order, 0);
+}
+
+string W_FixWeaponOrder_ForceComplete(string order)
+{
+ if(order == "")
+ order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority"));
+ return W_FixWeaponOrder(order, 1);
+}
+
+void W_RandomWeapons(entity e, float n)
+{
+ int i, j;
+ WepSet remaining;
+ WepSet result;
+ remaining = e.weapons;
+ result = '0 0 0';
+ for(i = 0; i < n; ++i)
+ {
+ RandomSelection_Init();
+ for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+ if(remaining & WepSet_FromWeapon(j))
+ RandomSelection_Add(world, j, string_null, 1, 1);
+ result |= WepSet_FromWeapon(RandomSelection_chosen_float);
+ remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float);
+ }
+ e.weapons = result;
+}
+
+string GetAmmoPicture(.int ammotype)
+{
+ switch(ammotype)
+ {
+ case ammo_shells: return "ammo_shells";
+ case ammo_nails: return "ammo_bullets";
+ case ammo_rockets: return "ammo_rockets";
+ case ammo_cells: return "ammo_cells";
+ case ammo_plasma: return "ammo_cells";
+ case ammo_fuel: return "ammo_fuel";
+ default: return ""; // wtf, no ammo type?
+ }
+}
+
+#ifdef CSQC
+.int GetAmmoFieldFromNum(int i)
+{
+ switch(i)
+ {
+ case 0: return ammo_shells;
+ case 1: return ammo_nails;
+ case 2: return ammo_rockets;
+ case 3: return ammo_cells;
+ case 4: return ammo_plasma;
+ case 5: return ammo_fuel;
+ default: return ammo_none;
+ }
+}
+
+int GetAmmoStat(.int ammotype)
+{
+ switch(ammotype)
+ {
+ case ammo_shells: return STAT_SHELLS;
+ case ammo_nails: return STAT_NAILS;
+ case ammo_rockets: return STAT_ROCKETS;
+ case ammo_cells: return STAT_CELLS;
+ case ammo_plasma: return STAT_PLASMA;
+ case ammo_fuel: return STAT_FUEL;
+ default: return -1;
+ }
+}
+#endif
+#endif
-// TODO: include once
-//#ifndef WEAPONS_ALL_H
-//#define WEAPONS_ALL_H
+#ifndef WEAPONS_ALL_H
+#define WEAPONS_ALL_H
+
+#ifndef MENUQC
+#include "calculations.qh"
+#endif
#include "../util.qh"
+#ifdef SVQC
+#include "../../server/bot/aim.qh"
+#endif
+const int MAX_SHOT_DISTANCE = 32768;
+
+// weapon pickup ratings for bot logic
+const int BOT_PICKUP_RATING_LOW = 2500;
+const int BOT_PICKUP_RATING_MID = 5000;
+const int BOT_PICKUP_RATING_HIGH = 10000;
+// weapon flags
+const int WEP_TYPE_OTHER = 0x00; // not for damaging people
+const int WEP_TYPE_SPLASH = 0x01; // splash damage
+const int WEP_TYPE_HITSCAN = 0x02; // hitscan
+const int WEP_TYPEMASK = 0x0F;
+const int WEP_FLAG_CANCLIMB = 0x10; // can be used for movement
+const int WEP_FLAG_NORMAL = 0x20; // in "most weapons" set
+const int WEP_FLAG_HIDDEN = 0x40; // hides from menu
+const int WEP_FLAG_RELOADABLE = 0x80; // can has reload
+const int WEP_FLAG_SUPERWEAPON = 0x100; // powerup timer
+const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
+
+// weapon requests
+const int WR_SETUP = 1; // (SERVER) setup weapon data
+const int WR_THINK = 2; // (SERVER) logic to run every frame
+const int WR_CHECKAMMO1 = 3; // (SERVER) checks ammo for weapon primary
+const int WR_CHECKAMMO2 = 4; // (SERVER) checks ammo for weapon second
+const int WR_AIM = 5; // (SERVER) runs bot aiming code for this weapon
+const int WR_INIT = 6; // (BOTH) precaches models/sounds used by this weapon, also sets up weapon properties
+const int WR_SUICIDEMESSAGE = 7; // (SERVER) notification number for suicide message (may inspect w_deathtype for details)
+const int WR_KILLMESSAGE = 8; // (SERVER) notification number for kill message (may inspect w_deathtype for details)
+const int WR_RELOAD = 9; // (SERVER) handles reloading for weapon
+const int WR_RESETPLAYER = 10; // (SERVER) clears fields that the weapon may use
+const int WR_IMPACTEFFECT = 11; // (CLIENT) impact effect for weapon explosion
+const int WR_PLAYERDEATH = 12; // (SERVER) called whenever a player dies
+const int WR_GONETHINK = 13; // (SERVER) logic to run when weapon is lost
+const int WR_CONFIG = 14; // (ALL) dump weapon cvars to config in data directory (see: sv_cmd dumpweapons)
+const int WR_ZOOMRETICLE = 15; // (CLIENT) weapon specific zoom reticle
+const int WR_DROP = 16; // (SERVER) the weapon is dropped
+const int WR_PICKUP = 17; // (SERVER) a weapon is picked up
+
+// variables:
+string weaponorder_byid;
+
+// weapon sets
+typedef vector WepSet;
+WepSet WepSet_FromWeapon(int a);
#ifdef SVQC
-# include "config.qh"
-# include "../../server/bot/aim.qh"
+void WepSet_AddStat();
+void WriteWepSet(float dest, WepSet w);
+#endif
+#ifdef CSQC
+WepSet WepSet_GetFromStat();
+WepSet ReadWepSet();
+#endif
+
+// weapon name macros
+#define WEP_FIRST 1
+#define WEP_MAXCOUNT 24 // Increase as needed. Can be up to three times as much.
+int WEP_COUNT;
+int WEP_LAST;
+WepSet WEPSET_ALL;
+WepSet WEPSET_SUPERWEAPONS;
+
+// functions:
+entity get_weaponinfo(int id);
+string W_FixWeaponOrder(string order, float complete);
+string W_UndeprecateName(string s);
+string W_NameWeaponOrder(string order);
+string W_NumberWeaponOrder(string order);
+string W_FixWeaponOrder_BuildImpulseList(string o);
+string W_FixWeaponOrder_AllowIncomplete(string order);
+string W_FixWeaponOrder_ForceComplete(string order);
+void W_RandomWeapons(entity e, float n);
+
+string GetAmmoPicture(.int ammotype);
+
+#ifdef CSQC
+.int GetAmmoFieldFromNum(int i);
+int GetAmmoStat(.int ammotype);
+#endif
+
+// ammo types
+.int ammo_shells;
+.int ammo_nails;
+.int ammo_rockets;
+.int ammo_cells;
+.int ammo_plasma;
+.int ammo_fuel;
+.int ammo_none;
+
+// other useful macros
+#define WEP_ACTION(wpn,wrequest) (get_weaponinfo(wpn)).weapon_func(wrequest)
+#define WEP_AMMO(wpn) ((get_weaponinfo(WEP_##wpn)).ammo_field) // only used inside weapon files/with direct name, don't duplicate prefix
+#define WEP_NAME(wpn) ((get_weaponinfo(wpn)).message)
+
+
+// ======================
+// Configuration Macros
+// ======================
+
+// create cvars for weapon settings
+#define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
+
+#define WEP_ADD_CVAR_PRI(wepname,name) WEP_ADD_CVAR_NONE(wepname, primary_##name)
+#define WEP_ADD_CVAR_SEC(wepname,name) WEP_ADD_CVAR_NONE(wepname, secondary_##name)
+#define WEP_ADD_CVAR_BOTH(wepname,name) \
+ WEP_ADD_CVAR_PRI(wepname, name) \
+ WEP_ADD_CVAR_SEC(wepname, name)
+
+#define WEP_ADD_CVAR(wepid,wepname,mode,name) WEP_ADD_CVAR_##mode(wepname, name)
+
+// create properties for weapon settings
+#define WEP_ADD_PROP(wepid,wepname,type,prop,name) \
+ .type prop; \
+ [[last]] type autocvar_g_balance_##wepname##_##name;
+
+// read cvars from weapon settings
+#define WEP_CVAR(wepname,name) autocvar_g_balance_##wepname##_##name
+#define WEP_CVAR_PRI(wepname,name) WEP_CVAR(wepname, primary_##name)
+#define WEP_CVAR_SEC(wepname,name) WEP_CVAR(wepname, secondary_##name)
+#define WEP_CVAR_BOTH(wepname,isprimary,name) ((isprimary) ? WEP_CVAR_PRI(wepname, name) : WEP_CVAR_SEC(wepname, name))
+
+// set initialization values for weapon settings
+#define WEP_SKIP_CVAR(unuseda,unusedb,unusedc,unusedd) /* skip cvars */
+#define WEP_SET_PROP(wepid,wepname,type,prop,name) get_weaponinfo(WEP_##wepid).##prop = autocvar_g_balance_##wepname##_##name;
+
+
+// =====================
+// Weapon Registration
+// =====================
+
+bool w_null(int dummy);
+
+void register_weapon(
+ int id,
+ WepSet bit,
+ bool(int) func,
+ .int ammotype,
+ int i,
+ int weapontype,
+ float pickupbasevalue,
+ vector clr,
+ string modelname,
+ string simplemdl,
+ string crosshair,
+ string wepimg,
+ string refname,
+ string wepname);
+
+void register_weapons_done();
+
+// entity properties of weaponinfo:
+// fields which are explicitly/manually set are marked with "M", fields set automatically are marked with "A"
+.int weapon; // M: WEP_id // WEP_...
+.WepSet weapons; // A: WEPSET_id // WEPSET_...
+.float(float) weapon_func; // M: function // w_...
+..int ammo_field; // M: ammotype // main ammo field
+.int impulse; // M: impulse // weapon impulse
+.int spawnflags; // M: flags // WEPSPAWNFLAG_... combined
+.float bot_pickupbasevalue; // M: rating // bot weapon priority
+.vector wpcolor; // M: color // waypointsprite color
+.string wpmodel; // A: wpn-id // wpn- sprite name
+.string mdl; // M: modelname // name of model (without g_ v_ or h_ prefixes)
+.string model; // A: modelname // full path to g_ model
+.string w_simplemdl; // M: simplemdl // simpleitems weapon model/image
+.string w_crosshair; // M: crosshair // per-weapon crosshair: "CrosshairImage Size"
+.float w_crosshair_size; // A: crosshair // per-weapon crosshair size (argument two of "crosshair" field)
+.string model2; // M: wepimg // "weaponfoobar" side view image file of weapon // WEAPONTODO: Move out of skin files, move to common files
+.string netname; // M: refname // reference name name
+.string message; // M: wepname // human readable name
+
+
+// note: the fabs call is just there to hide "if result is constant" warning
+#define REGISTER_WEAPON_2(id,bit,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) \
+ int id; \
+ WepSet bit; \
+ bool function(int); \
+ void RegisterWeapons_##id() \
+ { \
+ WEP_LAST = (id = WEP_FIRST + WEP_COUNT); \
+ bit = WepSet_FromWeapon(id); \
+ WEPSET_ALL |= bit; \
+ if((flags) & WEP_FLAG_SUPERWEAPON) \
+ WEPSET_SUPERWEAPONS |= bit; \
+ ++WEP_COUNT; \
+ register_weapon(id,bit,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname); \
+ } \
+ ACCUMULATE_FUNCTION(RegisterWeapons, RegisterWeapons_##id)
+#ifdef MENUQC
+#define REGISTER_WEAPON(id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) \
+ REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,w_null,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname)
+#else
+#define REGISTER_WEAPON(id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) \
+ REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname)
#endif
-// ONLY EVER ADD NEW WEAPONS AT THE END. IF YOU REMOVE ONE, PUT THE LAST ONE ON
-// ITS PLACE. THIS IS TO AVOID UNNECESSARY RENUMBERING OF WEAPON IMPULSES.
-// IF YOU DISREGARD THIS NOTICE, I'LL KILL YOU WITH THE @!#%'N TUBA
-
-// core weapons
-#include "w_blaster.qc"
-#include "w_shotgun.qc"
-#include "w_machinegun.qc"
-#include "w_mortar.qc"
-#include "w_minelayer.qc"
-#include "w_electro.qc"
-#include "w_crylink.qc"
-#include "w_vortex.qc"
-#include "w_hagar.qc"
-#include "w_devastator.qc"
-
-// other weapons
-#include "w_porto.qc"
-#include "w_vaporizer.qc"
-#include "w_hook.qc"
-#include "w_hlac.qc"
-#include "w_tuba.qc"
-#include "w_rifle.qc"
-#include "w_fireball.qc"
-#include "w_seeker.qc"
-#include "w_shockwave.qc"
-#include "w_arc.qc"
-#include "w_hmg.qc"
-#include "w_rpc.qc"
-
-//#endif
+#include "all.inc"
+
+#undef WEP_ADD_CVAR_MO_PRI
+#undef WEP_ADD_CVAR_MO_SEC
+#undef WEP_ADD_CVAR_MO_BOTH
+#undef WEP_ADD_CVAR_MO_NONE
+#undef WEP_ADD_CVAR
+#undef WEP_ADD_PROP
+#undef REGISTER_WEAPON
+
+ACCUMULATE_FUNCTION(RegisterWeapons, register_weapons_done);
+#endif
#include "../../dpdefs/dpextensions.qh"
#include "../util.qh"
#include "config.qh"
- #include "weapons.qh"
+ #include "all.qh"
#endif
// ==========================
#ifdef SVQC
void spawnfunc_weapon_arc(void) { weapon_defaultspawnfunc(WEP_ARC); }
-float W_Arc_Beam_Send(entity to, float sf)
+float W_Arc_Beam_Send(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
||
self.owner.frozen
||
+ self.owner.vehicle
+ ||
(WEP_CVAR(arc, overheat_max) > 0 && self.beam_heat >= WEP_CVAR(arc, overheat_max))
)
{
entity oldself = self;
self = self.owner;
if(!WEP_ACTION(WEP_ARC, WR_CHECKAMMO1) && !WEP_ACTION(WEP_ARC, WR_CHECKAMMO2))
+ if(!(self.items & IT_UNLIMITED_WEAPON_AMMO))
{
// note: this doesn't force the switch
W_SwitchToOtherWeapon(self);
}
}
-float W_Arc(float req)
+bool W_Arc(int req)
{
switch(req)
{
}
}
-float W_Arc(float req)
+bool W_Arc(int req)
{
switch(req)
{
self = oldself;
}
}
-float W_Blaster(float request)
+bool W_Blaster(int request)
{
switch(request)
{
}
#endif
#ifdef CSQC
-float W_Blaster(float request)
+bool W_Blaster(int request)
{
switch(request)
{
}
}
-float W_Crylink(float req)
+bool W_Crylink(int req)
{
float ammo_amount;
switch(req)
}
#endif
#ifdef CSQC
-float W_Crylink(float req)
+bool W_Crylink(int req)
{
switch(req)
{
if(self.realowner.weapon == WEP_DEVASTATOR)
{
if(self.realowner.WEP_AMMO(DEVASTATOR) < WEP_CVAR(devastator, ammo))
+ if(!(self.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
{
self.realowner.cnt = WEP_DEVASTATOR;
ATTACK_FINISHED(self.realowner) = time;
if(self.realowner.weapon == WEP_DEVASTATOR)
{
if(self.realowner.WEP_AMMO(DEVASTATOR) < WEP_CVAR(devastator, ammo))
+ if(!(self.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
{
self.realowner.cnt = WEP_DEVASTATOR;
ATTACK_FINISHED(self.realowner) = time;
W_Devastator_Explode();
}
-void W_Devastator_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Devastator_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
other = missile; MUTATOR_CALLHOOK(EditProjectile);
}
-float W_Devastator(float req)
+bool W_Devastator(int req)
{
entity rock;
float rockfound;
}
#endif
#ifdef CSQC
-float W_Devastator(float req)
+bool W_Devastator(int req)
{
switch(req)
{
}
}
-void W_Electro_Orb_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Electro_Orb_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
}
.float bot_secondary_electromooth;
-float W_Electro(float req)
+bool W_Electro(int req)
{
float ammo_amount;
switch(req)
}
#endif
#ifdef CSQC
-float W_Electro(float req)
+bool W_Electro(int req)
{
switch(req)
{
self.nextthink = time + 0.1;
}
-void W_Fireball_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Fireball_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
other = proj; MUTATOR_CALLHOOK(EditProjectile);
}
-float W_Fireball(float req)
+bool W_Fireball(int req)
{
switch(req)
{
}
#endif
#ifdef CSQC
-float W_Fireball(float req)
+bool W_Fireball(int req)
{
switch(req)
{
remove(self);
}
-void W_Hagar_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Hagar_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
loaded = self.hagar_load >= WEP_CVAR_SEC(hagar, load_max);
// this is different than WR_CHECKAMMO when it comes to reloading
- if(autocvar_g_balance_hagar_reload_ammo)
+ if(self.items & IT_UNLIMITED_WEAPON_AMMO)
+ enough_ammo = true;
+ else if(autocvar_g_balance_hagar_reload_ammo)
enough_ammo = self.(weapon_load[WEP_HAGAR]) >= WEP_CVAR_SEC(hagar, ammo);
else
enough_ammo = self.WEP_AMMO(HAGAR) >= WEP_CVAR_SEC(hagar, ammo);
// we aren't checking ammo during an attack, so we must do it here
if(!(WEP_ACTION(self.weapon, WR_CHECKAMMO1) + WEP_ACTION(self.weapon, WR_CHECKAMMO2)))
+ if(!(self.items & IT_UNLIMITED_WEAPON_AMMO))
{
// note: this doesn't force the switch
W_SwitchToOtherWeapon(self);
}
}
-float W_Hagar(float req)
+bool W_Hagar(int req)
{
float ammo_amount;
switch(req)
}
#endif
#ifdef CSQC
-float W_Hagar(float req)
+bool W_Hagar(int req)
{
switch(req)
{
}
}
-float W_HLAC(float req)
+bool W_HLAC(int req)
{
float ammo_amount;
switch(req)
}
#endif
#ifdef CSQC
-float W_HLAC(float req)
+bool W_HLAC(int req)
{
switch(req)
{
weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
}
-float W_HeavyMachineGun(float req)
+bool W_HeavyMachineGun(int req)
{
float ammo_amount;
switch(req)
}
#endif
#ifdef CSQC
-float W_HeavyMachineGun(float req)
+bool W_HeavyMachineGun(int req)
{
switch(req)
{
self.movetype = MOVETYPE_NONE;
}
-void W_Hook_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Hook_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
other = gren; MUTATOR_CALLHOOK(EditProjectile);
}
-float W_Hook(float req)
+bool W_Hook(int req)
{
float hooked_time_max, hooked_fuel;
}
#endif
#ifdef CSQC
-float W_Hook(float req)
+bool W_Hook(int req)
{
switch(req)
{
self.muzzle_flash.owner = self.muzzle_flash.realowner = self;
}
-void W_MachineGun_Attack(float deathtype)
+void W_MachineGun_Attack(int deathtype)
{
W_SetupShot(self, true, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, ((self.misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
if(!autocvar_g_norecoil)
}
-float W_MachineGun(float req)
+bool W_MachineGun(int req)
{
float ammo_amount;
switch(req)
}
#endif
#ifdef CSQC
-float W_MachineGun(float req)
+bool W_MachineGun(int req)
{
switch(req)
{
W_MineLayer_Explode();
}
-float W_MineLayer_Count(entity e)
+int W_MineLayer_Count(entity e)
{
- float minecount = 0;
+ int minecount = 0;
entity mine;
for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.realowner == e)
minecount += 1;
}
}
-void W_MineLayer_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_MineLayer_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
return minfound;
}
-float W_MineLayer(float req)
+bool W_MineLayer(int req)
{
entity mine;
float ammo_amount;
}
#endif
#ifdef CSQC
-float W_MineLayer(float req)
+bool W_MineLayer(int req)
{
switch(req)
{
}
-void W_Mortar_Grenade_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Mortar_Grenade_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
}
.float bot_secondary_grenademooth;
-float W_Mortar(float req)
+bool W_Mortar(int req)
{
entity nade;
float nadefound;
}
#endif
#ifdef CSQC
-float W_Mortar(float req)
+bool W_Mortar(int req)
{
switch(req)
{
#endif
#else
#ifdef SVQC
+#include "../triggers/trigger/jumppads.qh"
+
void spawnfunc_weapon_porto(void) { weapon_defaultspawnfunc(WEP_PORTO); }
void W_Porto_Success(void)
norm = trace_plane_normal;
if(trace_ent.iscreature)
{
- traceline(trace_ent.origin, trace_ent.origin + '0 0 2' * PL_MIN_z, MOVE_WORLDONLY, self);
+ traceline(trace_ent.origin, trace_ent.origin + '0 0 2' * PL_MIN.z, MOVE_WORLDONLY, self);
if(trace_fraction >= 1)
return;
if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
other = gren; MUTATOR_CALLHOOK(EditProjectile);
}
-float w_nexball_weapon(float req); // WEAPONTODO
-float W_Porto(float req)
+bool w_nexball_weapon(int req); // WEAPONTODO
+bool W_Porto(int req)
{
//vector v_angle_save;
}
#endif
#ifdef CSQC
-float W_Porto(float req)
+bool W_Porto(int req)
{
switch(req)
{
void spawnfunc_weapon_campingrifle(void) { spawnfunc_weapon_rifle(); }
void spawnfunc_weapon_sniperrifle(void) { spawnfunc_weapon_rifle(); }
-void W_Rifle_FireBullet(float pSpread, float pDamage, float pForce, float pSolidPenetration, float pAmmo, float deathtype, float pTracer, float pShots, string pSound)
+void W_Rifle_FireBullet(float pSpread, float pDamage, float pForce, float pSolidPenetration, float pAmmo, int deathtype, float pTracer, float pShots, string pSound)
{
float i;
}
.float bot_secondary_riflemooth;
-float W_Rifle(float req)
+bool W_Rifle(int req)
{
float ammo_amount;
}
#endif
#ifdef CSQC
-float W_Rifle(float req)
+bool W_Rifle(int req)
{
switch(req)
{
W_RocketPropelledChainsaw_Explode();
}
-void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if (self.health <= 0)
return;
other = missile; MUTATOR_CALLHOOK(EditProjectile);
}
-float W_RocketPropelledChainsaw(float req)
+bool W_RocketPropelledChainsaw(int req)
{
float ammo_amount = false;
switch(req)
#endif
#ifdef CSQC
-float W_RocketPropelledChainsaw(float req)
+bool W_RocketPropelledChainsaw(int req)
{
switch(req)
{
-void W_Seeker_Missile_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Seeker_Missile_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
remove(self);
}
-void W_Seeker_Tag_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void W_Seeker_Tag_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
// Begin: Genereal weapon functions
// ============================
-float W_Seeker(float req)
+bool W_Seeker(int req)
{
float ammo_amount;
}
#endif
#ifdef CSQC
-float W_Seeker(float req)
+bool W_Seeker(int req)
{
switch(req)
{
}
}
-float W_Shockwave(float req)
+bool W_Shockwave(int req)
{
switch(req)
{
shockwave.sw_time = time;
}
-float W_Shockwave(float req)
+bool W_Shockwave(int req)
{
switch(req)
{
#ifdef SVQC
void spawnfunc_weapon_tuba(void) { weapon_defaultspawnfunc(WEP_TUBA); }
-float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo)
+bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo)
{
float i, j, mmin, mmax, nolength;
float n = tokenize_console(melody);
remove(self);
}
-float W_Tuba_GetNote(entity pl, float hittype)
+int W_Tuba_GetNote(entity pl, int hittype)
{
float movestate = 5;
if (pl.movement.x < 0) movestate -= 3;
if (pl.movement.y < 0) movestate -= 1;
else if (pl.movement.y > 0) movestate += 1;
- float note = 0;
+ int note = 0;
switch(movestate)
{
// layout: originally I wanted
return note;
}
-float W_Tuba_NoteSendEntity(entity to, float sf)
+bool W_Tuba_NoteSendEntity(entity to, int sf)
{
- float f;
+ int f;
msg_entity = to;
if(!sound_allowed(MSG_ONE, self.realowner))
}
}
-float W_Tuba(float req)
+bool W_Tuba(int req)
{
switch(req)
{
}
#endif
#ifdef CSQC
-float W_Tuba(float req)
+bool W_Tuba(int req)
{
// nothing to do here; particles of tuba are handled differently
// WEAPONTODO
#ifdef SVQC
VORTEX_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+
+.float vortex_lasthit;
#endif
#else
#ifdef SVQC
}
yoda = 0;
+ damage_goodhits = 0;
FireRailgunBullet(w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_VORTEX);
if(yoda && flying)
Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+ if(damage_goodhits && self.vortex_lasthit)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
+ damage_goodhits = 0; // only every second time
+ }
+
+ self.vortex_lasthit = damage_goodhits;
//beam and muzzle flash done on client
SendCSQCVortexBeamParticle(charge);
void spawnfunc_weapon_vortex(void); // defined in t_items.qc
.float vortex_chargepool_pauseregen_finished;
-float W_Vortex(float req)
+bool W_Vortex(int req)
{
float dt;
float ammo_amount;
VORTEX_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
return true;
}
+ case WR_SETUP:
+ {
+ self.vortex_lasthit = 0;
+ return true;
+ }
case WR_CHECKAMMO1:
{
ammo_amount = self.WEP_AMMO(VORTEX) >= WEP_CVAR_PRI(vortex, ammo);
VORTEX_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
return true;
}
+ case WR_RESETPLAYER:
+ {
+ self.vortex_lasthit = 0;
+ return true;
+ }
case WR_RELOAD:
{
W_Reload(min(WEP_CVAR_PRI(vortex, ammo), WEP_CVAR_SEC(vortex, ammo)), "weapons/reload.wav");
#endif
#ifdef CSQC
float autocvar_g_balance_vortex_secondary = 0; // WEAPONTODO
-float W_Vortex(float req)
+bool W_Vortex(int req)
{
switch(req)
{
+++ /dev/null
-#ifndef WEAPONS_C
-#define WEAPONS_C
-
-#include "weapons.qh"
-
-#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
- #include "../../client/defs.qh"
- #include "../constants.qh"
- #include "../stats.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/mathlib.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/client.qh"
- #include "../util.qh"
- #include "../buffs.qh"
- #include "../../client/autocvars.qh"
- #include "../deathtypes.qh"
- #include "../../csqcmodellib/interpolate.qh"
- #include "../../client/movetypes.qh"
- #include "../../client/main.qh"
- #include "../../csqcmodellib/cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/mathlib.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/util_server.qh"
- #include "../../warpzonelib/server.qh"
- #include "../constants.qh"
- #include "../stats.qh"
- #include "../teams.qh"
- #include "../util.qh"
- #include "../buffs.qh"
- #include "../monsters/monsters.qh"
- #include "config.qh"
- #include "../../server/weapons/csqcprojectile.qh"
- #include "../../server/weapons/tracing.qh"
- #include "../../server/t_items.qh"
- #include "../../server/autocvars.qh"
- #include "../../server/constants.qh"
- #include "../../server/defs.qh"
- #include "../notifications.qh"
- #include "../deathtypes.qh"
- #include "../../server/mutators/mutators_include.qh"
- #include "../mapinfo.qh"
- #include "../../server/command/common.qh"
- #include "../../csqcmodellib/sv_model.qh"
- #include "../../server/portals.qh"
- #include "../../server/g_hook.qh"
-#endif
-#ifndef MENUQC
-#include "calculations.qc"
-#endif
-#include "all.qh"
-
-// WEAPON PLUGIN SYSTEM
-entity weapon_info[WEP_MAXCOUNT];
-entity dummy_weapon_info;
-
-#if WEP_MAXCOUNT > 72
-# error Kein Weltraum links auf dem Gerät
-#endif
-
-WepSet WepSet_FromWeapon(float a) {
- a -= WEP_FIRST;
-#if WEP_MAXCOUNT > 24
- if(a >= 24) {
- a -= 24;
-#if WEP_MAXCOUNT > 48
- if(a >= 24) {
- a -= 24;
- return '0 0 1' * power2of(a);
- }
-#endif
- return '0 1 0' * power2of(a);
- }
-#endif
- return '1 0 0' * power2of(a);
-}
-#ifdef SVQC
-void WepSet_AddStat()
-{
- addstat(STAT_WEAPONS, AS_INT, weapons_x);
-#if WEP_MAXCOUNT > 24
- addstat(STAT_WEAPONS2, AS_INT, weapons_y);
-#if WEP_MAXCOUNT > 48
- addstat(STAT_WEAPONS3, AS_INT, weapons_z);
-#endif
-#endif
-}
-void WriteWepSet(float dst, WepSet w)
-{
-#if WEP_MAXCOUNT > 48
- WriteInt72_t(dst, w);
-#elif WEP_MAXCOUNT > 24
- WriteInt48_t(dst, w);
-#else
- WriteInt24_t(dst, w.x);
-#endif
-}
-#endif
-#ifdef CSQC
-WepSet WepSet_GetFromStat()
-{
- WepSet w = '0 0 0';
- w.x = getstati(STAT_WEAPONS);
-#if WEP_MAXCOUNT > 24
- w.y = getstati(STAT_WEAPONS2);
-#if WEP_MAXCOUNT > 48
- w.z = getstati(STAT_WEAPONS3);
-#endif
-#endif
- return w;
-}
-WepSet ReadWepSet()
-{
-#if WEP_MAXCOUNT > 48
- return ReadInt72_t();
-#elif WEP_MAXCOUNT > 24
- return ReadInt48_t();
-#else
- return ReadInt24_t() * '1 0 0';
-#endif
-}
-#endif
-
-void register_weapon(
- int id,
- WepSet bit,
- float(float) func,
- .float ammotype,
- float i,
- float weapontype,
- float pickupbasevalue,
- vector clr,
- string modelname,
- string simplemdl,
- string crosshair,
- string wepimg,
- string refname,
- string wepname)
-{
- entity e;
- weapon_info[id - 1] = e = spawn();
- e.classname = "weapon_info";
- e.weapon = id;
- e.weapons = bit;
- e.weapon_func = func;
- e.ammo_field = ammotype;
- e.impulse = i;
- e.spawnflags = weapontype;
- e.bot_pickupbasevalue = pickupbasevalue;
- e.wpcolor = clr;
- e.wpmodel = strzone(strcat("wpn-", ftos(id)));
- e.mdl = modelname;
- e.model = strzone(strcat("models/weapons/g_", modelname, ".md3"));
- e.w_simplemdl = strzone(simplemdl); // simpleitems weapon model/image
- e.w_crosshair = strzone(car(crosshair));
- string s = cdr(crosshair);
- e.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
- e.model2 = strzone(wepimg);
- e.netname = refname;
- e.message = wepname;
-
- #ifdef CSQC
- func(WR_INIT);
- #endif
-}
-float w_null(float dummy)
-{
- return 0;
-}
-void register_weapons_done()
-{
- dummy_weapon_info = spawn();
- dummy_weapon_info.classname = "weapon_info";
- dummy_weapon_info.weapon = 0; // you can recognize dummies by this
- dummy_weapon_info.weapons = '0 0 0';
- dummy_weapon_info.netname = "";
- dummy_weapon_info.message = "AOL CD Thrower";
- dummy_weapon_info.weapon_func = w_null;
- dummy_weapon_info.wpmodel = "";
- dummy_weapon_info.mdl = "";
- dummy_weapon_info.model = "";
- dummy_weapon_info.spawnflags = 0;
- dummy_weapon_info.impulse = -1;
- dummy_weapon_info.bot_pickupbasevalue = 0;
- dummy_weapon_info.ammo_field = ammo_none;
-
- dummy_weapon_info.w_crosshair = "gfx/crosshair1";
- dummy_weapon_info.w_crosshair_size = 1;
- dummy_weapon_info.model2 = "";
-
- int i;
- weaponorder_byid = "";
- for(i = WEP_MAXCOUNT; i >= 1; --i)
- if(weapon_info[i-1])
- weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
- weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
-}
-entity get_weaponinfo(int id)
-{
- entity w;
- if(id < WEP_FIRST || id > WEP_LAST)
- return dummy_weapon_info;
- w = weapon_info[id - 1];
- if(w)
- return w;
- return dummy_weapon_info;
-}
-string W_FixWeaponOrder(string order, float complete)
-{
- return fixPriorityList(order, WEP_FIRST, WEP_LAST, 230 - WEP_FIRST, complete);
-}
-string W_NameWeaponOrder_MapFunc(string s)
-{
- entity wi;
- if(s == "0" || stof(s))
- {
- wi = get_weaponinfo(stof(s));
- if(wi != dummy_weapon_info)
- return wi.netname;
- }
- return s;
-}
-
-string W_UndeprecateName(string s)
-{
- switch ( s )
- {
- case "nex" : return "vortex";
- case "rocketlauncher" : return "devastator";
- case "laser" : return "blaster";
- case "minstanex" : return "vaporizer";
- case "grenadelauncher": return "mortar";
- case "uzi" : return "machinegun";
- default : return s;
- }
-}
-string W_NameWeaponOrder(string order)
-{
- return mapPriorityList(order, W_NameWeaponOrder_MapFunc);
-}
-string W_NumberWeaponOrder_MapFunc(string s)
-{
- float i;
- if(s == "0" || stof(s))
- return s;
- s = W_UndeprecateName(s);
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- if(s == get_weaponinfo(i).netname)
- return ftos(i);
- return s;
-}
-string W_NumberWeaponOrder(string order)
-{
- return mapPriorityList(order, W_NumberWeaponOrder_MapFunc);
-}
-
-float W_FixWeaponOrder_BuildImpulseList_buf[WEP_MAXCOUNT];
-string W_FixWeaponOrder_BuildImpulseList_order;
-void W_FixWeaponOrder_BuildImpulseList_swap(int i, int j, entity pass)
-{
- float h;
- h = W_FixWeaponOrder_BuildImpulseList_buf[i];
- W_FixWeaponOrder_BuildImpulseList_buf[i] = W_FixWeaponOrder_BuildImpulseList_buf[j];
- W_FixWeaponOrder_BuildImpulseList_buf[j] = h;
-}
-float W_FixWeaponOrder_BuildImpulseList_cmp(int i, int j, entity pass)
-{
- entity e1, e2;
- float d;
- e1 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[i]);
- e2 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[j]);
- d = (e1.impulse + 9) % 10 - (e2.impulse + 9) % 10;
- if(d != 0)
- return -d; // high impulse first!
- return
- strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0)
- -
- strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0)
- ; // low char index first!
-}
-string W_FixWeaponOrder_BuildImpulseList(string o)
-{
- int i;
- W_FixWeaponOrder_BuildImpulseList_order = o;
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST] = i;
- heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, world);
- o = "";
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- o = strcat(o, " ", ftos(W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST]));
- W_FixWeaponOrder_BuildImpulseList_order = string_null;
- return substring(o, 1, -1);
-}
-
-string W_FixWeaponOrder_AllowIncomplete(string order)
-{
- return W_FixWeaponOrder(order, 0);
-}
-
-string W_FixWeaponOrder_ForceComplete(string order)
-{
- if(order == "")
- order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority"));
- return W_FixWeaponOrder(order, 1);
-}
-
-void W_RandomWeapons(entity e, float n)
-{
- float i, j;
- WepSet remaining;
- WepSet result;
- remaining = e.weapons;
- result = '0 0 0';
- for(i = 0; i < n; ++i)
- {
- RandomSelection_Init();
- for(j = WEP_FIRST; j <= WEP_LAST; ++j)
- if(remaining & WepSet_FromWeapon(j))
- RandomSelection_Add(world, j, string_null, 1, 1);
- result |= WepSet_FromWeapon(RandomSelection_chosen_float);
- remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float);
- }
- e.weapons = result;
-}
-
-string GetAmmoPicture(.float ammotype)
-{
- switch(ammotype)
- {
- case ammo_shells: return "ammo_shells";
- case ammo_nails: return "ammo_bullets";
- case ammo_rockets: return "ammo_rockets";
- case ammo_cells: return "ammo_cells";
- case ammo_plasma: return "ammo_cells";
- case ammo_fuel: return "ammo_fuel";
- default: return ""; // wtf, no ammo type?
- }
-}
-
-#ifdef CSQC
-.float GetAmmoFieldFromNum(int i)
-{
- switch(i)
- {
- case 0: return ammo_shells;
- case 1: return ammo_nails;
- case 2: return ammo_rockets;
- case 3: return ammo_cells;
- case 4: return ammo_plasma;
- case 5: return ammo_fuel;
- default: return ammo_none;
- }
-}
-
-int GetAmmoStat(.float ammotype)
-{
- switch(ammotype)
- {
- case ammo_shells: return STAT_SHELLS;
- case ammo_nails: return STAT_NAILS;
- case ammo_rockets: return STAT_ROCKETS;
- case ammo_cells: return STAT_CELLS;
- case ammo_plasma: return STAT_PLASMA;
- case ammo_fuel: return STAT_FUEL;
- default: return -1;
- }
-}
-#endif
-#endif
+++ /dev/null
-#ifndef WEAPONS_H
-#define WEAPONS_H
-
-#ifndef MENUQC
-#include "calculations.qh"
-#endif
-
-const int MAX_SHOT_DISTANCE = 32768;
-
-// weapon pickup ratings for bot logic
-const int BOT_PICKUP_RATING_LOW = 2500;
-const int BOT_PICKUP_RATING_MID = 5000;
-const int BOT_PICKUP_RATING_HIGH = 10000;
-
-// weapon flags
-const int WEP_TYPE_OTHER = 0x00; // not for damaging people
-const int WEP_TYPE_SPLASH = 0x01; // splash damage
-const int WEP_TYPE_HITSCAN = 0x02; // hitscan
-const int WEP_TYPEMASK = 0x0F;
-const int WEP_FLAG_CANCLIMB = 0x10; // can be used for movement
-const int WEP_FLAG_NORMAL = 0x20; // in "most weapons" set
-const int WEP_FLAG_HIDDEN = 0x40; // hides from menu
-const int WEP_FLAG_RELOADABLE = 0x80; // can has reload
-const int WEP_FLAG_SUPERWEAPON = 0x100; // powerup timer
-const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
-
-// weapon requests
-const int WR_SETUP = 1; // (SERVER) setup weapon data
-const int WR_THINK = 2; // (SERVER) logic to run every frame
-const int WR_CHECKAMMO1 = 3; // (SERVER) checks ammo for weapon primary
-const int WR_CHECKAMMO2 = 4; // (SERVER) checks ammo for weapon second
-const int WR_AIM = 5; // (SERVER) runs bot aiming code for this weapon
-const int WR_INIT = 6; // (BOTH) precaches models/sounds used by this weapon, also sets up weapon properties
-const int WR_SUICIDEMESSAGE = 7; // (SERVER) notification number for suicide message (may inspect w_deathtype for details)
-const int WR_KILLMESSAGE = 8; // (SERVER) notification number for kill message (may inspect w_deathtype for details)
-const int WR_RELOAD = 9; // (SERVER) handles reloading for weapon
-const int WR_RESETPLAYER = 10; // (SERVER) clears fields that the weapon may use
-const int WR_IMPACTEFFECT = 11; // (CLIENT) impact effect for weapon explosion
-const int WR_PLAYERDEATH = 12; // (SERVER) called whenever a player dies
-const int WR_GONETHINK = 13; // (SERVER) logic to run when weapon is lost
-const int WR_CONFIG = 14; // (ALL) dump weapon cvars to config in data directory (see: sv_cmd dumpweapons)
-const int WR_ZOOMRETICLE = 15; // (CLIENT) weapon specific zoom reticle
-const int WR_DROP = 16; // (SERVER) the weapon is dropped
-const int WR_PICKUP = 17; // (SERVER) a weapon is picked up
-
-// variables:
-string weaponorder_byid;
-
-// weapon sets
-typedef vector WepSet;
-WepSet WepSet_FromWeapon(float a);
-#ifdef SVQC
-void WepSet_AddStat();
-void WriteWepSet(float dest, WepSet w);
-#endif
-#ifdef CSQC
-WepSet WepSet_GetFromStat();
-WepSet ReadWepSet();
-#endif
-
-// weapon name macros
-#define WEP_FIRST 1
-#define WEP_MAXCOUNT 24 // Increase as needed. Can be up to three times as much.
-int WEP_COUNT;
-int WEP_LAST;
-WepSet WEPSET_ALL;
-WepSet WEPSET_SUPERWEAPONS;
-
-// functions:
-entity get_weaponinfo(float id);
-string W_FixWeaponOrder(string order, float complete);
-string W_UndeprecateName(string s);
-string W_NameWeaponOrder(string order);
-string W_NumberWeaponOrder(string order);
-string W_FixWeaponOrder_BuildImpulseList(string o);
-string W_FixWeaponOrder_AllowIncomplete(string order);
-string W_FixWeaponOrder_ForceComplete(string order);
-void W_RandomWeapons(entity e, float n);
-
-string GetAmmoPicture(.float ammotype);
-
-#ifdef CSQC
-.float GetAmmoFieldFromNum(int i);
-int GetAmmoStat(.float ammotype);
-#endif
-
-// ammo types
-.float ammo_shells;
-.float ammo_nails;
-.float ammo_rockets;
-.float ammo_cells;
-.float ammo_plasma;
-.float ammo_fuel;
-.float ammo_none;
-
-// other useful macros
-#define WEP_ACTION(wpn,wrequest) (get_weaponinfo(wpn)).weapon_func(wrequest)
-#define WEP_AMMO(wpn) ((get_weaponinfo(WEP_##wpn)).ammo_field) // only used inside weapon files/with direct name, don't duplicate prefix
-#define WEP_NAME(wpn) ((get_weaponinfo(wpn)).message)
-
-
-// ======================
-// Configuration Macros
-// ======================
-
-// create cvars for weapon settings
-#define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
-
-#define WEP_ADD_CVAR_PRI(wepname,name) WEP_ADD_CVAR_NONE(wepname, primary_##name)
-#define WEP_ADD_CVAR_SEC(wepname,name) WEP_ADD_CVAR_NONE(wepname, secondary_##name)
-#define WEP_ADD_CVAR_BOTH(wepname,name) \
- WEP_ADD_CVAR_PRI(wepname, name) \
- WEP_ADD_CVAR_SEC(wepname, name)
-
-#define WEP_ADD_CVAR(wepid,wepname,mode,name) WEP_ADD_CVAR_##mode(wepname, name)
-
-// create properties for weapon settings
-#define WEP_ADD_PROP(wepid,wepname,type,prop,name) \
- .type prop; \
- [[last]] type autocvar_g_balance_##wepname##_##name;
-
-// read cvars from weapon settings
-#define WEP_CVAR(wepname,name) autocvar_g_balance_##wepname##_##name
-#define WEP_CVAR_PRI(wepname,name) WEP_CVAR(wepname, primary_##name)
-#define WEP_CVAR_SEC(wepname,name) WEP_CVAR(wepname, secondary_##name)
-#define WEP_CVAR_BOTH(wepname,isprimary,name) ((isprimary) ? WEP_CVAR_PRI(wepname, name) : WEP_CVAR_SEC(wepname, name))
-
-// set initialization values for weapon settings
-#define WEP_SKIP_CVAR(unuseda,unusedb,unusedc,unusedd) /* skip cvars */
-#define WEP_SET_PROP(wepid,wepname,type,prop,name) get_weaponinfo(WEP_##wepid).##prop = autocvar_g_balance_##wepname##_##name;
-
-
-// =====================
-// Weapon Registration
-// =====================
-
-float w_null(float dummy);
-
-void register_weapon(
- float id,
- WepSet bit,
- float(float) func,
- .float ammotype,
- float i,
- float weapontype,
- float pickupbasevalue,
- vector clr,
- string modelname,
- string simplemdl,
- string crosshair,
- string wepimg,
- string refname,
- string wepname);
-
-void register_weapons_done();
-
-// entity properties of weaponinfo:
-// fields which are explicitly/manually set are marked with "M", fields set automatically are marked with "A"
-.int weapon; // M: WEP_id // WEP_...
-.WepSet weapons; // A: WEPSET_id // WEPSET_...
-.float(float) weapon_func; // M: function // w_...
-..float ammo_field; // M: ammotype // main ammo field
-.int impulse; // M: impulse // weapon impulse
-.int spawnflags; // M: flags // WEPSPAWNFLAG_... combined
-.float bot_pickupbasevalue; // M: rating // bot weapon priority
-.vector wpcolor; // M: color // waypointsprite color
-.string wpmodel; // A: wpn-id // wpn- sprite name
-.string mdl; // M: modelname // name of model (without g_ v_ or h_ prefixes)
-.string model; // A: modelname // full path to g_ model
-.string w_simplemdl; // M: simplemdl // simpleitems weapon model/image
-.string w_crosshair; // M: crosshair // per-weapon crosshair: "CrosshairImage Size"
-.float w_crosshair_size; // A: crosshair // per-weapon crosshair size (argument two of "crosshair" field)
-.string model2; // M: wepimg // "weaponfoobar" side view image file of weapon // WEAPONTODO: Move out of skin files, move to common files
-.string netname; // M: refname // reference name name
-.string message; // M: wepname // human readable name
-
-
-// note: the fabs call is just there to hide "if result is constant" warning
-#define REGISTER_WEAPON_2(id,bit,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) \
- int id; \
- WepSet bit; \
- float function(float); \
- void RegisterWeapons_##id() \
- { \
- WEP_LAST = (id = WEP_FIRST + WEP_COUNT); \
- bit = WepSet_FromWeapon(id); \
- WEPSET_ALL |= bit; \
- if((flags) & WEP_FLAG_SUPERWEAPON) \
- WEPSET_SUPERWEAPONS |= bit; \
- ++WEP_COUNT; \
- register_weapon(id,bit,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname); \
- } \
- ACCUMULATE_FUNCTION(RegisterWeapons, RegisterWeapons_##id)
-#ifdef MENUQC
-#define REGISTER_WEAPON(id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) \
- REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,w_null,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname)
-#else
-#define REGISTER_WEAPON(id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) \
- REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname)
-#endif
-
-#include "all.qh"
-
-#undef WEP_ADD_CVAR_MO_PRI
-#undef WEP_ADD_CVAR_MO_SEC
-#undef WEP_ADD_CVAR_MO_BOTH
-#undef WEP_ADD_CVAR_MO_NONE
-#undef WEP_ADD_CVAR
-#undef WEP_ADD_PROP
-#undef REGISTER_WEAPON
-
-ACCUMULATE_FUNCTION(RegisterWeapons, register_weapons_done);
-#endif
self.frame2time = self.frame1time;
}
}
-void CSQCModel_InterpolateAnimation_PreNote(float sf)
+void CSQCModel_InterpolateAnimation_PreNote(int sf)
{
#ifdef CSQCMODEL_HAVE_TWO_FRAMES
CSQCModel_InterpolateAnimation_2To4_PreNote(sf);
self.frame1time = time;
}
}
-void CSQCModel_InterpolateAnimation_Note(float sf)
+void CSQCModel_InterpolateAnimation_Note(int sf)
{
#ifdef CSQCMODEL_HAVE_TWO_FRAMES
CSQCModel_InterpolateAnimation_2To4_Note(sf, true);
// this is exported for custom frame animation code. Use with care.
// to update frames, first call this:
-void CSQCModel_InterpolateAnimation_2To4_PreNote(float sf);
-void CSQCModel_InterpolateAnimation_1To2_PreNote(float sf);
+void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf);
+void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf);
// then update frame, frame1time (and possibly frame2, frame2time, lerpfrac)
// if set_times is not set, caller is responsible for frame1time, frame2time, csqcmodel_lerpfractime!
-void CSQCModel_InterpolateAnimation_2To4_Note(float sf, float set_times);
-void CSQCModel_InterpolateAnimation_1To2_Note(float sf, float set_times);
+void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times);
+void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times);
// to retrieve animation state, call this
void CSQCModel_InterpolateAnimation_2To4_Do();
void CSQCModel_InterpolateAnimation_1To2_Do();
#endif
float autocvar_cl_movement_errorcompensation = 0;
+int autocvar_cl_movement = 1;
// engine stuff
float pmove_onground; // weird engine flag we shouldn't really use but have to for now
self.origin = csqcplayer_origin;
self.velocity = csqcplayer_velocity;
csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
- self.pmove_flags = player_pmflags;
+ self.flags = player_pmflags;
}
void CSQCPlayer_SetMinsMaxs()
{
- if(self.pmove_flags & PMF_DUCKED)
+ if(self.flags & FL_DUCKED)
{
self.mins = PL_CROUCH_MIN;
self.maxs = PL_CROUCH_MAX;
void CSQCPlayer_SavePrediction()
{
- player_pmflags = self.pmove_flags;
+ player_pmflags = self.flags;
csqcplayer_origin = self.origin;
csqcplayer_velocity = self.velocity;
csqcplayer_sequence = servercommandframe;
csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
}
+void CSQC_ClientMovement_PlayerMove_Frame();
+
+void PM_Movement_Move()
+{
+ runstandardplayerphysics(self);
+#ifdef CSQC
+ self.flags =
+ ((self.pmove_flags & PMF_DUCKED) ? FL_DUCKED : 0) |
+ (!(self.pmove_flags & PMF_JUMP_HELD) ? FL_JUMPRELEASED : 0) |
+ ((self.pmove_flags & PMF_ONGROUND) ? FL_ONGROUND : 0);
+#endif
+}
+
+void CSQCPlayer_Physics(void)
+{
+ switch(autocvar_cl_movement)
+ {
+ case 1: CSQC_ClientMovement_PlayerMove_Frame(); break;
+ case 2: PM_Movement_Move(); break;
+ }
+}
+
void CSQCPlayer_PredictTo(float endframe, float apply_error)
{
CSQCPlayer_Unpredict();
{
if (!getinputstate(csqcplayer_moveframe))
break;
- runstandardplayerphysics(self);
+ CSQCPlayer_Physics();
CSQCPlayer_SetMinsMaxs();
csqcplayer_moveframe++;
}
input_angles = view_angles;
}
-float CSQCPlayer_IsLocalPlayer()
+bool CSQCPlayer_IsLocalPlayer()
{
return (self == csqcplayer);
}
self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
// get crouch state from the server
- if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
- self.pmove_flags &= ~PMF_DUCKED;
- else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
- self.pmove_flags |= PMF_DUCKED;
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+ self.flags &= ~FL_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+ self.flags |= FL_DUCKED;
// get onground state from the server
if(pmove_onground)
- self.pmove_flags |= PMF_ONGROUND;
+ self.flags |= FL_ONGROUND;
else
- self.pmove_flags &= ~PMF_ONGROUND;
+ self.flags &= ~FL_ONGROUND;
CSQCPlayer_SetMinsMaxs();
v = v0;
csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
CSQCPlayer_PredictTo(servercommandframe + 1, false);
- CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.pmove_flags & PMF_ONGROUND));
+ CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.flags & FL_ONGROUND));
self.origin = o;
self.velocity = v;
// get crouch state from the server
- if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
- self.pmove_flags &= ~PMF_DUCKED;
- else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
- self.pmove_flags |= PMF_DUCKED;
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+ self.flags &= ~FL_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+ self.flags |= FL_DUCKED;
// get onground state from the server
if(pmove_onground)
- self.pmove_flags |= PMF_ONGROUND;
+ self.flags |= FL_ONGROUND;
else
- self.pmove_flags &= ~PMF_ONGROUND;
+ self.flags &= ~FL_ONGROUND;
CSQCPlayer_SavePrediction();
}
#ifdef CSQCMODEL_SERVERSIDE_CROUCH
// get crouch state from the server (LAG)
- if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
- self.pmove_flags &= ~PMF_DUCKED;
- else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
- self.pmove_flags |= PMF_DUCKED;
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+ self.flags &= ~FL_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+ self.flags |= FL_DUCKED;
#endif
CSQCPlayer_SetMinsMaxs();
//const int PMF_DUCKED = 4;
//const int PMF_ONGROUND = 8;
+const int FL_DUCKED = 524288;
+
void CSQCPlayer_SetCamera();
float CSQCPlayer_PreUpdate();
float CSQCPlayer_PostUpdate();
// generic CSQC model code
-float CSQCModel_Send(entity to, int sf)
+bool CSQCModel_Send(entity to, int sf)
{
// some nice flags for CSQCMODEL_IF
float isplayer = (IS_CLIENT(self));
#pragma noref 1
-/*
-==============================================================================
+#define true _true
+#define false _false
+#define TRUE _TRUE
+#define FALSE _FALSE
- SOURCE FOR GLOBALVARS_T C STRUCTURE
- MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+#include "upstream/csprogsdefs.qc"
-==============================================================================
-*/
-
-//
-// system globals
-//
-entity self;
-entity other;
-entity world;
-float time;
-float frametime;
-
-int player_localentnum; //the entnum
-int player_localnum; //the playernum
-float maxclients; //a constant filled in by the engine. gah, portability eh?
-
-float clientcommandframe; //player movement
-float servercommandframe; //clientframe echoed off the server
-
-string mapname;
-
-//
-// global variables set by built in functions
-//
-vector v_forward, v_up, v_right; // set by makevectors()
-
-// set by traceline / tracebox
-float trace_allsolid;
-float trace_startsolid;
-float trace_fraction;
-vector trace_endpos;
-vector trace_plane_normal;
-float trace_plane_dist;
-entity trace_ent;
-float trace_inopen;
-float trace_inwater;
-
-//
-// required prog functions
-//
-void() CSQC_Init;
-void() CSQC_Shutdown;
-float(float f, float t, float n) CSQC_InputEvent;
-void(float w, float h) CSQC_UpdateView;
-bool(string s) CSQC_ConsoleCommand;
-
-//these fields are read and set by the default player physics
-vector pmove_org;
-vector pmove_vel;
-vector pmove_mins;
-vector pmove_maxs;
-//retrieved from the current movement commands (read by player physics)
-float input_timelength;
-vector input_angles;
-vector input_movevalues; //forwards, right, up.
-int input_buttons; //attack, use, jump (default physics only uses jump)
-
-float movevar_gravity;
-float movevar_stopspeed;
-float movevar_maxspeed;
-float movevar_spectatormaxspeed; //used by NOCLIP movetypes.
-float movevar_accelerate;
-float movevar_airaccelerate;
-float movevar_wateraccelerate;
-float movevar_friction;
-float movevar_waterfriction;
-float movevar_entgravity; //the local player's gravity field. Is a multiple (1 is the normal value)
-
-//================================================
-void end_sys_globals; // flag for structure dumping
-//================================================
-
-/*
-==============================================================================
-
- SOURCE FOR ENTVARS_T C STRUCTURE
- MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
-
-==============================================================================
-*/
-
-//
-// system fields (*** = do not set in prog code, maintained by C code)
-//
-.int modelindex; // *** model index in the precached list
-.vector absmin, absmax; // *** origin + mins / maxs
-
-.int entnum; // *** the ent number as on the server
-.float drawmask;
-.void() predraw;
-
-.float movetype;
-.float solid;
-
-.vector origin; // ***
-.vector oldorigin; // ***
-.vector velocity;
-.vector angles;
-.vector avelocity;
-
-.string classname; // spawn function
-.string model;
-.int frame;
-.int skin;
-.int effects;
-
-.vector mins, maxs; // bounding box extents reletive to origin
-.vector size; // maxs - mins
-
-.void() touch;
-.void() use;
-.void() think;
-.void() blocked; // for doors or plats, called when can't push other
-
-.float nextthink;
-
-.entity chain;
-
-.string netname;
-
-.entity enemy;
-
-.int flags;
-
-.int colormap;
-
-.entity owner; // who launched a missile
-
-//================================================
-void end_sys_fields; // flag for structure dumping
-//================================================
-
-/*
-==============================================================================
-
- OPTIONAL FIELDS AND GLOBALS
-
-==============================================================================
-*/
-
-// Additional OPTIONAL Fields and Globals
-float intermission; // indicates intermission state (0 = normal, 1 = scores, 2 = finale text)
-
-vector view_angles; // same as input_angles
-vector view_punchangle; // from server
-vector view_punchvector; // from server
-
-/*
-==============================================================================
-
- CONSTANT DEFINITIONS
-
-==============================================================================
-*/
-
-const int MASK_ENGINE = 1;
-const int MASK_ENGINEVIEWMODELS = 2;
-const int MASK_NORMAL = 4;
-
-const int RF_VIEWMODEL = 1;
-const int RF_EXTERNALMODEL = 2;
-const int RF_DEPTHHACK = 4;
-const int RF_ADDITIVE = 8;
-const int RF_USEAXIS = 16;
-
-const int VF_MIN = 1; //(vector)
-const int VF_MIN_X = 2; //(float)
-const int VF_MIN_Y = 3; //(float)
-const int VF_SIZE = 4; //(vector) (viewport size)
-const int VF_SIZE_Y = 5; //(float)
-const int VF_SIZE_X = 6; //(float)
-const int VF_VIEWPORT = 7; //(vector, vector)
-const int VF_FOV = 8; //(vector)
-const int VF_FOVX = 9; //(float)
-const int VF_FOVY = 10; //(float)
-const int VF_ORIGIN = 11; //(vector)
-const int VF_ORIGIN_X = 12; //(float)
-const int VF_ORIGIN_Y = 13; //(float)
-const int VF_ORIGIN_Z = 14; //(float)
-const int VF_ANGLES = 15; //(vector)
-const int VF_ANGLES_X = 16; //(float)
-const int VF_ANGLES_Y = 17; //(float)
-const int VF_ANGLES_Z = 18; //(float)
-const int VF_DRAWWORLD = 19; //(float)
-const int VF_DRAWENGINESBAR = 20; //(float)
-const int VF_DRAWCROSSHAIR = 21; //(float)
-
-const int VF_CL_VIEWANGLES = 33; //(vector)
-const int VF_CL_VIEWANGLES_X = 34; //(float)
-const int VF_CL_VIEWANGLES_Y = 35; //(float)
-const int VF_CL_VIEWANGLES_Z = 36; //(float)
-
-const int VF_PERSPECTIVE = 200;
-
-//const int STAT_HEALTH = 0;
-//const int STAT_WEAPONMODEL = 2;
-//const int STAT_AMMO = 3;
-//const int STAT_ARMOR = 4;
-//const int STAT_WEAPONFRAME = 5;
-//const int STAT_SHELLS = 6;
-//const int STAT_NAILS = 7;
-//const int STAT_ROCKETS = 8;
-//const int STAT_CELLS = 9;
-//const int STAT_ACTIVEWEAPON = 10;
-//const int STAT_TOTALSECRETS = 11;
-//const int STAT_TOTALMONSTERS = 12;
-//const int STAT_SECRETS = 13;
-//const int STAT_MONSTERS = 14;
-//const int STAT_ITEMS = 15;
-//const int STAT_VIEWHEIGHT = 16;
-
-// Quake Sound Constants
-const int CHAN_AUTO = 0;
-const int CHAN_WEAPON = 1;
-const int CHAN_VOICE = 2;
-const int CHAN_ITEM = 3;
-const int CHAN_BODY = 4;
-
-const int ATTN_NONE = 0;
-const int ATTN_NORM = 1;
-const int ATTN_IDLE = 2;
-const int ATTN_STATIC = 3;
-
-// Frik File Constants
-const int FILE_READ = 0;
-const int FILE_APPEND = 1;
-const int FILE_WRITE = 2;
-
-// Quake Point Contents
-const int CONTENT_EMPTY = -1;
-const int CONTENT_SOLID = -2;
-const int CONTENT_WATER = -3;
-const int CONTENT_SLIME = -4;
-const int CONTENT_LAVA = -5;
-const int CONTENT_SKY = -6;
-
-// Quake Solid Constants
-const int SOLID_NOT = 0;
-const int SOLID_TRIGGER = 1;
-const int SOLID_BBOX = 2;
-const int SOLID_SLIDEBOX = 3;
-const int SOLID_BSP = 4;
-const int SOLID_CORPSE = 5;
-
-// Quake Move Constants
-const int MOVE_NORMAL = 0;
-const int MOVE_NOMONSTERS = 1;
-const int MOVE_MISSILE = 2;
-
-const float EXTRA_LOW = -99999999;
-const float EXTRA_HIGH = 99999999;
-
-const vector VEC_1 = '1 1 1';
-const vector VEC_0 = '0 0 0';
-const vector VEC_M1 = '-1 -1 -1';
-
-//const float M_PI = 3.14159265358979323846;
-
-vector VEC_HULL_MIN = '-16 -16 -24';
-vector VEC_HULL_MAX = '16 16 32';
-
-// Quake Temporary Entity Constants
-const int TE_SPIKE = 0;
-const int TE_SUPERSPIKE = 1;
-const int TE_GUNSHOT = 2;
-const int TE_EXPLOSION = 3;
-const int TE_TAREXPLOSION = 4;
-const int TE_LIGHTNING1 = 5;
-const int TE_LIGHTNING2 = 6;
-const int TE_WIZSPIKE = 7;
-const int TE_KNIGHTSPIKE = 8;
-const int TE_LIGHTNING3 = 9;
-const int TE_LAVASPLASH = 10;
-const int TE_TELEPORT = 11;
-const int TE_EXPLOSION2 = 12;
-
-// Darkplaces Additions
-const int TE_EXPLOSIONRGB = 53;
-const int TE_GUNSHOTQUAD = 57;
-const int TE_EXPLOSIONQUAD = 70;
-const int TE_SPIKEQUAD = 58;
-const int TE_SUPERSPIKEQUAD = 59;
-
-// PFlags for Dynamic Lights
-const int PFLAGS_NOSHADOW = 1;
-const int PFLAGS_CORONA = 2;
-const int PFLAGS_FULLDYNAMIC = 128;
-
-const int EF_ADDITIVE = 32;
-const int EF_BLUE = 64;
-const int EF_FLAME = 1024;
-const int EF_FULLBRIGHT = 512;
-const int EF_NODEPTHTEST = 8192;
-const int EF_NODRAW = 16;
-const int EF_NOSHADOW = 4096;
-const int EF_RED = 128;
-const int EF_STARDUST = 2048;
-const int EF_SELECTABLE = 16384;
-
-const int PFL_ONGROUND = 1;
-const int PFL_CROUCH = 2;
-const int PFL_DEAD = 4;
-const int PFL_GIBBED = 8;
-
-// draw flags
-const int DRAWFLAG_NORMAL = 0;
-const int DRAWFLAG_ADDITIVE = 1;
-const int DRAWFLAG_MODULATE = 2;
-const int DRAWFLAG_2XMODULATE = 3;
-const int DRAWFLAG_SCREEN = 4;
-const int DRAWFLAG_MIPMAP = 0x100; // only for R_BeginPolygon
-
-/*
-==============================================================================
-
- BUILTIN DEFINITIONS
- EXTENSIONS ARE NOT ADDED HERE, BUT BELOW!
-
-==============================================================================
-*/
-
-void(vector ang) makevectors = #1;
-void(entity e, vector o) setorigin = #2;
-void(entity e, string m) setmodel = #3;
-void(entity e, vector min, vector max) setsize = #4;
-
-void() break_to_debugger = #6;
-float() random = #7;
-void(entity e, float chan, string samp) sound = #8;
-vector(vector v) normalize = #9;
-void(string e) error = #10;
-void(string e) objerror = #11;
-float(vector v) vlen = #12;
-float(vector v) vectoyaw = #13;
-entity() spawn = #14;
-void(entity e) remove = #15;
-float(vector v1, vector v2, float tryents, entity ignoreentity) traceline = #16;
-
-entity(entity start, .string fld, string match) find = #18;
-void(string s) precache_sound = #19;
-void(string s) precache_model = #20;
-
-entity(vector org, float rad) findradius = #22;
-
-void(string s, ...) dprint = #25;
-string(float f) ftos = #26;
-string(vector v) vtos = #27;
-void() coredump = #28;
-void() traceon = #29;
-void() traceoff = #30;
-void(entity e) eprint = #31;
-// settrace optional
-float(float yaw, float dist, float settrace) walkmove = #32;
-
-float() droptofloor = #34;
-void(float style, string value) lightstyle = #35;
-int(float v) rint = #36;
-int(float v) floor = #37;
-int(float v) ceil = #38;
-
-float(entity e) checkbottom = #40;
-float(vector v) pointcontents = #41;
-
-float(float f) fabs = #43;
-
-float(string s) cvar = #45;
-void(string s, ...) localcmd = #46;
-entity(entity e) nextent = #47;
-void(vector o, vector d, float color, float count) particle = #48;
-void() ChangeYaw = #49;
-
-vector(vector v) vectoangles = #51;
-vector(vector v, vector w) vectoangles2 = #51;
-
-float(float f) sin = #60;
-float(float f) cos = #61;
-float(float f) sqrt = #62;
-void(entity ent) changepitch = #63;
-void(entity e, entity ignore) tracetoss = #64;
-string(entity ent) etos = #65;
-
-string(string s) precache_file = #68;
-void(entity e) makestatic = #69;
-
-void(string name, string value) cvar_set = #72;
-
-void(vector pos, string samp, float vol, float atten) ambientsound = #74;
-string(string s) precache_model2 = #75;
-string(string s) precache_sound2 = #76;
-string(string s) precache_file2 = #77;
-
-float(string s) stof = #81;
-
-
-void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox = #90;
-vector() randomvec = #91;
-vector(vector org) getlight = #92;
-vector(vector org, float lpflags) getlight2 = #92;
-vector getlight_dir;
-vector getlight_ambient;
-vector getlight_diffuse;
-const float LP_LIGHTMAP = 1;
-const float LP_RTWORLD = 2;
-const float LP_DYNLIGHT = 4;
-const float LP_COMPLETE = 7;
-
-float(string name, string value) registercvar = #93;
-float( float a, ... ) min = #94;
-float( float b, ... ) max = #95;
-float(float minimum, float val, float maximum) bound = #96;
-float(float f, float f) pow = #97;
-entity(entity start, .float fld, float match) findfloat = #98;
-float(string s) checkextension = #99;
-// FrikaC and Telejano range #100-#199
-
-int(string filename, int mode) fopen = #110;
-void(float fhandle) fclose = #111;
-string(float fhandle) fgets = #112;
-void(float fhandle, string s) fputs = #113;
-float(string s) strlen = #114;
-string(...) strcat = #115;
-string(string s, float start, float length) substring = #116;
-vector(string) stov = #117;
-string(string s) strzone = #118;
-void(string s) strunzone = #119;
-
-// FTEQW range #200-#299
-
-float(float number, float quantity) bitshift = #218;
-
-//float(string str, string sub[, float startpos]) strstrofs = #221;
-int(string str, string sub, float startpos) strstrofs = #221;
-int(string str, float ofs) str2chr = #222;
-string(int c, ...) chr2str = #223;
-string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
-string(float chars, string s, ...) strpad = #225;
-string(string info, string key, string value, ...) infoadd = #226;
-string(string info, string key) infoget = #227;
-int(string s1, string s2) strcmp = #228;
-int(string s1, string s2, float len) strncmp = #228;
-int(string s1, string s2) strcasecmp = #229;
-int(string s1, string s2, float len) strncasecmp = #230;
-
-// CSQC range #300-#399
-void() clearscene = #300;
-void(float mask) addentities = #301;
-void(entity ent) addentity = #302;
-float(float property, ...) setproperty = #303;
-float(float property) getproperty = #309;
-vector(float property) getpropertyvec = #309;
-void() renderscene = #304;
-void(vector org, float radius, vector lightcolours) adddynamiclight = #305;
-void(vector org, float radius, vector lightcolours, float style, string cubemapname, float pflags) adddynamiclight2 = #305;
-//void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon = #306;
-void(string texturename, float flag, ...) R_BeginPolygon = #306;
-void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307;
-void() R_EndPolygon = #308;
-vector (vector v) cs_unproject = #310;
-vector (vector v) cs_project = #311;
-
-void(float width, vector pos1, vector pos2, float flag) drawline = #315;
-float(string name) iscachedpic = #316;
-string(string name, ...) precache_pic = #317;
-string(string name) precache_cubemap = #317;
-vector(string picname) draw_getimagesize = #318;
-void(string name) freepic = #319;
-float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter = #320;
-float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #321;
-float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic = #322;
-float(vector position, vector size, vector rgb, float alpha, float flag) drawfill = #323;
-void(float x, float y, float width, float height) drawsetcliparea = #324;
-void(void) drawresetcliparea = #325;
-float(vector position, string text, vector scale, float alpha, float flag) drawcolorcodedstring = #326;
-vector(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawcolorcodedstring2 = #326;
-
-float(int stnum) getstatf = #330;
-int(int stnum, ...) getstati = #331; // can optionally take first bit and count
-string(float firststnum) getstats = #332;
-void(entity e, float mdlindex) setmodelindex = #333;
-string(float mdlindex) modelnameforindex = #334;
-int(string effectname) particleeffectnum = #335;
-void(entity ent, float effectnum, vector start, vector end) trailparticles = #336;
-//void(float effectnum, vector origin [, vector dir, float count]) pointparticles = #337;
-void(float effectnum, vector origin , vector dir, float count) pointparticles = #337;
-void(string s, ...) centerprint = #338;
-void(string s, ...) print = #339;
-string(float keynum) keynumtostring = #340;
-float(string keyname) stringtokeynum = #341;
-string(float keynum) getkeybind = #342;
-void(float usecursor) setcursormode = #343;
-vector() getmousepos = #344;
-float(float framenum) getinputstate = #345;
-void(float sens) setsensitivityscale = #346;
-void(...) runstandardplayerphysics = #347; // this may or may not take a player ent
-string(float playernum, string keyname) getplayerkeyvalue = #348;
-float() isdemo = #349;
-float() isserver = #350;
-void(vector origin, vector forward, vector right, vector up) SetListener = #351;
-void(string cmdname) registercommand = #352;
-float(entity ent) wasfreed = #353;
-string(string key) serverkey = #354;
-
-// Use proper case; refer to the id1 Write* functions!
-int() ReadByte = #360;
-int() ReadChar = #361;
-int() ReadShort = #362;
-int() ReadLong = #363;
-float() ReadCoord = #364;
-float() ReadAngle = #365;
-string() ReadString = #366;
-float() ReadFloat = #367;
-
-// LordHavoc's range #400-#499
-void(entity from, entity to) copyentity = #400;
-
-entity(.string fld, string match) findchain = #402;
-entity(.float fld, float match) findchainfloat = #403;
-void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404;
-void(vector org, vector velocity, float howmany) te_blood = #405;
-void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406;
-void(vector org, vector color) te_explosionrgb = #407;
-void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408;
-void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409;
-void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410;
-void(vector org, vector vel, float howmany) te_spark = #411;
-void(vector org) te_gunshotquad = #412;
-void(vector org) te_spikequad = #413;
-void(vector org) te_superspikequad = #414;
-void(vector org) te_explosionquad = #415;
-void(vector org) te_smallflash = #416;
-void(vector org, float radius, float lifetime, vector color) te_customflash = #417;
-void(vector org) te_gunshot = #418;
-void(vector org) te_spike = #419;
-void(vector org) te_superspike = #420;
-void(vector org) te_explosion = #421;
-void(vector org) te_tarexplosion = #422;
-void(vector org) te_wizspike = #423;
-void(vector org) te_knightspike = #424;
-void(vector org) te_lavasplash = #425;
-void(vector org) te_teleport = #426;
-void(vector org, float colorstart, float colorlength) te_explosion2 = #427;
-void(entity own, vector start, vector end) te_lightning1 = #428;
-void(entity own, vector start, vector end) te_lightning2 = #429;
-void(entity own, vector start, vector end) te_lightning3 = #430;
-void(entity own, vector start, vector end) te_beam = #431;
-void(vector dir) vectorvectors = #432;
-void(vector org) te_plasmaburn = #433;
-//float(entity e, float s) getsurfacenumpoints = #434;
-//vector(entity e, float s, float n) getsurfacepoint = #435;
-//vector(entity e, float s) getsurfacenormal = #436;
-//string(entity e, float s) getsurfacetexture = #437;
-//float(entity e, vector p) getsurfacenearpoint = #438;
-//vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
-
-int(string s) tokenize = #441;
-string(float n) argv = #442;
-void(entity e, entity tagentity, string tagname) setattachment = #443;
-float(string pattern, float caseinsensitive, float quiet) search_begin = #444;
-void(float handle) search_end = #445;
-float(float handle) search_getsize = #446;
-string(float handle, float num) search_getfilename = #447;
-string(string s) cvar_string = #448;
-entity(entity start, .float fld, float match) findflags = #449;
-entity(.float fld, float match) findchainflags = #450;
-int(entity ent, string tagname) gettagindex = #451;
-vector(entity ent, float tagindex) gettaginfo = #452;
-
-void(vector org, vector vel, float howmany) te_flamejet = #457;
-
-entity(float num) entitybyindex = #459;
-int() buf_create = #460;
-void(float bufhandle) buf_del = #461;
-float(float bufhandle) buf_getsize = #462;
-void(float bufhandle_from, float bufhandle_to) buf_copy = #463;
-void(float bufhandle, float sortpower, float backward) buf_sort = #464;
-string(float bufhandle, string glue) buf_implode = #465;
-string(float bufhandle, float string_index) bufstr_get = #466;
-void(float bufhandle, float string_index, string str) bufstr_set = #467;
-float(float bufhandle, string str, float order) bufstr_add = #468;
-void(float bufhandle, float string_index) bufstr_free = #469;
-
-//float(float s) asin = #471;
-//float(float c) acos = #472;
-//float(float t) atan = #473;
-//float(float c, float s) atan2 = #474;
-//float(float a) tan = #475;
-float(string s) strippedstringlen = #476;
-float(string s) strlennocol = #476; // This is the correct name for the function, but not removing the decolorizedstring mapping.
-string(string s) decolorizedstring = #477;
-string(string s) strdecolorize = #477; // This is the correct name for the function, but not removing the decolorizedstring mapping.
-string(float uselocaltime, string format, ...) strftime = #478;
-string(string s) strtolower = #480;
-string(string s) strtoupper = #481;
-string(string s) cvar_defstring = #482;
-void(vector origin, string sample, float volume, float attenuation) pointsound = #483;
-string(string search, string replace, string subject) strreplace = #484;
-string(string search, string replace, string subject) strireplace = #485;
-//vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
-#ifdef SUPPORT_GECKO
-float gecko_create( string name ) = #487;
-void gecko_destroy( string name ) = #488;
-void gecko_navigate( string name, string URI ) = #489;
-float gecko_keyevent( string name, float key, float eventtype ) = #490;
-void gecko_mousemove( string name, float x, float y ) = #491;
-void gecko_resize( string name, float w, float h ) = #492;
-vector gecko_get_texture_extent( string name ) = #493;
-#else
-
-#endif
-
-/*
-==============================================================================
-
- EXTENSION DEFINITIONS
-
-==============================================================================
-*/
-
-// DP_CSQC_SPAWNPARTICLE
-// idea: VorteX
-// darkplaces implementation: VorteX
-// constant definitions:
-// particle base behavior:
-float PT_ALPHASTATIC = 1;
-float PT_STATIC = 2;
-float PT_SPARK = 3;
-float PT_BEAM = 4;
-float PT_RAIN = 5;
-float PT_RAINDECAL = 6;
-float PT_SNOW = 7;
-float PT_BUBBLE = 8;
-float PT_BLOOD = 9;
-float PT_SMOKE = 10;
-float PT_DECAL = 11;
-float PT_ENTITYPARTICLE = 12;
-// particle blendtypes:
-float PBLEND_ALPHA = 0;
-float PBLEND_ADD = 1;
-float PBLEND_INVMOD = 2;
-// particle orientation:
-float PARTICLE_BILLBOARD = 0;
-float PARTICLE_SPARK = 1;
-float PARTICLE_ORIENTED_DOUBLESIDED = 2;
-float PARTICLE_BEAM = 3;
-// global definitions:
-float particle_type; // one of PT_
-float particle_blendmode; // one of PBLEND_ values
-float particle_orientation; // one of PARTICLE_ values
-vector particle_color1;
-vector particle_color2;
-float particle_tex; // number of chunk in particlefont
-float particle_size;
-float particle_sizeincrease;
-float particle_alpha;
-float particle_alphafade;
-float particle_time;
-float particle_gravity;
-float particle_bounce;
-float particle_airfriction;
-float particle_liquidfriction;
-float particle_originjitter;
-float particle_velocityjitter;
-float particle_qualityreduction; // enable culling of this particle when FPS is low
-float particle_stretch;
-vector particle_staincolor1;
-vector particle_staincolor2;
-float particle_staintex;
-float particle_stainalpha;
-float particle_stainsize;
-float particle_delayspawn;
-float particle_delaycollision;
-float particle_angle;
-float particle_spin;
-// builtin definitions:
-float(float max_themes) initparticlespawner = #522; // check fields/globals for integration and enable particle spawner, return 1 is succeded, otherwise returns 0
-void() resetparticle = #523; // reset p_ globals to default theme #0
-void(float theme) particletheme = #524; // restore p_ globals from saved theme
-float() particlethemesave = #525; // save p_ globals to new particletheme and return it's index
-void(float theme) particlethemeupdate = #525; // save p_ globals to new particletheme and return it's index
-void(float theme) particlethemefree = #526; // delete a particle theme
-float(vector org, vector vel) spawnparticle = #527; // returns 0 when failed, 1 when spawned
-float(vector org, vector vel, float theme) quickparticle = #527; // not reading globals, just theme, returns 0 when failed, 1 when spawned
-float(vector org, vector vel, float delay, float collisiondelay) delayedparticle = #528;
-float(vector org, vector vel, float delay, float collisiondelay, float theme) quickdelayedparticle = #528;
-// description: this builtin provides an easy and flexible way to spawn particles,
-// it is not created as replace for DP_SV_POINTPARTICLES but as an addition to it.
-// With this extension you can create a specific particles like rain particles, or entity particles
-// notes:
-// 1) 0 is default particle template, it could be changed
-// 2) color vectors could have value 0-255 of each component
-// restrictions: max themes could be between 4 and 2048
-// warning: you should call initparticlespawner() at very beginning BEFORE all other particle spawner functions
-// function to query particle info
-// don't remove this function as it protects all particle_ globals from FTEQCC/FRIKQCC non-referenced removal optimisation
-void() printparticle =
-{
- // vortex: this also protects from 'non-referenced' optimisation on some compilers
- print("PARTICLE:\n");
- print(strcat(" type: ", ftos(particle_type), "\n"));
- print(strcat(" blendmode: ", ftos(particle_blendmode), "\n"));
- print(strcat(" orientation: ", ftos(particle_orientation), "\n"));
- print(strcat(" color1: ", vtos(particle_color1), "\n"));
- print(strcat(" color2: ", vtos(particle_color2), "\n"));
- print(strcat(" tex: ", ftos(particle_tex), "\n"));
- print(strcat(" size: ", ftos(particle_size), "\n"));
- print(strcat(" sizeincrease: ", ftos(particle_sizeincrease), "\n"));
- print(strcat(" alpha: ", ftos(particle_alpha), "\n"));
- print(strcat(" alphafade: ", ftos(particle_alphafade), "\n"));
- print(strcat(" time: ", ftos(particle_time), "\n"));
- print(strcat(" gravity: ", ftos(particle_gravity), "\n"));
- print(strcat(" bounce: ", ftos(particle_bounce), "\n"));
- print(strcat(" airfriction: ", ftos(particle_airfriction), "\n"));
- print(strcat(" liquidfriction: ", ftos(particle_liquidfriction), "\n"));
- print(strcat(" originjitter: ", ftos(particle_originjitter), "\n"));
- print(strcat(" velocityjitter: ", ftos(particle_velocityjitter), "\n"));
- print(strcat(" qualityreduction: ", ftos(particle_qualityreduction), "\n"));
- print(strcat(" stretch: ", ftos(particle_stretch), "\n"));
- print(strcat(" staincolor1: ", vtos(particle_staincolor1), "\n"));
- print(strcat(" staincolor2: ", vtos(particle_staincolor2), "\n"));
- print(strcat(" staintex: ", ftos(particle_staintex), "\n"));
- print(strcat(" stainalpha: ", ftos(particle_stainalpha), "\n"));
- print(strcat(" stainsize: ", ftos(particle_stainsize), "\n"));
- print(strcat(" delayspawn: ", ftos(particle_delayspawn), "\n"));
- print(strcat(" delaycollision: ", ftos(particle_delaycollision), "\n"));
- print(strcat(" angle: ", ftos(particle_angle), "\n"));
- print(strcat(" spin: ", ftos(particle_spin), "\n"));
-}
-
-// DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET
-// idea: VorteX
-// darkplaces implementation: VorteX
-float RF_USETRANSPARENTOFFSET = 64; // enables transparent origin offsetting
-// global definitions
-float transparent_offset; // should be set before entity is added
-// description: offset a model's meshes origin used for transparent sorting. Could be used to tweak sorting bugs on very large transparent entities or hacking transparent sorting order for certain objects
-// example: transparent_offset = 1000000; // entity always appear on background of other transparents
-// note: offset is done in view forward axis
-
-// DP_CSQC_ENTITYWORLDOBJECT
-// idea: VorteX
-// darkplaces implementation: VorteX
-const float RF_WORLDOBJECT = 128;
-// description: when renderflag is set, engine will not use culling methods for this entity, e.g. it will always be drawn
-// useful for large outdoor objects (like asteroids on sky horizon or sky models)
-
-// DP_CSQC_ENTITYMODELLIGHT
-// idea: VorteX
-// darkplaces implementation: VorteX
-const float RF_MODELLIGHT = 4096;
-.vector modellight_ambient;
-.vector modellight_diffuse;
-.vector modellight_dir;
-// description: allows CSQC to override directional model lightning on entity
-
-// DP_CSQC_SETPAUSE
-// idea: VorteX
-// darkplaces implementation: VorteX
-// builtin definitions:
-void(float ispaused) setpause = #531;
-// description: provides ability to set pause in local games (similar to one set once console is activated)
-// not stopping sound/cd track, useful for inventory screens, ingame menus with input etc.
-
-// DP_CSQC_QUERYRENDERENTITY
-// idea: VorteX
-// darkplaces implementation: VorteX
-// constant definitions:
-// render entity fields:
-float E_ACTIVE = 0; // float 0/1
-float E_ORIGIN = 1; // vector
-float E_FORWARD = 2; // vector
-float E_RIGHT = 3; // vector
-float E_UP = 4; // vector
-float E_SCALE = 5; // float
-float E_ORIGINANDVECTORS = 6; // returns origin, + sets v_* vectors to orientation
-float E_ALPHA = 7; // float
-float E_COLORMOD = 8; // vector
-float E_PANTSCOLOR = 9; // vector
-float E_SHIRTCOLOR = 10; // vector
-float E_SKIN = 11; // float
-float E_MINS = 12; // vector
-float E_MAXS = 13; // vector
-float E_ABSMIN = 14; // vector
-float E_ABSMAX = 15; // vector
-float E_LIGHT = 16; // vector - modellight
-// builtin definitions:
-float(float entitynum, float fldnum) getentity = #504;
-vector(float entitynum, float fldnum) getentityvec = #504;
-// description: allows to query parms from render entities, especially useful with attaching CSQC ents to
-// server entities networked and interpolated by engine (monsters, players), number of entity is it's SVQC number
-// you can send it via tempentity/CSQC entity message. Note that this builtin doesnt know about entity removing/reallocating
-// so it's meaning to work for short period of time, dont use it on missiles/grenades whatever will be removed next five seconds
-
-//DP_GFX_FONTS
-//idea: Blub\0, divVerent
-//darkplaces implementation: Blub\0
-//console commands:
-// loadfont fontname fontmaps size1 size2 ...
-// A font can simply be gfx/tgafile (freetype fonts doent need extension),
-// or alternatively you can specify multiple fonts and faces
-// Like this: gfx/vera-sans:2,gfx/fallback:1
-// to load face 2 of the font gfx/vera-sans and use face 1
-// of gfx/fallback as fallback font
-// You can also specify a list of font sizes to load, like this:
-// loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32
-// In many cases, 8 12 16 24 32 should be a good choice.
-// for slots see:
-//constant definitions:
-float drawfont; // set it before drawstring()/drawchar() calls
-float FONT_DEFAULT = 0; // 'default'
-float FONT_CONSOLE = 1; // 'console', REALLY should be fixed width (ls!)
-float FONT_SBAR = 2; // 'sbar', used on hud, must be fixed width
-float FONT_NOTIFY = 3; // 'notify', used on sprint/bprint
-float FONT_CHAT = 4; // 'chat'
-float FONT_CENTERPRINT = 5;// 'centerprint'
-float FONT_INFOBAR = 6; // 'infobar'
-float FONT_MENU = 7; // 'menu', should be fixed width
-float FONT_USER0 = 8; // 'user0', userdefined fonts
-float FONT_USER1 = 9; // 'user1', userdefined fonts
-float FONT_USER2 = 10; // 'user2', userdefined fonts
-float FONT_USER3 = 11; // 'user3', userdefined fonts
-float FONT_USER4 = 12; // 'user4', userdefined fonts
-float FONT_USER5 = 13; // 'user5', userdefined fonts
-float FONT_USER6 = 14; // 'user6', userdefined fonts
-float FONT_USER7 = 15; // 'user7' slot, userdefined fonts
-//builtin definitions:
-float findfont(string s) = #356; // find font by fontname and return it's index
-float loadfont(string fontname, string fontmaps, string sizes, float slot, float fix_scale, float fix_voffset) = #357;
-// loads font immediately so stringwidth() function can be used just after builtin call
-// returns a font slotnum (which is used to set drawfont to)
-// first 3 parms are identical to "loadfont" console command ones
-// slot could be one of FONT_ constants or result of findfont() or -1 to not use it
-// if slot is given, font will be loaded to this slotnum and fontname become new title for it
-// this way you can rename user* fonts to something more usable
-// fix_* parms let you fix badly made fonts by applying some transformations to them
-// fix_scale : per-character center-oriented scale (doesn't change line height at all)
-// fix_voffset : vertical offset for each character, it's a multiplier to character height
-float stringwidth(string text, float allowColorCodes, vector size) = #327; // get a width of string with given font and char size
-float stringwidth_menu(string text, float allowColorCodes, vector size) = #468; // in menu.dat it has different builtin #
-//description: engine support for custom fonts in console, hud, qc etc.
-// limits:
-// max 128 chars for font name
-// max 3 font fallbacks
-// max 8 sizes per font
-
-//DP_GFX_FONTS_FREETYPE
-//idea: Blub\0, divVerent
-//darkplaces implementation: Blub\0
-//cvar definitions:
-// r_font_disable_freetype 0/1 : disable freetype fonts loading (uttetly disables freetype library initialization)
-// r_font_antialias 0/1 : antialiasing when loading font
-// r_font_hint 0/1/2/3 : hinting when loading font, 0 is no hinting, 1 light autohinting , 2 full autohinting, 3 full hinting
-// r_font_postprocess_blur X : font outline blur amount
-// r_font_postprocess_outline X : font outline width
-// r_font_postprocess_shadow_x X : font outline shadow x shift amount, applied during outlining
-// r_font_postprocess_shadow_y X : font outline shadow y shift amount, applied during outlining
-// r_font_postprocess_shadow_z X : font outline shadow z shift amount, applied during blurring
-//description: engine support for truetype/freetype fonts
-//so .AFM+.PFB/.OTF/.TTF files could be stuffed as fontmaps in loadfont()
-//(console command version will support them as well)
-
-//DP_CSQC_BINDMAPS
-//idea: daemon, motorsep
-//darkplaces implementation: divVerent
-//builtin definitions:
-string(float key, float bindmap) getkeybind_bindmap = #342;
-float(float key, string bind, float bindmap) setkeybind_bindmap = #630;
-vector(void) getbindmaps = #631;
-float(vector bm) setbindmaps = #632;
-string(string command, float bindmap) findkeysforcommand = #610;
-//<already in EXT_CSQC> float(string key) stringtokeynum = #341;
-//<already in EXT_CSQC> string(float keynum) keynumtostring = #340;
-//description: key bind setting/getting including support for switchable
-//bindmaps.
-
-//DP_CRYPTO
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions: (CSQC)
-float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
-//description:
-//use -1 as buffer handle to justs end delim as postdata
-
-//DP_CSQC_MAINVIEW
-//idea: divVerent
-//darkplaces implementation: divVerent
-//constant definitions:
-const int VF_MAINVIEW = 400;
-//use setproperty(VF_MAINVIEW, 1); before calling R_RenderView for the render
-//that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR
-//this flag is set for the first scene, and not cleared by R_ClearScene
-//this flag is automatically cleared by R_RenderView
-//so when not using this extension, the first view rendered is the main view
-
-//DP_CSQC_MINFPS_QUALITY
-//idea: divVerent
-//darkplaces implementation: divVerent
-//constant definitions:
-const int VF_MINFPS_QUALITY = 401;
-//use getproperty(VF_MINFPS_QUALITY); to do CSQC based LOD based on cl_minfps
-//1 should lead to an unmodified view
-
-//DP_CSQC_V_CALCREFDEF_WIP1
-//DP_CSQC_V_CALCREFDEF_WIP2
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-void(entity e, float refdefflags) V_CalcRefdef = #640;
-//constant definitions:
-const int PMF_DUCKED = 4;
-const int PMF_ONGROUND = 8;
-const int REFDEFFLAG_TELEPORTED = 1;
-const int REFDEFFLAG_JUMPING = 2;
-const int REFDEFFLAG_DEAD = 4;
-const int REFDEFFLAG_INTERMISSION = 8;
-//- use this on the player entity after performing prediction
-//- pass REFDEFFLAG_TELEPORTED if the player teleported since last frame
-//- pass REFDEFFLAG_JUMPING if jump button is pressed
-//- pass REFDEFFLAG_DEAD if dead (DP_CSQC_V_CALCREFDEF_WIP2)
-//- pass REFDEFFLAG_INTERMISSION if in intermission (DP_CSQC_V_CALCREFDEF_WIP2)
-//- the player entity needs to have origin, velocity, pmove_flags set according
-// to prediction (the above two PMF_ flags are used in the player's pmove_flags)
-//- NOTE: to check for this, ALSO OR a check with DP_CSQC_V_CALCREFDEF to also support
-// the finished extension once done
-
-// assorted builtins
-float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #328;
-vector drawgetimagesize(string pic) = #318;
-const float SPA_POSITION = 0;
-const float SPA_S_AXIS = 1;
-const float SPA_T_AXIS = 2;
-const float SPA_R_AXIS = 3;
-const float SPA_TEXCOORDS0 = 4;
-const float SPA_LIGHTMAP0_TEXCOORDS = 5;
-const float SPA_LIGHTMAP_COLOR = 6;
-float (entity e, float s) getsurfacenumpoints = #434;
-vector (entity e, float s, float n) getsurfacepoint = #435;
-vector (entity e, float s) getsurfacenormal = #436;
-string (entity e, float s) getsurfacetexture = #437;
-float (entity e, vector p) getsurfacenearpoint = #438;
-vector (entity e, float s, vector p) getsurfaceclippedpoint = #439;
-vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
-float(entity e, float s) getsurfacenumtriangles = #628;
-vector(entity e, float s, float n) getsurfacetriangle = #629;
-
-//DP_QC_ASINACOSATANATAN2TAN
-//idea: Urre
-//darkplaces implementation: LordHavoc
-//constant definitions:
-float DEG2RAD = 0.0174532925199432957692369076848861271344287188854172545609719144;
-float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612;
-float PI = 3.1415926535897932384626433832795028841971693993751058209749445923;
-//builtin definitions:
-float(float s) asin = #471; // returns angle in radians for a given sin() value, the result is in the range -PI*0.5 to PI*0.5
-float(float c) acos = #472; // returns angle in radians for a given cos() value, the result is in the range 0 to PI
-float(float t) atan = #473; // returns angle in radians for a given tan() value, the result is in the range -PI*0.5 to PI*0.5
-float(float c, float s) atan2 = #474; // returns angle in radians for a given cos() and sin() value pair, the result is in the range -PI to PI (this is identical to vectoyaw except it returns radians rather than degrees)
-float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(a)) for the given angle in radians, the result is in the range -infinity to +infinity
-//description:
-//useful math functions for analyzing vectors, note that these all use angles in radians (just like the cos/sin functions) not degrees unlike makevectors/vectoyaw/vectoangles, so be sure to do the appropriate conversions (multiply by DEG2RAD or RAD2DEG as needed).
-//note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v)
-
-//DP_QC_SPRINTF
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-string(string format, ...) sprintf = #627;
-//description:
-//you know sprintf :P
-//supported stuff:
-// %
-// optional: <argpos>$ for the argument to format
-// flags: #0- +
-// optional: <width>, *, or *<argpos>$ for the field width
-// optional: .<precision>, .*, or .*<argpos>$ for the precision
-// length modifiers: h for forcing a float, l for forcing an int/entity (by default, %d etc. cast a float to int)
-// conversions:
-// d takes a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an int
-// i takes an int/entity if no length is specified or i is, and a float if h is specified as length, and cast it to an int
-// ouxXc take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an unsigned int
-// eEfFgG take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to a double
-// s takes a string
-// vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space
-// For conversions s and c, the flag # makes precision and width interpreted
-// as byte count, by default it is interpreted as character count in UTF-8
-// enabled engines. No other conversions can create wide characters, and #
-// has another meaning in these.
-
-//DP_QC_GETTIME
-//idea: tZork
-//darkplaces implementation: tZork, divVerent
-//constant definitions:
-float GETTIME_FRAMESTART = 0; // time of start of frame
-float GETTIME_REALTIME = 1; // current time (may be OS specific)
-float GETTIME_HIRES = 2; // like REALTIME, but may reset between QC invocations and thus can be higher precision
-float GETTIME_UPTIME = 3; // time since start of the engine
-//builtin definitions:
-float(float tmr) gettime = #519;
-//description:
-//some timers to query...
-
-//DP_QC_GETTIME_CDTRACK
-//idea: divVerent
-//darkplaces implementation: divVerent
-//constant definitions:
-float GETTIME_CDTRACK = 4;
-//description:
-//returns the playing time of the current cdtrack when passed to gettime()
-//see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels
-
-//DP_QC_TOKENIZEBYSEPARATOR
-//idea: Electro, SavageX, LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-int(string s, string separator1, ...) tokenizebyseparator = #479;
-//description:
-//this function returns tokens separated by any of the supplied separator strings, example:
-//numnumbers = tokenizebyseparator("10.2.3.4", ".");
-//returns 4 and the tokens are "10" "2" "3" "4"
-//possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000")
-
-//DP_QC_TOKENIZE_CONSOLE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-int(string s) tokenize_console = #514;
-int(float i) argv_start_index = #515;
-int(float i) argv_end_index = #516;
-//description:
-//this function returns tokens separated just like the console does
-//also, functions are provided to get the index of the first and last character of each token in the original string
-//Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token.
-
-//DP_SND_SOUND7_WIP1
-//DP_SND_SOUND7_WIP2
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8;
-float SOUNDFLAG_RELIABLE = 1;
-//description:
-//plays a sound, with some more flags
-//extensions to sound():
-//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto",
-// i.e. support multiple sounds at once, but cannot be stopped/restarted
-//- a value 0 in the speed parameter means no change; otherwise, it is a
-// percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is
-// half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2)
-//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send
-// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default);
-// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE
-//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by
-// snd_channel1volume, etc. (so, a channel shares the cvar with its respective
-// auto-channel); however, the mod MUST define snd_channel8volume and upwards
-// in default.cfg if they are to be used, as the engine does not create them
-// to not litter the cvar list
-//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and
-// flags as extra 7th and 8th argument
-//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP
-//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support
-// the finished extension once done
-
-//DP_PRECACHE_PIC_FLAGS
-//idea: divVerent
-//darkplaces implementation: divVerent
-//constant definitions:
-float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC
-float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused
-float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense
-//notes: these constants are given as optional second argument to precache_pic()
-
-//DP_QC_TRACE_MOVETYPE_WORLDONLY
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//constant definitions:
-float MOVE_WORLDONLY = 3;
-//description:
-//allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions
-
-//DP_SND_GETSOUNDTIME
-//idea: VorteX
-//darkplaces implementation: VorteX
-//constant definitions:
-float(entity e, float channel) getsoundtime = #533; // get currently sound playing position on entity channel, -1 if not playing or error
-float(string sample) soundlength = #534; // returns length of sound sample in seconds, -1 on error (sound not precached, sound system not initialized etc.)
-//description: provides opportunity to query length of sound samples and realtime tracking of sound playing on entities (similar to DP_GETTIME_CDTRACK)
-//note: beware dedicated server not running sound engine at all, so in dedicated mode this builtins will not work in server progs
-//note also: menu progs not supporting getsoundtime() (will give a warning) since it has no sound playing on entities
-//examples of use:
-// - QC-driven looped sounds
-// - QC events when sound playing is finished
-// - toggleable ambientsounds
-// - subtitles
-
-//DP_QC_NUM_FOR_EDICT
-//idea: Blub\0
-//darkplaces implementation: Blub\0
-//Function to get the number of an entity - a clean way.
-float(entity num) num_for_edict = #512;
-
-//DP_TRACE_HITCONTENTSMASK_SURFACEINFO
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//globals:
-.int dphitcontentsmask; // if non-zero on the entity passed to traceline/tracebox/tracetoss this will override the normal collidable contents rules and instead hit these contents values (for example AI can use tracelines that hit DONOTENTER if it wants to, by simply changing this field on the entity passed to traceline), this affects normal movement as well as trace calls
-float trace_dpstartcontents; // DPCONTENTS_ value at start position of trace
-int trace_dphitcontents; // DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit)
-int trace_dphitq3surfaceflags; // Q3SURFACEFLAG_ value of impacted surface
-string trace_dphittexturename; // texture name of impacted surface
-//constants:
-const int DPCONTENTS_SOLID = 1; // hit a bmodel, not a bounding box
-const int DPCONTENTS_WATER = 2;
-const int DPCONTENTS_SLIME = 4;
-const int DPCONTENTS_LAVA = 8;
-const int DPCONTENTS_SKY = 16;
-const int DPCONTENTS_BODY = 32; // hit a bounding box, not a bmodel
-const int DPCONTENTS_CORPSE = 64; // hit a SOLID_CORPSE entity
-const int DPCONTENTS_NODROP = 128; // an area where backpacks should not spawn
-const int DPCONTENTS_PLAYERCLIP = 256; // blocks player movement
-const int DPCONTENTS_MONSTERCLIP = 512; // blocks monster movement
-const int DPCONTENTS_DONOTENTER = 1024; // AI hint brush
-const int DPCONTENTS_LIQUIDSMASK = 14; // WATER | SLIME | LAVA
-const int DPCONTENTS_BOTCLIP = 2048; // AI hint brush
-const int DPCONTENTS_OPAQUE = 4096; // only fully opaque brushes get this (may be useful for line of sight checks)
-const int Q3SURFACEFLAG_NODAMAGE = 1;
-const int Q3SURFACEFLAG_SLICK = 2; // low friction surface
-const int Q3SURFACEFLAG_SKY = 4; // sky surface (also has NOIMPACT and NOMARKS set)
-const int Q3SURFACEFLAG_LADDER = 8; // climbable surface
-const int Q3SURFACEFLAG_NOIMPACT = 16; // projectiles should remove themselves on impact (this is set on sky)
-const int Q3SURFACEFLAG_NOMARKS = 32; // projectiles should not leave marks, such as decals (this is set on sky)
-const int Q3SURFACEFLAG_FLESH = 64; // projectiles should do a fleshy effect (blood?) on impact
-const int Q3SURFACEFLAG_NODRAW = 128; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_HINT = 256; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_SKIP = 512; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_NOLIGHTMAP = 1024; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_POINTLIGHT = 2048; // compiler hint (not important to qc)
-const int Q3SURFACEFLAG_METALSTEPS = 4096; // walking on this surface should make metal step sounds
-const int Q3SURFACEFLAG_NOSTEPS = 8192; // walking on this surface should not make footstep sounds
-const int Q3SURFACEFLAG_NONSOLID = 16384; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_LIGHTFILTER = 32768; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_ALPHASHADOW = 65536; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_NODLIGHT = 131072; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_DUST = 262144; // translucent 'light beam' effect (not important to qc)
-//description:
-//adds additional information after a traceline/tracebox/tracetoss call.
-//also (very important) sets trace_* globals before calling .touch functions,
-//this allows them to inspect the nature of the collision (for example
-//determining if a projectile hit sky), clears trace_* variables for the other
-//object in a touch event (that is to say, a projectile moving will see the
-//trace results in its .touch function, but the player it hit will see very
-//little information in the trace_ variables as it was not moving at the time)
-
-//DP_QC_CVAR_TYPE
-//idea: divVerent
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-float(string name) cvar_type = #495;
-const int CVAR_TYPEFLAG_EXISTS = 1;
-const int CVAR_TYPEFLAG_SAVED = 2;
-const int CVAR_TYPEFLAG_PRIVATE = 4;
-const int CVAR_TYPEFLAG_ENGINE = 8;
-const int CVAR_TYPEFLAG_HASDESCRIPTION = 16;
-const int CVAR_TYPEFLAG_READONLY = 32;
-
-//DP_QC_CRC16
-//idea: divVerent
-//darkplaces implementation: divVerent
-//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
-//When caseinsensitive is set, the CRC is calculated of the lower cased string.
-int(bool caseinsensitive, string s, ...) crc16 = #494;
-
-//DP_QC_URI_ESCAPE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//URI::Escape's functionality
-string(string in) uri_escape = #510;
-string(string in) uri_unescape = #511;
-
-//DP_QC_DIGEST
-//idea: motorsep, Spike
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-string(string digest, string data, ...) digest_hex = #639;
-//description:
-//returns a given hex digest of given data
-//the returned digest is always encoded in hexadecimal
-//only the "MD4" digest is always supported!
-//if the given digest is not supported, string_null is returned
-//the digest string is matched case sensitively, use "MD4", not "md4"!
-
-//DP_QC_DIGEST_SHA256
-//idea: motorsep, Spike
-//DarkPlaces implementation: divVerent
-//description:
-//"SHA256" is also an allowed digest type
-
-//DP_QC_LOG
-//darkplaces implementation: divVerent
-//builtin definitions:
-float log(float f) = #532;
-//description:
-//logarithm
-
-//FTE_CSQC_SKELETONOBJECTS
-//idea: Spike, LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-// all skeleton numbers are 1-based (0 being no skeleton)
-// all bone numbers are 1-based (0 being invalid)
-float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model.
-float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
-float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist
-string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist
-int(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
-int(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity
-vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
-vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
-void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
-void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
-void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
-void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
-void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
-float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found
-float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
-//fields:
-.float skeletonindex; // active skeleton overriding standard animation on model
-.int frame; // primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
-.int frame2; // secondary framegroup animation (strength = lerpfrac)
-.int frame3; // tertiary framegroup animation (strength = lerpfrac3)
-.int frame4; // quaternary framegroup animation (strength = lerpfrac4)
-.float lerpfrac; // strength of framegroup blend
-.float lerpfrac3; // strength of framegroup blend
-.float lerpfrac4; // strength of framegroup blend
-.float frame1time; // start time of framegroup animation
-.float frame2time; // start time of framegroup animation
-.float frame3time; // start time of framegroup animation
-.float frame4time; // start time of framegroup animation
-//description:
-//this extension provides a way to do complex skeletal animation on an entity.
-//
-//see also DP_SKELETONOBJECTS (this extension implemented on server as well as client)
-//
-//notes:
-//each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render).
-//each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files).
-//if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton.
-//proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose.
-//
-//features include:
-//multiple animations blended together.
-//animating a model with animations from another model with a compatible skeleton.
-//restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head.
-//custom bone controllers - for example making eyes track a target location.
-//
-//
-//
-//example code follows...
-//
-//this helper function lets you identify (by parentage) what group a bone
-//belongs to - for example "torso", "leftarm", would return 1 ("torso") for
-//all children of the bone named "torso", unless they are children of
-//"leftarm" (which is a child of "torso") which would return 2 instead...
-float(float skel, float bonenum, string g1, string g2, string g3, string g4, string g5, string g6) example_skel_findbonegroup =
-{
- string bonename;
- while (bonenum >= 0)
- {
- bonename = skel_get_bonename(skel, bonenum);
- if (bonename == g1) return 1;
- if (bonename == g2) return 2;
- if (bonename == g3) return 3;
- if (bonename == g4) return 4;
- if (bonename == g5) return 5;
- if (bonename == g6) return 6;
- bonenum = skel_get_boneparent(skel, bonenum);
- }
- return 0;
-};
-// create a skeletonindex for our player using current modelindex
-void() example_skel_player_setup =
-{
- self.skeletonindex = skel_create(self.modelindex);
-};
-// setup bones of skeleton based on an animation
-// note: animmodelindex can be a different model than self.modelindex
-void(float animmodelindex, float framegroup, float framegroupstarttime) example_skel_player_update_begin =
-{
- // start with our standard animation
- self.frame = framegroup;
- self.frame2 = 0;
- self.frame3 = 0;
- self.frame4 = 0;
- self.frame1time = framegroupstarttime;
- self.frame2time = 0;
- self.frame3time = 0;
- self.frame4time = 0;
- self.lerpfrac = 0;
- self.lerpfrac3 = 0;
- self.lerpfrac4 = 0;
- skel_build(self.skeletonindex, self, animmodelindex, 0, 0, 100000);
-};
-// apply a different framegroup animation to bones with a specified parent
-void(float animmodelindex, float framegroup, float framegroupstarttime, float blendalpha, string groupbonename, string excludegroupname1, string excludegroupname2) example_skel_player_update_applyoverride =
-{
- self.frame = framegroup;
- self.frame2 = 0;
- self.frame3 = 0;
- self.frame4 = 0;
- self.frame1time = framegroupstarttime;
- self.frame2time = 0;
- self.frame3time = 0;
- self.frame4time = 0;
- self.lerpfrac = 0;
- self.lerpfrac3 = 0;
- self.lerpfrac4 = 0;
- float bonenum = 0;
- float numbones = skel_get_numbones(self.skeletonindex);
- while (bonenum < numbones)
- {
- if (example_skel_findbonegroup(self.skeletonindex, bonenum, groupbonename, excludegroupname1, excludegroupname2, "", "", "") == 1)
- skel_build(self.skeletonindex, self, animmodelindex, 1 - blendalpha, bonenum, bonenum + 1);
- bonenum = bonenum + 1;
- }
-};
-// make eyes point at a target location, be sure v_forward, v_right, v_up are set correctly before calling
-void(vector eyetarget, string bonename) example_skel_player_update_eyetarget =
-{
- float bonenum = skel_find_bone(self.skeletonindex, bonename) - 1;
- if (bonenum < 0)
- return;
- vector oldforward = v_forward;
- vector oldright = v_right;
- vector oldup = v_up;
- vector v = eyetarget - self.origin;
- vector modeleyetarget;
- modeleyetarget.x = v * v_forward;
- modeleyetarget.y = 0-v * v_right;
- modeleyetarget.z = v * v_up;
- // this is an eyeball, make it point at the target location
- // first get all the data we can...
- vector relorg = skel_get_bonerel(self.skeletonindex, bonenum);
- vector relforward = v_forward;
- vector relright = v_right;
- vector relup = v_up;
- vector boneorg = skel_get_boneabs(self.skeletonindex, bonenum);
- vector boneforward = v_forward;
- vector boneright = v_right;
- vector boneup = v_up;
- vector parentorg = skel_get_boneabs(self.skeletonindex, skel_get_boneparent(self.skeletonindex, bonenum));
- vector parentforward = v_forward;
- vector parentright = v_right;
- vector parentup = v_up;
- // get the vector from the eyeball to the target
- vector u = modeleyetarget - boneorg;
- // now transform it inversely by the parent matrix to produce new rel vectors
- v.x = u * parentforward;
- v.y = u * parentright;
- v.z = u * parentup;
- vector ang = vectoangles2(v, relup);
- ang.x = 0 - ang.x;
- makevectors(ang);
- // set the relative bone matrix
- skel_set_bone(self.skeletonindex, bonenum, relorg);
- // restore caller's v_ vectors
- v_forward = oldforward;
- v_right = oldright;
- v_up = oldup;
-};
-// delete skeleton when we're done with it
-// note: skeleton remains valid until next frame when it is really deleted
-void() example_skel_player_delete =
-{
- skel_delete(self.skeletonindex);
- self.skeletonindex = 0;
-};
-//
-// END OF EXAMPLES FOR FTE_CSQC_SKELETONOBJECTS
-//
-
-//DP_QC_ENTITYDATA
-//idea: KrimZon
-//darkplaces implementation: KrimZon
-//builtin definitions:
-float() numentityfields = #496;
-string(float fieldnum) entityfieldname = #497;
-float(float fieldnum) entityfieldtype = #498;
-string(float fieldnum, entity ent) getentityfieldstring = #499;
-float(float fieldnum, entity ent, string s) putentityfieldstring = #500;
-//constants:
-//Returned by entityfieldtype
-float FIELD_STRING = 1;
-float FIELD_FLOAT = 2;
-float FIELD_VECTOR = 3;
-float FIELD_ENTITY = 4;
-float FIELD_FUNCTION = 6;
-//description:
-//Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame.
-//WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers.
-//numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z.
-//entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever.
-//entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers.
-//getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
-//putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
-
-//DP_QC_ENTITYSTRING
-void(string s) loadfromdata = #529;
-void(string s) loadfromfile = #530;
-void(string s) callfunction = #605;
-void(float fh, entity e) writetofile = #606;
-float(string s) isfunction = #607;
-void(entity e, string s) parseentitydata = #608;
-
-//DP_COVERAGE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//function definitions:
-void coverage() = #642; // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
-
-// assorted builtins
-//const int STAT_MOVEVARS_TICRATE = 240;
-//const int STAT_MOVEVARS_TIMESCALE = 241;
-//const int STAT_FRAGLIMIT = 235;
-//const int STAT_TIMELIMIT = 236;
-//const int STAT_MOVEVARS_GRAVITY = 242;
-string(void) ReadPicture = #501;
-const int PARTICLES_USEALPHA = 1;
-float particles_alphamin, particles_alphamax;
-const int PARTICLES_USECOLOR = 2;
-vector particles_colormin, particles_colormax;
-const int PARTICLES_USEFADE = 4; // fades the COUNT (fade alpha using alphamin/alphamax)
-float particles_fade;
-const int PARTICLES_DRAWASTRAIL = 128;
-void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, float flags) boxparticles = #502;
-float trace_networkentity;
-const int RF_FULLBRIGHT = 256;
-const int RF_NOSHADOW = 512;
-const int RF_DYNAMICMODELLIGHT = 8192;
-
-float gettaginfo_parent;
-string gettaginfo_name;
-vector gettaginfo_offset;
-vector gettaginfo_forward;
-vector gettaginfo_right;
-vector gettaginfo_up;
-float checkpvs(vector viewpos, entity viewee) = #240;
+#undef true
+#undef false
+#undef TRUE
+#undef FALSE
#pragma noref 0
#ifndef DPEXTENSIONS_H
#define DPEXTENSIONS_H
-//DarkPlaces supported extension list, draft version 1.04
-//things that don't have extensions yet:
-.float disableclientprediction;
+#pragma noref 1
-//definitions that id Software left out:
-//these are passed as the 'nomonsters' parameter to traceline/tracebox (yes really this was supported in all quake engines, nomonsters is misnamed)
-float MOVE_NORMAL = 0; // same as false
-float MOVE_NOMONSTERS = 1; // same as true
-float MOVE_MISSILE = 2; // save as movement with .movetype == MOVETYPE_FLYMISSILE
+#include "upstream/dpextensions.qc"
-//checkextension function
-//idea: expected by almost everyone
-//darkplaces implementation: LordHavoc
-float(string s) checkextension = #99;
-//description:
-//check if (cvar("pr_checkextension")) before calling this, this is the only
-//guaranteed extension to be present in the extension system, it allows you
-//to check if an extension is available, by name, to check for an extension
-//use code like this:
-//// (it is recommended this code be placed in worldspawn or a worldspawn called function somewhere)
-//if (cvar("pr_checkextension"))
-//if (checkextension("DP_SV_SETCOLOR"))
-// ext_setcolor = true;
-//from then on you can check ext_setcolor to know if that extension is available
+int(entity ent, string tagname) _gettagindex = #451;
+#define gettagindex _gettagindex
-//BX_WAL_SUPPORT
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//description:
-//indicates the engine supports .wal textures for filenames in the textures/ directory
-//(note: DarkPlaces has supported this since 2001 or 2002, but did not advertise it as an extension, then I noticed Betwix was advertising it and added the extension accordingly)
+int(string effectname) _particleeffectnum = #335;
+#define particleeffectnum _particleeffectnum
-//DP_BUTTONCHAT
-//idea: Vermeulen
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float buttonchat;
-//description:
-//true if the player is currently chatting (in messagemode, menus or console)
+int(string s, string separator1, ...) _tokenizebyseparator = #479;
+#define tokenizebyseparator _tokenizebyseparator
-//DP_BUTTONUSE
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float buttonuse;
-//client console commands:
-//+use
-//-use
-//description:
-//made +use and -use commands work, they now control the .buttonuse field (.button1 was used by many mods for other purposes).
+int(string s) _tokenize_console = #514;
+#define tokenize_console _tokenize_console
-//DP_CL_LOADSKY
-//idea: Nehahra, LordHavoc
-//darkplaces implementation: LordHavoc
-//client console commands:
-//"loadsky" (parameters: "basename", example: "mtnsun_" would load "mtnsun_up.tga" and "mtnsun_rt.tga" and similar names, use "" to revert to quake sky, note: this is the same as Quake2 skybox naming)
-//description:
-//sets global skybox for the map for this client (can be stuffed to a client by QC), does not hurt much to repeatedly execute this command, please don't use this in mods if it can be avoided (only if changing skybox is REALLY needed, otherwise please use DP_GFX_SKYBOX).
+int(int i) _argv_start_index = #515;
+#define argv_start_index _argv_start_index
-//DP_CON_SET
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//description:
-//indicates this engine supports the "set" console command which creates or sets a non-archived cvar (not saved to config.cfg on exit), it is recommended that set and seta commands be placed in default.cfg for mod-specific cvars.
+int(int i) _argv_end_index = #516;
+#define argv_end_index _argv_end_index
-//DP_CON_SETA
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//description:
-//indicates this engine supports the "seta" console command which creates or sets an archived cvar (saved to config.cfg on exit), it is recommended that set and seta commands be placed in default.cfg for mod-specific cvars.
+int(string s) _strlen = #114;
+#define strlen _strlen
-//DP_CON_ALIASPARAMETERS
-//idea: many
-//darkplaces implementation: Black
-//description:
-//indicates this engine supports aliases containing $1 through $9 parameter macros (which when called will expand to the parameters passed to the alias, for example alias test "say $2 $1", then you can type test hi there and it will execute say there hi), as well as $0 (name of the alias) and $* (all parameters $1 onward).
+float(float skel, float bonenum) _skel_get_boneparent = #267;
+#define skel_get_boneparent _skel_get_boneparent
-//DP_CON_EXPANDCVAR
-//idea: many, PHP
-//darkplaces implementation: Black
-//description:
-//indicates this engine supports console commandlines containing $cvarname which will expand to the contents of that cvar as a parameter, for instance say my fov is $fov, will say "my fov is 90", or similar.
+float(float skel, string tagname) _skel_find_bone = #268;
+#define skel_find_bone _skel_find_bone
-//DP_CON_STARTMAP
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//adds two engine-called aliases named startmap_sp and startmap_dm which are called when the engine tries to start a singleplayer game from the menu (startmap_sp) or the -listen or -dedicated options are used or the engine is a dedicated server (uses startmap_dm), these allow a mod or game to specify their own map instead of start, and also distinguish between singleplayer and -listen/-dedicated, also these need not be a simple "map start" command, they can do other things if desired, startmap_sp and startmap_dm both default to "map start".
+float(string str, string sub, float startpos) _strstrofs = #221;
+#define strstrofs _strstrofs
-//DP_EF_ADDITIVE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_ADDITIVE = 32;
-//description:
-//additive blending when this object is rendered
+float(string str, float ofs) _str2chr = #222;
+#define str2chr _str2chr
-//DP_EF_BLUE
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_BLUE = 64;
-//description:
-//entity emits blue light (used for quad)
+string(int c, ...) _chr2str = #223;
+#define chr2str _chr2str
-//DP_EF_DOUBLESIDED
-//idea: LordHavoc
-//darkplaces implementation: [515] and LordHavoc
-//effects bit:
-const int EF_DOUBLESIDED = 32768;
-//description:
-//render entity as double sided (backfaces are visible, I.E. you see the 'interior' of the model, rather than just the front), can be occasionally useful on transparent stuff.
+int(string s1, string s2) _strcmp = #228;
+#define strcmp _strcmp
-//DP_EF_DYNAMICMODELLIGHT
-//idea: C.Brutail, divVerent, maikmerten
-//darkplaces implementation: divVerent
-//effects bit:
-const int EF_DYNAMICMODELLIGHT = 131072;
-//description:
-//force dynamic model light on the entity, even if it's a BSP model (or anything else with lightmaps or light colors)
+int(string s1, string s2, int len) _strncmp = #228;
+#define strncmp _strncmp
-//DP_EF_FLAME
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_FLAME = 1024;
-//description:
-//entity is on fire
+int(string s1, string s2) _strcasecmp = #229;
+#define strcasecmp _strcasecmp
-//DP_EF_FULLBRIGHT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_FULLBRIGHT = 512;
-//description:
-//entity is always brightly lit
+int(string s1, string s2, int len) _strncasecmp = #230;
+#define strncasecmp _strncasecmp
-//DP_EF_NODEPTHTEST
-//idea: Supa
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_NODEPTHTEST = 8192;
-//description:
-//makes entity show up to client even through walls, useful with EF_ADDITIVE for special indicators like where team bases are in a map, so that people don't get lost
+int() _buf_create = #460;
+#define buf_create _buf_create
-//DP_EF_NODRAW
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_NODRAW = 16;
-//description:
-//prevents server from sending entity to client (forced invisible, even if it would have been a light source or other such things)
+#pragma noref 0
-//DP_EF_NOGUNBOB
-//idea: Chris Page, Dresk
-//darkplaces implementation: LordHAvoc
-//effects bit:
-const int EF_NOGUNBOB = 256;
-//description:
-//this has different meanings depending on the entity it is used on:
-//player entity - prevents gun bobbing on player.viewmodel
-//viewmodelforclient entity - prevents gun bobbing on an entity attached to the player's view
-//other entities - no effect
-//uses:
-//disabling gun bobbing on a diving mask or other model used as a .viewmodel.
-//disabling gun bobbing on view-relative models meant to be part of the heads up display. (note: if fov is changed these entities may be off-screen, or too near the center of the screen, so use fov 90 in this case)
-
-//DP_EF_NOSHADOW
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_NOSHADOW = 4096;
-//description:
-//realtime lights will not cast shadows from this entity (but can still illuminate it)
-
-//DP_EF_RED
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_RED = 128;
-//description:
-//entity emits red light (used for invulnerability)
-
-//DP_EF_RESTARTANIM_BIT
-//idea: id software
-//darkplaces implementation: divVerent
-//effects bit:
-const int EF_RESTARTANIM_BIT = 1048576;
-//description:
-//when toggled, the current animation is restarted. Useful for weapon animation.
-//to toggle this bit in QC, you can do:
-// self.effects += (EF_RESTARTANIM_BIT - 2 * (self.effects & EF_RESTARTANIM_BIT));
-
-//DP_EF_STARDUST
-//idea: MythWorks Inc
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_STARDUST = 2048;
-//description:
-//entity emits bouncing sparkles in every direction
-
-//DP_EF_TELEPORT_BIT
-//idea: id software
-//darkplaces implementation: divVerent
-//effects bit:
-const int EF_TELEPORT_BIT = 2097152;
-//description:
-//when toggled, interpolation of the entity is skipped for one frame. Useful for teleporting.
-//to toggle this bit in QC, you can do:
-// self.effects += (EF_TELEPORT_BIT - 2 * (self.effects & EF_TELEPORT_BIT));
-
-//DP_ENT_ALPHA
-//idea: Nehahra
-//darkplaces implementation: LordHavoc
-//fields:
-.float alpha;
-//description:
-//controls opacity of the entity, 0.0 is forced to be 1.0 (otherwise everything would be invisible), use -1 if you want to make something invisible, 1.0 is solid (like normal).
-
-//DP_ENT_COLORMOD
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definition:
-.vector colormod;
-//description:
-//controls color of the entity, '0 0 0', is forced to be '1 1 1' (otherwise everything would be black), used for tinting objects, for instance using '1 0.6 0.4' on an ogre would give you an orange ogre (order is red green blue), note the colors can go up to '8 8 8' (8x as bright as normal).
-
-//DP_ENT_CUSTOMCOLORMAP
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//if .colormap is set to 1024 + pants + shirt * 16, those colors will be used for colormapping the entity, rather than looking up a colormap by player number.
-
-/*
-//NOTE: no longer supported by darkplaces because all entities are delta compressed now
-//DP_ENT_DELTACOMPRESS // no longer supported
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//effects bit:
-float EF_DELTA = 8388608;
-//description:
-//(obsolete) applies delta compression to the network updates of the entity, making updates smaller, this might cause some unreliable behavior in packet loss situations, so it should only be used on numerous (nails/plasma shots/etc) or unimportant objects (gibs/shell casings/bullet holes/etc).
-*/
-
-//DP_ENT_EXTERIORMODELTOCLIENT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//fields:
-.entity exteriormodeltoclient;
-//description:
-//the entity is visible to all clients with one exception: if the specified client is using first person view (not using chase_active) the entity will not be shown. Also if tag attachments are supported any entities attached to the player entity will not be drawn in first person.
-
-//DP_ENT_GLOW
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float glow_color;
-.float glow_size;
-.float glow_trail;
-//description:
-//customizable glowing light effect on the entity, glow_color is a paletted (8bit) color in the range 0-255 (note: 0 and 254 are white), glow_size is 0 or higher (up to the engine what limit to cap it to, darkplaces imposes a 1020 limit), if glow_trail is true it will leave a trail of particles of the same color as the light.
-
-//DP_ENT_GLOWMOD
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definition:
-.vector glowmod;
-//description:
-//controls color of the entity's glow texture (fullbrights), '0 0 0', is forced to be '1 1 1' (otherwise everything would be black), used for tinting objects, see colormod (same color restrictions apply).
-
-//DP_ENT_LOWPRECISION
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_LOWPRECISION = 4194304;
-//description:
-//uses low quality origin coordinates, reducing network traffic compared to the default high precision, intended for numerous objects (projectiles/gibs/bullet holes/etc).
-
-//DP_ENT_SCALE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float scale;
-//description:
-//controls rendering scale of the object, 0 is forced to be 1, darkplaces uses 1/16th accuracy and a limit of 15.9375, can be used to make an object larger or smaller.
-
-//DP_ENT_TRAILEFFECTNUM
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float traileffectnum;
-//description:
-//use a custom effectinfo.txt effect on this entity, assign it like this:
-//self.traileffectnum = particleeffectnum("mycustomeffect");
-//this will do both the dlight and particle trail as described in the effect, basically equivalent to trailparticles() in CSQC but performed on a server entity.
-
-//DP_ENT_VIEWMODEL
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.entity viewmodelforclient;
-//description:
-//this is a very special capability, attachs the entity to the view of the client specified, origin and angles become relative to the view of that client, all effects can be used (multiple skins on a weapon model etc)... the entity is not visible to any other client.
-
-//DP_GFX_EXTERNALTEXTURES
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//loads external textures found in various directories (tenebrae compatible)...
-/*
-in all examples .tga is merely the base texture, it can be any of these:
-.tga (base texture)
-_glow.tga (fullbrights or other glowing overlay stuff, NOTE: this is done using additive blend, not alpha)
-_pants.tga (pants overlay for colormapping on models, this should be shades of grey (it is tinted by pants color) and black wherever the base texture is not black, as this is an additive blend)
-_shirt.tga (same idea as pants, but for shirt color)
-_diffuse.tga (this may be used instead of base texture for per pixel lighting)
-_gloss.tga (specular texture for per pixel lighting, note this can be in color (tenebrae only supports greyscale))
-_norm.tga (normalmap texture for per pixel lighting)
-_bump.tga (bumpmap, converted to normalmap at load time, supported only for reasons of tenebrae compatibility)
-_luma.tga (same as _glow but supported only for reasons of tenebrae compatibility)
-
-due to glquake's incomplete Targa(r) loader, this section describes
-required Targa(r) features support:
-types:
-type 1 (uncompressed 8bit paletted with 24bit/32bit palette)
-type 2 (uncompressed 24bit/32bit true color, glquake supported this)
-type 3 (uncompressed 8bit greyscale)
-type 9 (RLE compressed 8bit paletted with 24bit/32bit palette)
-type 10 (RLE compressed 24bit/32bit true color, glquake supported this)
-type 11 (RLE compressed 8bit greyscale)
-attribute bit 0x20 (Origin At Top Left, top to bottom, left to right)
-
-image formats guaranteed to be supported: tga, pcx, lmp
-image formats that are optional: png, jpg
-
-mdl/spr/spr32 examples:
-skins are named _A (A being a number) and skingroups are named like _A_B
-these act as suffixes on the model name...
-example names for skin _2_1 of model "progs/armor.mdl":
-game/override/progs/armor.mdl_2_1.tga
-game/textures/progs/armor.mdl_2_1.tga
-game/progs/armor.mdl_2_1.tga
-example names for skin _0 of the model "progs/armor.mdl":
-game/override/progs/armor.mdl_0.tga
-game/textures/progs/armor.mdl_0.tga
-game/progs/armor.mdl_0.tga
-note that there can be more skins files (of the _0 naming) than the mdl
-contains, this is only useful to save space in the .mdl file if classic quake
-compatibility is not a concern.
-
-bsp/md2/md3 examples:
-example names for the texture "quake" of model "maps/start.bsp":
-game/override/quake.tga
-game/textures/quake.tga
-game/quake.tga
-
-sbar/menu/console textures: for example the texture "conchars" (console font) in gfx.wad
-game/override/gfx/conchars.tga
-game/textures/gfx/conchars.tga
-game/gfx/conchars.tga
-*/
-
-//DP_GFX_EXTERNALTEXTURES_PERMAPTEXTURES
-//idea: Fuh?
-//darkplaces implementation: LordHavoc
-//description:
-//Q1BSP and HLBSP map loading loads external textures found in textures/<mapname>/ as well as textures/.
-//Where mapname is the bsp filename minus the extension (typically .bsp) and minus maps/ if it is in maps/ (any other path is not removed)
-//example:
-//maps/e1m1.bsp uses textures in the directory textures/e1m1/ and falls back to textures/
-//maps/b_batt0.bsp uses textures in the directory textures/b_batt0.bsp and falls back to textures/
-//as a more extreme example:
-//progs/something/blah.bsp uses textures in the directory textures/progs/something/blah/ and falls back to textures/
-
-//DP_GFX_FOG
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//worldspawn fields:
-//"fog" (parameters: "density red green blue", example: "0.1 0.3 0.3 0.3")
-//description:
-//global fog for the map, can not be changed by QC
-
-//DP_GFX_QUAKE3MODELTAGS
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//field definitions:
-.entity tag_entity; // entity this is attached to (call setattachment to set this)
-.float tag_index; // which tag on that entity (0 is relative to the entity, > 0 is an index into the tags on the model if it has any) (call setattachment to set this)
-//builtin definitions:
-void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
-//description:
-//allows entities to be visually attached to model tags (which follow animations perfectly) on other entities, for example attaching a weapon to a player's hand, or upper body attached to lower body, allowing it to change angles and frame separately (note: origin and angles are relative to the tag, use '0 0 0' for both if you want it to follow exactly, this is similar to viewmodelforclient's behavior).
-//note 2: if the tag is not found, it defaults to "" (attach to origin/angles of entity)
-//note 3: attaching to world turns off attachment
-//note 4: the entity that this is attached to must be visible for this to work
-//note 5: if an entity is attached to the player entity it will not be drawn in first person.
-
-//DP_GFX_SKINFILES
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//alias models (mdl, md2, md3) can have .skin files to replace conventional texture naming, these have a naming format such as:
-//progs/test.md3_0.skin
-//progs/test.md3_1.skin
-//...
-//
-//these files contain replace commands (replace meshname shadername), example:
-//replace "helmet" "progs/test/helmet1.tga" // this is a mesh shader replacement
-//replace "teamstripes" "progs/test/redstripes.tga"
-//replace "visor" "common/nodraw" // this makes the visor mesh invisible
-////it is not possible to rename tags using this format
-//
-//Or the Quake3 syntax (100% compatible with Quake3's .skin files):
-//helmet,progs/test/helmet1.tga // this is a mesh shader replacement
-//teamstripes,progs/test/redstripes.tga
-//visor,common/nodraw // this makes the visor mesh invisible
-//tag_camera, // this defines that the first tag in the model is called tag_camera
-//tag_test, // this defines that the second tag in the model is called tag_test
-//
-//any names that are not replaced are automatically show up as a grey checkerboard to indicate the error status, and "common/nodraw" is a special case that is invisible.
-//this feature is intended to allow multiple skin sets on md3 models (which otherwise only have one skin set).
-//other commands might be added someday but it is not expected.
-
-//DP_GFX_SKYBOX
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//worldspawn fields:
-//"sky" (parameters: "basename", example: "mtnsun_" would load "mtnsun_up.tga" and "mtnsun_rt.tga" and similar names, note: "sky" is also used the same way by Quake2)
-//description:
-//global skybox for the map, can not be changed by QC
-
-//DP_UTF8
-//idea: Blub\0, divVerent
-//darkplaces implementation: Blub\0
-//cvar definitions:
-// utf8_enable: enable utf8 encoding
-//description: utf8 characters are allowed inside cvars, protocol strings, files, progs strings, etc.,
-//and count as 1 char for string functions like strlen, substring, etc.
-// note: utf8_enable is run-time cvar, could be changed during execution
-// note: beware that str2chr() could return value bigger than 255 once utf8 is enabled
-
-//DP_HALFLIFE_MAP
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//simply indicates that the engine supports HalfLife maps (BSP version 30, NOT the QER RGBA ones which are also version 30).
-
-//DP_HALFLIFE_MAP_CVAR
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//cvars:
-//halflifebsp 0/1
-//description:
-//engine sets this cvar when loading a map to indicate if it is halflife format or not.
-
-//DP_HALFLIFE_SPRITE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//simply indicates that the engine supports HalfLife sprites.
-
-//DP_INPUTBUTTONS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float button3;
-.float button4;
-.float button5;
-.float button6;
-.float button7;
-.float button8;
-.float button9;
-.float button10;
-.float button11;
-.float button12;
-.float button13;
-.float button14;
-.float button15;
-.float button16;
-//description:
-//set to the state of the +button3, +button4, +button5, +button6, +button7, and +button8 buttons from the client, this does not involve protocol changes (the extra 6 button bits were simply not used).
-//the exact mapping of protocol button bits on the server is:
-//self.button0 = (bits & 1) != 0;
-///* button1 is skipped because mods abuse it as a variable, and accordingly it has no bit */
-//self.button2 = (bits & 2) != 0;
-//self.button3 = (bits & 4) != 0;
-//self.button4 = (bits & 8) != 0;
-//self.button5 = (bits & 16) != 0;
-//self.button6 = (bits & 32) != 0;
-//self.button7 = (bits & 64) != 0;
-//self.button8 = (bits & 128) != 0;
-
-// DP_LIGHTSTYLE_STATICVALUE
-// idea: VorteX
-// darkplaces implementation: VorteX
-// description: allows alternative 'static' lightstyle syntax : "=value"
-// examples: "=0.5", "=2.0", "=2.75"
-// could be used to control switchable lights or making styled lights with brightness > 2
-// Warning: this extension is experimental. It safely works in CSQC, but SVQC use is limited by the fact
-// that other engines (which do not support this extension) could connect to a game and misunderstand this kind of lightstyle syntax
-
-//DP_LITSPRITES
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//indicates this engine supports lighting on sprites, any sprite with ! in its filename (both on disk and in the qc) will be lit rather than having forced EF_FULLBRIGHT (EF_FULLBRIGHT on the entity can still force these sprites to not be lit).
-
-//DP_LITSUPPORT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//indicates this engine loads .lit files for any quake1 format .bsp files it loads to enhance maps with colored lighting.
-//implementation description: these files begin with the header QLIT followed by version number 1 (as little endian 32bit), the rest of the file is a replacement lightmaps lump, except being 3x as large as the lightmaps lump of the map it matches up with (and yes the between-lightmap padding is expanded 3x to keep this consistent), so the lightmap offset in each surface is simply multiplied by 3 during loading to properly index the lit data, and the lit file is loaded instead of the lightmap lump, other renderer changes are needed to display these of course... see the litsupport.zip sample code (almost a tutorial) at http://icculus.org/twilight/darkplaces for more information.
-
-//DP_MONSTERWALK
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//MOVETYPE_WALK is permitted on non-clients, so bots can move smoothly, run off ledges, etc, just like a real player.
-
-//DP_MOVETYPEBOUNCEMISSILE
-//idea: id Software
-//darkplaces implementation: id Software
-//movetype definitions:
-//float MOVETYPE_BOUNCEMISSILE = 11; // already in defs.qc
-//description:
-//MOVETYPE_BOUNCE but without gravity, and with full reflection (no speed loss like grenades have), in other words - bouncing laser bolts.
-
-//DP_MOVETYPEFLYWORLDONLY
-//idea: Samual
-//darkplaces implementation: Samual
-//movetype definitions:
-float MOVETYPE_FLY_WORLDONLY = 33;
-//description:
-//like MOVETYPE_FLY, but does all traces with MOVE_WORLDONLY, and is ignored by MOVETYPE_PUSH. Should only be combined with SOLID_NOT and SOLID_TRIGGER.
-
-//DP_NULL_MODEL
-//idea: Chris
-//darkplaces implementation: divVerent
-//definitions:
-//string dp_null_model = "null";
-//description:
-//setmodel(e, "null"); makes an entity invisible, have a zero bbox, but
-//networked. useful for shared CSQC entities.
-
-//DP_MOVETYPEFOLLOW
-//idea: id Software, LordHavoc (redesigned)
-//darkplaces implementation: LordHavoc
-//movetype definitions:
-float MOVETYPE_FOLLOW = 12;
-//description:
-//MOVETYPE_FOLLOW implemented, this uses existing entity fields in unusual ways:
-//aiment - the entity this is attached to.
-//punchangle - the original angles when the follow began.
-//view_ofs - the relative origin (note that this is un-rotated by punchangle, and that is actually the only purpose of punchangle).
-//v_angle - the relative angles.
-//here's an example of how you would set a bullet hole sprite to follow a bmodel it was created on, even if the bmodel rotates:
-//hole.movetype = MOVETYPE_FOLLOW; // make the hole follow
-//hole.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid
-//hole.aiment = bmodel; // make the hole follow bmodel
-//hole.punchangle = bmodel.angles; // the original angles of bmodel
-//hole.view_ofs = hole.origin - bmodel.origin; // relative origin
-//hole.v_angle = hole.angles - bmodel.angles; // relative angles
-
-//DP_QC_ASINACOSATANATAN2TAN
-//idea: Urre
-//darkplaces implementation: LordHavoc
-//constant definitions:
-float DEG2RAD = 0.0174532925199432957692369076848861271344287188854172545609719144;
-float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612;
-float PI = 3.1415926535897932384626433832795028841971693993751058209749445923;
-//builtin definitions:
-float(float s) asin = #471; // returns angle in radians for a given sin() value, the result is in the range -PI*0.5 to PI*0.5
-float(float c) acos = #472; // returns angle in radians for a given cos() value, the result is in the range 0 to PI
-float(float t) atan = #473; // returns angle in radians for a given tan() value, the result is in the range -PI*0.5 to PI*0.5
-float(float c, float s) atan2 = #474; // returns angle in radians for a given cos() and sin() value pair, the result is in the range -PI to PI (this is identical to vectoyaw except it returns radians rather than degrees)
-float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(a)) for the given angle in radians, the result is in the range -infinity to +infinity
-//description:
-//useful math functions for analyzing vectors, note that these all use angles in radians (just like the cos/sin functions) not degrees unlike makevectors/vectoyaw/vectoangles, so be sure to do the appropriate conversions (multiply by DEG2RAD or RAD2DEG as needed).
-//note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v)
-
-//DP_QC_AUTOCVARS
-//idea: divVerent
-//darkplaces implementation: divVerent
-//description:
-//allows QC variables to be bound to cvars
-//(works for float, string, vector types)
-//example:
-// float autocvar_developer;
-// float autocvar_registered;
-// string autocvar__cl_name;
-//NOTE: copying a string-typed autocvar to another variable/field, and then
-//changing the cvar or returning from progs is UNDEFINED. Writing to autocvar
-//globals is UNDEFINED. Accessing autocvar globals after changing that cvar in
-//the same frame by any means other than cvar_set() from the same QC VM is
-//IMPLEMENTATION DEFINED (an implementation may either yield the previous, or
-//the current, value). Changing them via cvar_set() in the same QC VM
-//immediately must reflect on the autocvar globals. Whether autocvar globals,
-//after restoring a savegame, have the cvar's current value, or the original
-//value at time of saving, is UNDEFINED. Restoring a savegame however must not
-//restore the cvar values themselves.
-//In case the cvar does NOT exist, then it is automatically created with the
-//value of the autocvar initializer, if given. This is possible with e.g.
-//frikqcc and fteqcc the following way:
-// var float autocvar_whatever = 42;
-//If no initializer is given, the cvar will be initialized to a string
-//equivalent to the NULL value of the given data type, that is, the empty
-//string, 0, or '0 0 0'. However, when automatic cvar creation took place, a
-//warning is printed to the game console.
-//NOTE: to prevent an ambiguity with float names for vector types, autocvar
-//names MUST NOT end with _x, _y or _z!
-
-//DP_QC_CHANGEPITCH
-//idea: id Software
-//darkplaces implementation: id Software
-//field definitions:
-.float idealpitch;
-.float pitch_speed;
-//builtin definitions:
-void(entity ent) changepitch = #63;
-//description:
-//equivalent to changeyaw, ent is normally self. (this was a Q2 builtin)
-
-//DP_QC_COPYENTITY
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(entity from, entity to) copyentity = #400;
-//description:
-//copies all data in the entity to another entity.
-
-//DP_QC_CRC16
-//idea: divVerent
-//darkplaces implementation: divVerent
-//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
-//When caseinsensitive is set, the CRC is calculated of the lower cased string.
-float(float caseinsensitive, string s, ...) crc16 = #494;
-
-//DP_QC_CVAR_DEFSTRING
-//idea: id Software (Doom3), LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-string(string s) cvar_defstring = #482;
-//description:
-//returns the default value of a cvar, as a tempstring.
-
-//DP_QC_CVAR_DESCRIPTION
-//idea: divVerent
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-string(string name) cvar_description = #518;
-//description:
-//returns the description of a cvar
-
-//DP_QC_CVAR_STRING
-//idea: VorteX
-//DarkPlaces implementation: VorteX, LordHavoc
-//builtin definitions:
-string(string s) cvar_string = #448;
-//description:
-//returns the value of a cvar, as a tempstring.
-
-//DP_QC_CVAR_TYPE
-//idea: divVerent
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-float(string name) cvar_type = #495;
-float CVAR_TYPEFLAG_EXISTS = 1;
-float CVAR_TYPEFLAG_SAVED = 2;
-float CVAR_TYPEFLAG_PRIVATE = 4;
-float CVAR_TYPEFLAG_ENGINE = 8;
-float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
-float CVAR_TYPEFLAG_READONLY = 32;
-
-//DP_QC_DIGEST
-//idea: motorsep, Spike
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-string(string digest, string data, ...) digest_hex = #639;
-//description:
-//returns a given hex digest of given data
-//the returned digest is always encoded in hexadecimal
-//only the "MD4" digest is always supported!
-//if the given digest is not supported, string_null is returned
-//the digest string is matched case sensitively, use "MD4", not "md4"!
-
-//DP_QC_DIGEST_SHA256
-//idea: motorsep, Spike
-//DarkPlaces implementation: divVerent
-//description:
-//"SHA256" is also an allowed digest type
-
-//DP_QC_EDICT_NUM
-//idea: 515
-//DarkPlaces implementation: LordHavoc
-//builtin definitions:
-entity(float entnum) edict_num = #459;
-float(entity ent) wasfreed = #353; // same as in EXT_CSQC extension
-//description:
-//edict_num returns the entity corresponding to a given number, this works even for freed entities, but you should call wasfreed(ent) to see if is currently active.
-//wasfreed returns whether an entity slot is currently free (entities that have never spawned are free, entities that have had remove called on them are also free).
-
-//DP_QC_ENTITYDATA
-//idea: KrimZon
-//darkplaces implementation: KrimZon
-//builtin definitions:
-float() numentityfields = #496;
-string(float fieldnum) entityfieldname = #497;
-float(float fieldnum) entityfieldtype = #498;
-string(float fieldnum, entity ent) getentityfieldstring = #499;
-float(float fieldnum, entity ent, string s) putentityfieldstring = #500;
-//constants:
-//Returned by entityfieldtype
-float FIELD_STRING = 1;
-float FIELD_FLOAT = 2;
-float FIELD_VECTOR = 3;
-float FIELD_ENTITY = 4;
-float FIELD_FUNCTION = 6;
-//description:
-//Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame.
-//WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers.
-//numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z.
-//entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever.
-//entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers.
-//getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
-//putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
-
-//DP_QC_ENTITYSTRING
-void(string s) loadfromdata = #529;
-void(string s) loadfromfile = #530;
-void(string s) callfunction = #605;
-void(float fh, entity e) writetofile = #606;
-float(string s) isfunction = #607;
-void(entity e, string s) parseentitydata = #608;
-
-//DP_QC_ETOS
-//idea: id Software
-//darkplaces implementation: id Software
-//builtin definitions:
-string(entity ent) etos = #65;
-//description:
-//prints "entity 1" or similar into a string. (this was a Q2 builtin)
-
-//DP_QC_EXTRESPONSEPACKET
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-string(void) getextresponse = #624;
-//description:
-//returns a string of the form "\"ipaddress:port\" data...", or the NULL string
-//if no packet was found. Packets can be queued into the client/server by
-//sending a packet starting with "\xFF\xFF\xFF\xFFextResponse " to the
-//listening port.
-
-//DP_QC_FINDCHAIN
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-entity(.string fld, string match) findchain = #402;
-//description:
-//similar to find() but returns a chain of entities like findradius.
-
-//DP_QC_FINDCHAIN_TOFIELD
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-entity(.string fld, float match, .entity tofield) findradius_tofield = #22;
-entity(.string fld, string match, .entity tofield) findchain_tofield = #402;
-entity(.string fld, float match, .entity tofield) findchainflags_tofield = #450;
-entity(.string fld, float match, .entity tofield) findchainfloat_tofield = #403;
-//description:
-//similar to findchain() etc, but stores the chain into .tofield instead of .chain
-//actually, the .entity tofield is an optional field of the the existing findchain* functions
-
-//DP_QC_FINDCHAINFLAGS
-//idea: Sajt
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-entity(.float fld, float match) findchainflags = #450;
-//description:
-//similar to findflags() but returns a chain of entities like findradius.
-
-//DP_QC_FINDCHAINFLOAT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-entity(.entity fld, entity match) findchainentity = #403;
-entity(.float fld, float match) findchainfloat = #403;
-//description:
-//similar to findentity()/findfloat() but returns a chain of entities like findradius.
-
-//DP_QC_FINDFLAGS
-//idea: Sajt
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-entity(entity start, .float fld, float match) findflags = #449;
-//description:
-//finds an entity with the specified flag set in the field, similar to find()
-
-//DP_QC_FINDFLOAT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-entity(entity start, .entity fld, entity match) findentity = #98;
-entity(entity start, .float fld, float match) findfloat = #98;
-//description:
-//finds an entity or float field value, similar to find(), but for entity and float fields.
-
-//DP_QC_FS_SEARCH
-//idea: Black
-//darkplaces implementation: Black
-//builtin definitions:
-float(string pattern, float caseinsensitive, float quiet) search_begin = #444;
-void(float handle) search_end = #445;
-float(float handle) search_getsize = #446;
-string(float handle, float num) search_getfilename = #447;
-//description:
-//search_begin performs a filename search with the specified pattern (for example "maps/*.bsp") and stores the results in a search slot (minimum of 128 supported by any engine with this extension), the other functions take this returned search slot number, be sure to search_free when done (they are also freed on progs reload).
-//search_end frees a search slot (also done at progs reload).
-//search_getsize returns how many filenames were found.
-//search_getfilename returns a filename from the search.
-
-//DP_QC_GETLIGHT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-vector(vector org) getlight = #92;
-//description:
-//returns the lighting at the requested location (in color), 0-255 range (can exceed 255).
-
-//DP_QC_GETSURFACE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-float(entity e, float s) getsurfacenumpoints = #434;
-vector(entity e, float s, float n) getsurfacepoint = #435;
-vector(entity e, float s) getsurfacenormal = #436;
-string(entity e, float s) getsurfacetexture = #437;
-float(entity e, vector p) getsurfacenearpoint = #438;
-vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
-//description:
-//functions to query surface information.
-
-//DP_QC_GETSURFACEPOINTATTRIBUTE
-//idea: BlackHC
-//darkplaces implementation: BlackHC
-// constants
-float SPA_POSITION = 0;
-float SPA_S_AXIS = 1;
-float SPA_T_AXIS = 2;
-float SPA_R_AXIS = 3; // same as SPA_NORMAL
-float SPA_TEXCOORDS0 = 4;
-float SPA_LIGHTMAP0_TEXCOORDS = 5;
-float SPA_LIGHTMAP0_COLOR = 6;
-//builtin definitions:
-vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
-
-//description:
-//function to query extended information about a point on a certain surface
-
-//DP_QC_GETSURFACETRIANGLE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-float(entity e, float s) getsurfacenumtriangles = #628;
-vector(entity e, float s, float n) getsurfacetriangle = #629;
-//description:
-//function to query triangles of a surface
-
-//DP_QC_GETTAGINFO
-//idea: VorteX, LordHavoc
-//DarkPlaces implementation: VorteX
-//builtin definitions:
-int(entity ent, string tagname) gettagindex = #451;
-vector(entity ent, float tagindex) gettaginfo = #452;
-//description:
-//gettagindex returns the number of a tag on an entity, this number is the same as set by setattachment (in the .tag_index field), allowing the qc to save a little cpu time by keeping the number around if it wishes (this could already be done by calling setattachment and saving off the tag_index).
-//gettaginfo returns the origin of the tag in worldspace and sets v_forward, v_right, and v_up to the current orientation of the tag in worldspace, this automatically resolves all dependencies (attachments, including viewmodelforclient), this means you could fire a shot from a tag on a gun entity attached to the view for example.
-
-//DP_QC_GETTAGINFO_BONEPROPERTIES
-//idea: daemon
-//DarkPlaces implementation: divVerent
-//global definitions:
-float gettaginfo_parent;
-string gettaginfo_name;
-vector gettaginfo_offset;
-vector gettaginfo_forward;
-vector gettaginfo_right;
-vector gettaginfo_up;
-//description:
-//when this extension is present, gettaginfo fills in some globals with info about the bone that had been queried
-//gettaginfo_parent is set to the number of the parent bone, or 0 if it is a root bone
-//gettaginfo_name is set to the name of the bone whose index had been specified in gettaginfo
-//gettaginfo_offset, gettaginfo_forward, gettaginfo_right, gettaginfo_up contain the transformation matrix of the bone relative to its parent. Note that the matrix may contain a scaling component.
-
-//DP_QC_GETTIME
-//idea: tZork
-//darkplaces implementation: tZork, divVerent
-//constant definitions:
-float GETTIME_FRAMESTART = 0; // time of start of frame
-float GETTIME_REALTIME = 1; // current time (may be OS specific)
-float GETTIME_HIRES = 2; // like REALTIME, but may reset between QC invocations and thus can be higher precision
-float GETTIME_UPTIME = 3; // time since start of the engine
-//builtin definitions:
-float(float tmr) gettime = #519;
-//description:
-//some timers to query...
-
-//DP_QC_GETTIME_CDTRACK
-//idea: divVerent
-//darkplaces implementation: divVerent
-//constant definitions:
-float GETTIME_CDTRACK = 4;
-//description:
-//returns the playing time of the current cdtrack when passed to gettime()
-//see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels
-
-//DP_QC_I18N
-//idea: divVerent
-//darkplaces implementation: divVerent
-//description:
-//
-//The engine supports translating by gettext compatible .po files.
-//progs.dat uses progs.dat.<LANGUAGE>.po
-//menu.dat uses menu.dat.<LANGUAGE>.po
-//csprogs.dat uses csprogs.dat.<LANGUAGE>.po
-//
-//To create a string that can be translated, define it as
-// string dotranslate_FILENOTFOUND = "File not found";
-//Note: if the compiler does constant folding, this will only work if there is
-//no other "File not found" string in the progs!
-//
-//Alternatively, if using the Xonotic patched fteqcc compiler, you can simplify
-//this by using _("File not found") directly in the source code.
-//
-//The language is set by the "prvm_language" cvar: if prvm_language is set to
-//"de", it will read progs.dat.de.po for translating strings in progs.dat.
-//
-//If prvm_language is set to the special name "dump", progs.dat.pot will be
-//written, which is a translation template to be edited by filling out the
-//msgstr entries.
-
-//DP_QC_LOG
-//darkplaces implementation: divVerent
-//builtin definitions:
-float log(float f) = #532;
-//description:
-//logarithm
-
-//DP_QC_MINMAXBOUND
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-float(float a, float b, ...) min = #94;
-float(float a, float b, float c) min3 = #94;
-float(float a, float b, float c, float d) min4 = #94;
-float(float a, float b, float c, float d, float e) min5 = #94;
-float(float a, float b, float c, float d, float e, float f) min6 = #94;
-float(float a, float b, float c, float d, float e, float f, float g) min7 = #94;
-float(float a, float b, float c, float d, float e, float f, float g, float h) min8 = #94;
-float(float a, float b, ...) max = #95;
-float(float a, float b, float c) max3 = #95;
-float(float a, float b, float c, float d) max4 = #95;
-float(float a, float b, float c, float d, float e) max5 = #95;
-float(float a, float b, float c, float d, float e, float f) max6 = #95;
-float(float a, float b, float c, float d, float e, float f, float g) max7 = #95;
-float(float a, float b, float c, float d, float e, float f, float g, float h) max8 = #95;
-float(float minimum, float val, float maximum) bound = #96;
-//description:
-//min returns the lowest of all the supplied numbers.
-//max returns the highest of all the supplied numbers.
-//bound clamps the value to the range and returns it.
-
-//DP_QC_MULTIPLETEMPSTRINGS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//this extension makes all builtins returning tempstrings (ftos for example)
-//cycle through a pool of multiple tempstrings (at least 16), allowing
-//multiple ftos results to be gathered before putting them to use, normal
-//quake only had 1 tempstring, causing many headaches.
-//
-//Note that for longer term storage (or compatibility on engines having
-//FRIK_FILE but not this extension) the FRIK_FILE extension's
-//strzone/strunzone builtins provide similar functionality (slower though).
-//
-//NOTE: this extension is superseded by DP_QC_UNLIMITEDTEMPSTRINGS
-
-//DP_QC_NUM_FOR_EDICT
-//idea: Blub\0
-//darkplaces implementation: Blub\0
-//Function to get the number of an entity - a clean way.
-float(entity num) num_for_edict = #512;
-
-//DP_QC_RANDOMVEC
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-vector() randomvec = #91;
-//description:
-//returns a vector of length < 1, much quicker version of this QC: do {v_x = random()*2-1;v_y = random()*2-1;v_z = random()*2-1;} while(vlen(v) > 1)
-
-//DP_QC_SINCOSSQRTPOW
-//idea: id Software, LordHavoc
-//darkplaces implementation: id Software, LordHavoc
-//builtin definitions:
-float(float val) sin = #60;
-float(float val) cos = #61;
-float(float val) sqrt = #62;
-float(float a, float b) pow = #97;
-//description:
-//useful math functions, sine of val, cosine of val, square root of val, and raise a to power b, respectively.
-
-//DP_QC_SPRINTF
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-string(string format, ...) sprintf = #627;
-//description:
-//you know sprintf :P
-//supported stuff:
-// %
-// optional: <argpos>$ for the argument to format
-// flags: #0- +
-// optional: <width>, *, or *<argpos>$ for the field width
-// optional: .<precision>, .*, or .*<argpos>$ for the precision
-// length modifiers: h for forcing a float, l for forcing an int/entity (by default, %d etc. cast a float to int)
-// conversions:
-// d takes a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an int
-// i takes an int/entity if no length is specified or i is, and a float if h is specified as length, and cast it to an int
-// ouxXc take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an unsigned int
-// eEfFgG take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to a double
-// s takes a string
-// vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space
-// For conversions s and c, the flag # makes precision and width interpreted
-// as byte count, by default it is interpreted as character count in UTF-8
-// enabled engines. No other conversions can create wide characters, and #
-// has another meaning in these. When in character count mode, color codes
-// are ignored. To get UTF-8 semantics WITHOUT color code parsing, use
-// the + flag.
-
-//DP_QC_STRFTIME
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-string(float uselocaltime, string format, ...) strftime = #478;
-//description:
-//provides the ability to get the local (in your timezone) or world (Universal Coordinated Time) time as a string using the formatting of your choice:
-//example: "%Y-%m-%d %H:%M:%S" (result looks like: 2007-02-08 01:03:15)
-//note: "%F %T" gives the same result as "%Y-%m-%d %H:%M:%S" (ISO 8601 date format and 24-hour time)
-//for more format codes please do a web search for strftime 3 and you should find the man(3) pages for this standard C function.
-//
-//practical uses:
-//changing day/night cycle (shops closing, monsters going on the prowl) in an RPG, for this you probably want to use s = strftime(true, "%H");hour = stof(s);
-//printing current date/time for competitive multiplayer games, such as the beginning/end of each round in real world time.
-//activating eastereggs in singleplayer games on certain dates.
-//
-//note: some codes such as %x and %X use your locale settings and thus may not make sense to international users, it is not advisable to use these as the server and clients may be in different countries.
-//note: if you display local time to a player, it would be a good idea to note whether it is local time using a string like "%F %T (local)", and otherwise use "%F %T (UTC)".
-//note: be aware that if the game is saved and reloaded a week later the date and time will be different, so if activating eastereggs in a singleplayer game or something you may want to only check when a level is loaded and then keep the same easteregg state throughout the level so that the easteregg does not deactivate when reloading from a savegame (also be aware that precaches should not depend on such date/time code because reloading a savegame often scrambles the precaches if so!).
-//note: this function can return a NULL string (you can check for it with if (!s)) if the localtime/gmtime functions returned NULL in the engine code, such as if those functions don't work on this platform (consoles perhaps?), so be aware that this may return nothing.
-
-//DP_QC_STRINGCOLORFUNCTIONS
-//idea: Dresk
-//darkplaces implementation: Dresk
-//builtin definitions:
-float(string s) strlennocol = #476; // returns how many characters are in a string, minus color codes
-string(string s) strdecolorize = #477; // returns a string minus the color codes of the string provided
-//description:
-//provides additional functionality to strings by supporting functions that isolate and identify strings with color codes
-
-//DP_QC_STRING_CASE_FUNCTIONS
-//idea: Dresk
-//darkplaces implementation: LordHavoc / Dresk
-//builtin definitions:
-string(string s) strtolower = #480; // returns the passed in string in pure lowercase form
-string(string s) strtoupper = #481; // returns the passed in string in pure uppercase form
-//description:
-//provides simple string uppercase and lowercase functions
-
-//DP_QC_TOKENIZEBYSEPARATOR
-//idea: Electro, SavageX, LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-int(string s, string separator1, ...) tokenizebyseparator = #479;
-//description:
-//this function returns tokens separated by any of the supplied separator strings, example:
-//numnumbers = tokenizebyseparator("10.2.3.4", ".");
-//returns 4 and the tokens are "10" "2" "3" "4"
-//possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000")
-
-//DP_QC_TOKENIZE_CONSOLE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-int(string s) tokenize_console = #514;
-int(float i) argv_start_index = #515;
-int(float i) argv_end_index = #516;
-//description:
-//this function returns tokens separated just like the console does
-//also, functions are provided to get the index of the first and last character of each token in the original string
-//Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token.
-
-//DP_QC_TRACEBOX
-//idea: id Software
-//darkplaces implementation: id Software
-//builtin definitions:
-void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox = #90;
-//description:
-//similar to traceline but much more useful, traces a box of the size specified (technical note: in quake1 and halflife bsp maps the mins and maxs will be rounded up to one of the hull sizes, quake3 bsp does not have this problem, this is the case with normal moving entities as well).
-
-//DP_QC_TRACETOSS
-//idea: id Software
-//darkplaces implementation: id Software
-//builtin definitions:
-void(entity ent, entity ignore) tracetoss = #64;
-//description:
-//simulates movement of the entity as if it is MOVETYPE_TOSS and starting with it's current state (location, velocity, etc), returns relevant trace_ variables (trace_fraction is always 0, all other values are supported - trace_ent, trace_endpos, trace_plane_normal), does not actually alter the entity.
-
-//DP_QC_TRACE_MOVETYPE_HITMODEL
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//constant definitions:
-float MOVE_HITMODEL = 4;
-//description:
-//allows traces to hit alias models (not sprites!) instead of entity boxes, use as the nomonsters parameter to trace functions, note that you can hit invisible model entities (alpha < 0 or EF_NODRAW or model "", it only checks modelindex)
-
-//DP_QC_TRACE_MOVETYPE_WORLDONLY
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//constant definitions:
-float MOVE_WORLDONLY = 3;
-//description:
-//allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions
-
-//DP_QC_UNLIMITEDTEMPSTRINGS
-//idea: divVerent
-//darkplaces implementation: LordHavoc
-//description:
-//this extension alters Quake behavior such that instead of reusing a single
-//tempstring (or multiple) there are an unlimited number of tempstrings, which
-//are removed only when a QC function invoked by the engine returns,
-//eliminating almost all imaginable concerns with string handling in QuakeC.
-//
-//in short:
-//you can now use and abuse tempstrings as much as you like, you still have to
-//use strzone (FRIK_FILE) for permanent storage however.
-//
-//
-//
-//implementation notes for other engine coders:
-//these tempstrings are expected to be stored in a contiguous buffer in memory
-//which may be fixed size or controlled by a cvar, or automatically grown on
-//demand (in the case of DarkPlaces).
-//
-//this concept is similar to quake's Zone system, however these are all freed
-//when the QC interpreter returns.
-//
-//this is basically a poor man's garbage collection system for strings.
-
-//DP_QC_VECTOANGLES_WITH_ROLL
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-vector(vector forward, vector up) vectoangles2 = #51; // same number as vectoangles
-//description:
-//variant of vectoangles that takes an up vector to calculate roll angle (also uses this to calculate yaw correctly if the forward is straight up or straight down)
-//note: just like normal vectoangles you need to negate the pitch of the returned angles if you want to feed them to makevectors or assign to self.v_angle
-
-//DP_QC_VECTORVECTORS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector dir) vectorvectors = #432;
-//description:
-//creates v_forward, v_right, and v_up vectors given a forward vector, similar to makevectors except it takes a forward direction vector instead of angles.
-
-//DP_QC_WHICHPACK
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-string(string filename) whichpack = #503;
-//description:
-//returns the name of the pak/pk3/whatever containing the given file, in the same path space as FRIK_FILE functions use (that is, possibly with a path name prefix)
-
-//DP_QC_URI_ESCAPE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//URI::Escape's functionality
-string(string in) uri_escape = #510;
-string(string in) uri_unescape = #511;
-
-//DP_QC_URI_GET
-//idea: divVerent
-//darkplaces implementation: divVerent
-//loads text from an URL into a string
-//returns 1 on success of initiation, 0 if there are too many concurrent
-//connections already or if the URL is invalid
-//the following callback will receive the data and MUST exist!
-// void(float id, float status, string data) URI_Get_Callback;
-//status is either
-// negative for an internal error,
-// 0 for success, or
-// the HTTP response code on server error (e.g. 404)
-//if 1 is returned by uri_get, the callback will be called in the future
-float(string url, float id) uri_get = #513;
-
-//DP_QC_URI_POST
-//idea: divVerent
-//darkplaces implementation: divVerent
-//loads text from an URL into a string after POSTing via HTTP
-//works like uri_get, but uri_post sends data with Content-Type: content_type to the server
-//and uri_post sends the string buffer buf, joined using the delimiter delim
-float(string url, float id, string content_type, string data) uri_post = #513;
-float(string url, float id, string content_type, string delim, float buf) uri_postbuf = #513;
-
-//DP_SKELETONOBJECTS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//this extension indicates that FTE_CSQC_SKELETONOBJECTS functionality is available in server QC (as well as CSQC).
-
-//DP_SV_SPAWNFUNC_PREFIX
-//idea: divVerent
-//darkplaces implementation: divVerent
-//Make functions whose name start with spawnfunc_ take precedence as spawn function for loading entities.
-//Useful if you have a field ammo_shells (required in any Quake mod) but want to support spawn functions called ammo_shells (like in Q3A).
-//Optionally, you can declare a global "float require_spawnfunc_prefix;" which will require ANY spawn function to start with that prefix.
-
-
-//DP_QUAKE2_MODEL
-//idea: quake community
-//darkplaces implementation: LordHavoc
-//description:
-//shows that the engine supports Quake2 .md2 files.
-
-//DP_QUAKE2_SPRITE
-//idea: LordHavoc
-//darkplaces implementation: Elric
-//description:
-//shows that the engine supports Quake2 .sp2 files.
-
-//DP_QUAKE3_MAP
-//idea: quake community
-//darkplaces implementation: LordHavoc
-//description:
-//shows that the engine supports Quake3 .bsp files.
-
-//DP_QUAKE3_MODEL
-//idea: quake community
-//darkplaces implementation: LordHavoc
-//description:
-//shows that the engine supports Quake3 .md3 files.
-
-//DP_REGISTERCVAR
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-float(string name, string value) registercvar = #93;
-//description:
-//adds a new console cvar to the server console (in singleplayer this is the player's console), the cvar exists until the mod is unloaded or the game quits.
-//NOTE: DP_CON_SET is much better.
-
-//DP_SND_DIRECTIONLESSATTNNONE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//make sounds with ATTN_NONE have no spatialization (enabling easy use as music sources).
-
-//DP_SND_FAKETRACKS
-//idea: requested
-
-//darkplaces implementation: Elric
-//description:
-//the engine plays sound/cdtracks/track001.wav instead of cd track 1 and so on if found, this allows games and mods to have music tracks without using ambientsound.
-//Note: also plays .ogg with DP_SND_OGGVORBIS extension.
-
-//DP_SND_SOUND7_WIP1
-//DP_SND_SOUND7_WIP2
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8;
-float SOUNDFLAG_RELIABLE = 1;
-//description:
-//plays a sound, with some more flags
-//extensions to sound():
-//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto",
-// i.e. support multiple sounds at once, but cannot be stopped/restarted
-//- a value 0 in the speed parameter means no change; otherwise, it is a
-// percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is
-// half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2)
-//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send
-// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default);
-// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE
-//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by
-// snd_channel1volume, etc. (so, a channel shares the cvar with its respective
-// auto-channel); however, the mod MUST define snd_channel8volume and upwards
-// in default.cfg if they are to be used, as the engine does not create them
-// to not litter the cvar list
-//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and
-// flags as extra 7th and 8th argument
-//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP
-//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support
-// the finished extension once done
-
-//DP_SND_OGGVORBIS
-//idea: Transfusion
-//darkplaces implementation: Elric
-//description:
-//the engine supports loading Ogg Vorbis sound files. Use either the .ogg filename directly, or a .wav of the same name (will try to load the .wav first and then .ogg).
-
-//DP_SND_STEREOWAV
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//the engine supports stereo WAV files. (useful with DP_SND_DIRECTIONLESSATTNNONE for music)
-
-//DP_SND_GETSOUNDTIME
-//idea: VorteX
-//darkplaces implementation: VorteX
-//constant definitions:
-float(entity e, float channel) getsoundtime = #533; // get currently sound playing position on entity channel, -1 if not playing or error
-float(string sample) soundlength = #534; // returns length of sound sample in seconds, -1 on error (sound not precached, sound system not initialized etc.)
-//description: provides opportunity to query length of sound samples and realtime tracking of sound playing on entities (similar to DP_GETTIME_CDTRACK)
-//note: beware dedicated server not running sound engine at all, so in dedicated mode this builtins will not work in server progs
-//note also: menu progs not supporting getsoundtime() (will give a warning) since it has no sound playing on entities
-//examples of use:
-// - QC-driven looped sounds
-// - QC events when sound playing is finished
-// - toggleable ambientsounds
-// - subtitles
-
-//DP_VIDEO_DPV
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//console commands:
-// playvideo <videoname> - start playing video
-// stopvideo - stops current video
-//description: indicated that engine support playing videos in DPV format
-
-//DP_VIDEO_SUBTITLES
-//idea: VorteX
-//darkplaces implementation: VorteX
-//cvars:
-// cl_video_subtitles - toggles subtitles showing
-// cl_video_subtitles_lines - how many lines to reserve for subtitles
-// cl_video_subtitles_textsize - font size
-//console commands:
-// playvideo <videoname> <custom_subtitles_file> - start playing video
-// stopvideo - stops current video
-//description: indicates that engine support subtitles on videos
-//subtitles stored in external text files, each video file has it's default subtitles file ( <videoname>.dpsubs )
-//example: for video/act1.dpv default subtitles file will be video/act1.dpsubs
-//also video could be played with custom subtitles file by utilizing second parm of playvideo command
-//syntax of .dpsubs files: each line in .dpsubs file defines 1 subtitle, there are three tokens:
-// <start> <end> "string"
-// start: subtitle start time in seconds
-// end: subtitle time-to-show in seconds, if 0 - subtitle will be showed until next subtitle is started,
-// if below 0 - show until next subtitles minus this number of seconds
-// text: subtitle text, color codes (Q3-style and ^xRGB) are allowed
-//example of subtitle file:
-// 3 0 "Vengeance! Vengeance for my eternity of suffering!"
-// 9 0 "Whelp! As if you knew what eternity was!"
-// 13 0 "Grovel before your true master."
-// 17 0 "Never!"
-// 18 7 "I'll hack you from crotch to gizzard and feed what's left of you to your brides..."
-
-//DP_SOLIDCORPSE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//solid definitions:
-float SOLID_CORPSE = 5;
-//description:
-//the entity will not collide with SOLID_CORPSE and SOLID_SLIDEBOX entities (and likewise they will not collide with it), this is useful if you want dead bodies that are shootable but do not obstruct movement by players and monsters, note that if you traceline with a SOLID_SLIDEBOX entity as the ignoreent, it will ignore SOLID_CORPSE entities, this is desirable for visibility and movement traces, but not for bullets, for the traceline to hit SOLID_CORPSE you must temporarily force the player (or whatever) to SOLID_BBOX and then restore to SOLID_SLIDEBOX after the traceline.
-
-//DP_SPRITE32
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//the engine supports .spr32 sprites.
-
-//DP_SV_BOTCLIENT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//constants:
-float CLIENTTYPE_DISCONNECTED = 0;
-float CLIENTTYPE_REAL = 1;
-float CLIENTTYPE_BOT = 2;
-float CLIENTTYPE_NOTACLIENT = 3;
-//builtin definitions:
-entity() spawnclient = #454; // like spawn but for client slots (also calls relevant connect/spawn functions), returns world if no clients available
-float(entity clent) clienttype = #455; // returns one of the CLIENTTYPE_* constants
-//description:
-//spawns a client with no network connection, to allow bots to use client slots with no hacks.
-//How to use:
-/*
- // to spawn a bot
- local entity oldself;
- oldself = self;
- self = spawnclient();
- if (!self)
- {
- bprint("Can not add bot, server full.\n");
- self = oldself;
- return;
- }
- self.netname = "Yoyobot";
- self.clientcolors = 12 * 16 + 4; // yellow (12) shirt and red (4) pants
- ClientConnect();
- PutClientInServer();
- self = oldself;
-
- // to remove all bots
- local entity head;
- head = find(world, classname, "player");
- while (head)
- {
- if (clienttype(head) == CLIENTTYPE_BOT)
- dropclient(head);
- head = find(head, classname, "player");
- }
-
- // to identify if a client is a bot (for example in PlayerPreThink)
- if (clienttype(self) == CLIENTTYPE_BOT)
- botthink();
-*/
-//see also DP_SV_CLIENTCOLORS DP_SV_CLIENTNAME DP_SV_DROPCLIENT
-//How it works:
-//creates a new client, calls SetNewParms and stores the parms, and returns the client.
-//this intentionally does not call SV_SendServerinfo to allow the QuakeC a chance to set the netname and clientcolors fields before actually spawning the bot by calling ClientConnect and PutClientInServer manually
-//on level change ClientConnect and PutClientInServer are called by the engine to spawn in the bot (this is why clienttype() exists to tell you on the next level what type of client this is).
-//parms work the same on bot clients as they do on real clients, and do carry from level to level
-
-//DP_SV_BOUNCEFACTOR
-//idea: divVerent
-//darkplaces implementation: divVerent
-//field definitions:
-.float bouncefactor; // velocity multiplier after a bounce
-.float bouncestop; // bounce stops if velocity to bounce plane is < bouncestop * gravity AFTER the bounce
-//description:
-//allows qc to customize MOVETYPE_BOUNCE a bit
-
-//DP_SV_CLIENTCAMERA
-//idea: LordHavoc, others
-//darkplaces implementation: Black
-//field definitions:
-.entity clientcamera; // override camera entity
-//description:
-//allows another entity to be the camera for a client, for example a remote camera, this is similar to sending svc_setview manually except that it also changes the network culling appropriately.
-
-//DP_SV_CLIENTCOLORS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float clientcolors; // colors of the client (format: pants + shirt * 16)
-//description:
-//allows qc to read and modify the client colors associated with a client entity (not particularly useful on other entities), and automatically sends out any appropriate network updates if changed
-
-//DP_SV_CLIENTNAME
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//description:
-//allows qc to modify the client's .netname, and automatically sends out any appropriate network updates if changed
-
-//DP_SV_CUSTOMIZEENTITYFORCLIENT
-//idea: LordHavoc
-//darkplaces implementation: [515] and LordHavoc
-//field definitions:
-.float() customizeentityforclient; // self = this entity, other = client entity
-//description:
-//allows qc to modify an entity before it is sent to each client, the function returns true if it should send, false if it should not, and is fully capable of editing the entity's fields, this allows cloaked players to appear less transparent to their teammates, navigation markers to only show to their team, etc
-//tips on writing customize functions:
-//it is a good idea to return false early in the function if possible to reduce cpu usage, because this function may be called many thousands of times per frame if there are many customized entities on a 64+ player server.
-//you are free to change anything in self, but please do not change any other entities (the results may be very inconsistent).
-//example ideas for use of this extension:
-//making icons over teammates' heads which are only visible to teammates. for exasmple: float() playericon_customizeentityforclient = {return self.owner.team == other.team;};
-//making cloaked players more visible to their teammates than their enemies. for example: float() player_customizeentityforclient = {if (self.items & IT_CLOAKING) {if (self.team == other.team) self.alpha = 0.6;else self.alpha = 0.1;} return true;};
-//making explosion models that face the viewer (does not work well with chase_active). for example: float() explosion_customizeentityforclient = {self.angles = vectoangles(other.origin + other.view_ofs - self.origin);self.angles_x = 0 - self.angles_x;};
-//implementation notes:
-//entity customization is done before per-client culling (visibility for instance) because the entity may be doing setorigin to display itself in different locations on different clients, may be altering its .modelindex, .effects and other fields important to culling, so customized entities increase cpu usage (non-customized entities can use all the early culling they want however, as they are not changing on a per client basis).
-
-//DP_SV_DISCARDABLEDEMO
-//idea: parasti
-//darkplaces implementation: parasti
-//field definitions:
-.float discardabledemo;
-//description:
-//when this field is set to a non-zero value on a player entity, a possibly recorded server-side demo for the player is discarded
-//Note that this extension only works if:
-// auto demos are enabled (the cvar sv_autodemo_perclient is set)
-// discarding demos is enabled (the cvar sv_autodemo_perclient_discardable is set)
-
-//DP_SV_DRAWONLYTOCLIENT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.entity drawonlytoclient;
-//description:
-//the entity is only visible to the specified client.
-
-//DP_SV_DROPCLIENT
-//idea: FrikaC
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(entity clent) dropclient = #453;
-//description:
-//causes the server to immediately drop the client, more reliable than stuffcmd(clent, "disconnect\n"); which could be intentionally ignored by the client engine
-
-//DP_SV_EFFECT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404;
-//SVC definitions:
-//float svc_effect = #52; // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
-//float svc_effect2 = #53; // [vector] org [short] modelindex [byte] startframe [byte] framecount [byte] framerate
-//description:
-//clientside playback of simple custom sprite effects (explosion sprites, etc).
-
-//DP_SV_ENTITYCONTENTSTRANSITION
-//idea: Dresk
-//darkplaces implementation: Dresk
-//field definitions:
-.void(float nOriginalContents, float nNewContents) contentstransition;
-//description:
-//This field function, when provided, is triggered on an entity when the contents (ie. liquid / water / etc) is changed.
-//The first parameter provides the entities original contents, prior to the transition. The second parameter provides the new contents.
-//NOTE: If this field function is provided on an entity, the standard watersplash sound IS SUPPRESSED to allow for authors to create their own transition sounds.
-
-//DP_SV_MOVETYPESTEP_LANDEVENT
-//idea: Dresk
-//darkplaces implementation: Dresk
-//field definitions:
-.void(vector vImpactVelocity) movetypesteplandevent;
-//description:
-//This field function, when provided, is triggered on a MOVETYPE_STEP entity when it experiences "land event".
-// The standard engine behavior for this event is to play the sv_sound_land CVar sound.
-//The parameter provides the velocity of the entity at the time of the impact. The z value may therefore be used to calculate how "hard" the entity struck the surface.
-//NOTE: If this field function is provided on a MOVETYPE_STEP entity, the standard sv_sound_land sound IS SUPPRESSED to allow for authors to create their own feedback.
-
-//DP_SV_POINTSOUND
-//idea: Dresk
-//darkplaces implementation: Dresk
-//builtin definitions:
-void(vector origin, string sample, float volume, float attenuation) pointsound = #483;
-//description:
-//Similar to the standard QC sound function, this function takes an origin instead of an entity and omits the channel parameter.
-// This allows sounds to be played at arbitrary origins without spawning entities.
-
-//DP_SV_ONENTITYNOSPAWNFUNCTION
-//idea: Dresk
-//darkplaces implementation: Dresk
-//engine-called QC prototypes:
-//void() SV_OnEntityNoSpawnFunction;
-//description:
-// This function is called whenever an entity on the server has no spawn function, and therefore has no defined QC behavior.
-// You may as such dictate the behavior as to what happens to the entity.
-// To mimic the engine's default behavior, simply call remove(self).
-
-//DP_SV_ONENTITYPREPOSTSPAWNFUNCTION
-//idea: divVerent
-//darkplaces implementation: divVerent
-//engine-called QC prototypes:
-//void() SV_OnEntityPreSpawnFunction;
-//void() SV_OnEntityPostSpawnFunction;
-//description:
-// These functions are called BEFORE or AFTER an entity is spawned the regular way.
-// You may as such dictate the behavior as to what happens to the entity.
-// SV_OnEntityPreSpawnFunction is called before even looking for the spawn function, so you can even change its classname in there. If it remove()s the entity, the spawn function will not be looked for.
-// SV_OnEntityPostSpawnFunction is called ONLY after its spawn function or SV_OnEntityNoSpawnFunction was called, and skipped if the entity got removed by either.
-
-//DP_SV_MODELFLAGS_AS_EFFECTS
-//idea: LordHavoc, Dresk
-//darkplaces implementation: LordHavoc
-//field definitions:
-.int modelflags;
-//constant definitions:
-float EF_NOMODELFLAGS = 8388608; // ignore any effects in a model file and substitute your own
-float MF_ROCKET = 1; // leave a trail
-float MF_GRENADE = 2; // leave a trail
-float MF_GIB = 4; // leave a trail
-float MF_ROTATE = 8; // rotate (bonus items)
-float MF_TRACER = 16; // green split trail
-float MF_ZOMGIB = 32; // small blood trail
-float MF_TRACER2 = 64; // orange split trail
-float MF_TRACER3 = 128; // purple trail
-//description:
-//this extension allows model flags to be specified on entities so you can add a rocket trail and glow to any entity, etc.
-//setting any of these will override the flags the model already has, to disable the model's flags without supplying any of your own you must use EF_NOMODELFLAGS.
-//
-//silly example modification #1 to W_FireRocket in weapons.qc:
-//missile.effects = EF_NOMODELFLAGS; // rocket without a glow/fire trail
-//silly example modification #2 to W_FireRocket in weapons.qc:
-//missile.modelflags = MF_GIB; // leave a blood trail instead of glow/fire trail
-//
-//note: you can not combine multiple kinds of trail, only one of them will be active, you can combine MF_ROTATE and the other MF_ flags however, and using EF_NOMODELFLAGS along with these does no harm.
-//
-//note to engine coders: they are internally encoded in the protocol as extra EF_ flags (shift the values left 24 bits and send them in the protocol that way), so no protocol change was required (however 32bit effects is a protocol extension itself), within the engine they are referred to as EF_ for the 24bit shifted values.
-
-//DP_SV_NETADDRESS
-//idea: Dresk
-//darkplaces implementation: Dresk
-//field definitions:
-.string netaddress;
-//description:
-// provides the netaddress of the associated entity (ie. 127.0.0.1) and "null/botclient" if the netconnection of the entity is invalid
-
-//DP_SV_NODRAWTOCLIENT
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.entity nodrawtoclient;
-//description:
-//the entity is not visible to the specified client.
-
-//DP_SV_PING
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float ping;
-//description:
-//continuously updated field indicating client's ping (based on average of last 16 packet time differences).
-
-//DP_SV_PING_PACKETLOSS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float ping_packetloss;
-.float ping_movementloss;
-//description:
-//continuously updated field indicating client's packet loss, and movement loss (i.e. packet loss affecting player movement).
-
-//DP_SV_POINTPARTICLES
-//idea: Spike
-//darkplaces implementation: LordHavoc
-//function definitions:
-int(string effectname) particleeffectnum = #335; // same as in CSQC
-void(entity ent, float effectnum, vector start, vector end) trailparticles = #336; // same as in CSQC
-void(float effectnum, vector org, vector vel, float howmany) pointparticles = #337; // same as in CSQC
-//SVC definitions:
-//float svc_trailparticles = 60; // [short] entnum [short] effectnum [vector] start [vector] end
-//float svc_pointparticles = 61; // [short] effectnum [vector] start [vector] velocity [short] count
-//float svc_pointparticles1 = 62; // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1
-//description:
-//provides the ability to spawn non-standard particle effects, typically these are defined in a particle effect information file such as effectinfo.txt in darkplaces.
-//this is a port of particle effect features from clientside QC (EXT_CSQC) to server QC, as these effects are potentially useful to all games even if they do not make use of EXT_CSQC.
-//warning: server must have same order of effects in effectinfo.txt as client does or the numbers would not match up, except for standard quake effects which are always the same numbers.
-
-//DP_SV_PUNCHVECTOR
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.vector punchvector;
-//description:
-//offsets client view in worldspace, similar to view_ofs but all 3 components are used and are sent with at least 8 bits of fraction, this allows the view to be kicked around by damage or hard landings or whatever else, note that unlike punchangle this is not faded over time, it is up to the mod to fade it (see also DP_SV_PLAYERPHYSICS).
-
-//DP_SV_PLAYERPHYSICS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.vector movement;
-//cvar definitions:
-//"sv_playerphysicsqc" (0/1, default 1, allows user to disable qc player physics)
-//engine-called QC prototypes:
-//void() SV_PlayerPhysics;
-//description:
-//.movement vector contains the movement input from the player, allowing QC to do as it wishs with the input, and SV_PlayerPhysics will completely replace the player physics if present (works for all MOVETYPE's), see darkplaces mod source for example of this function (in playermovement.qc, adds HalfLife ladders support, as well as acceleration/deceleration while airborn (rather than the quake sudden-stop while airborn), and simplifies the physics a bit)
-
-//DP_PHYSICS_ODE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//globals:
-//new movetypes:
-const float MOVETYPE_PHYSICS = 32; // need to be set before any physics_* builtins applied
-//new solid types (deprecated):
-const float SOLID_PHYSICS_BOX = 32;
-const float SOLID_PHYSICS_SPHERE = 33;
-const float SOLID_PHYSICS_CAPSULE = 34;
-const float SOLID_PHYSICS_TRIMESH = 35;
-const float SOLID_PHYSICS_CYLINDER = 36;
-//geometry types:
-const float GEOMTYPE_NONE = -1; // entity will be entirely skipped by ODE
-const float GEOMTYPE_SOLID = 0; // geometry type will be set based on .solid field
-const float GEOMTYPE_BOX = 1; // entity bound box
-const float GEOMTYPE_SPHERE = 2; // sphere with radius picked from x axis of entity bound box
-const float GEOMTYPE_CAPSULE = 3; // with leading axis automatically determined from longest one, radius is picked as minimal of the rest 2 axes
-const float GEOMTYPE_TRIMESH = 4; // triangle mesh
-const float GEOMTYPE_CYLINDER = 5; // like capsule but not capped
- // note that ODE's builtin cylinder support is experimental, somewhat bugged and unfinished (no cylinder-cylinder collision)
- // to use properly working cylinder should build ODE with LIBCCD extension
-const float GEOMTYPE_CAPSULE_X = 6; // capsule with fixed leading axis
-const float GEOMTYPE_CAPSULE_Y = 7;
-const float GEOMTYPE_CAPSULE_Z = 8;
-const float GEOMTYPE_CYLINDER_X = 9; // cylinder with fixed leading axis
-const float GEOMTYPE_CYLINDER_Y = 10;
-const float GEOMTYPE_CYLINDER_Z = 11;
-//joint types:
-const float JOINTTYPE_NONE = 0;
-const float JOINTTYPE_POINT = 1;
-const float JOINTTYPE_HINGE = 2;
-const float JOINTTYPE_SLIDER = 3;
-const float JOINTTYPE_UNIVERSAL = 4;
-const float JOINTTYPE_HINGE2 = 5;
-const float JOINTTYPE_FIXED = -1;
-//force types:
-const float FORCETYPE_NONE = 0;
-const float FORCETYPE_FORCE = 1; // applied at center of mass
-const float FORCETYPE_FORCEATPOS = 2;
-const float FORCETYPE_TORQUE = 3;
-// common joint properties:
-// .entity aiment; // connected objects
-// .entity enemy; // connected objects, forces
-// .vector movedir;
-// for a spring:
-// movedir_x = spring constant (force multiplier, must be > 0)
-// movedir_y = spring dampening constant to prevent oscillation (must be > 0)
-// movedir_z = spring stop position (+/-)
-// for a motor:
-// movedir_x = desired motor velocity
-// movedir_y = -1 * max motor force to use
-// movedir_z = stop position (+/-), set to 0 for no stop
-// note that ODE does not support both in one anyway
-// for a force:
-// force vector to apply
-//field definitions:
-.float geomtype; // see GEOMTYPE_*, a more correct way to set collision shape, allows to set SOLID_CORPSE and trimesh collisions
-.float maxcontacts; // maximum number of contacts to make for this object, lesser = faster (but setting it too low will could make object pass though walls), default is 16, maximum is 32
-.float mass; // ODE mass, standart value is 1
-.vector massofs; // offsets a mass center out of object center, if not set a center of model bounds is used
-.float friction; // a friction of object, get multiplied by second objects's friction on contact
-.float bouncefactor;
-.float bouncestop;
-.float jointtype; // type of joint
-.float forcetype; // type of force
-.float erp; // error restitution parameter, makes ODE solver attempt to fix errors in contacts,
- // bringing together 2 joints or fixing object being stuch in other object,
- // a value of 0.1 will fix slightly, a value of 1.0 attempts to fix whole error in one frame
- // use with care as high values makes system unstable and likely to explode
-//builtin definitions:
-void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object
-void(entity e, vector force, vector force_pos) physics_addforce = #541; // deprecated, apply a force from certain origin, length of force vector is power of force
-void(entity e, vector torque) physics_addtorque = #542; // deprecated, add relative torque
-//description: provides Open Dynamics Engine support, requires extenal dll to be present or engine compiled with statical link option
-//be sure to checkextension for it to know if library is loaded and ready, also to enable physics set "physics_ode" cvar to 1
-//note: this extension is highly experimental and may be unstable
-
-//DP_SV_PRINT
-//idea: id Software (QuakeWorld Server)
-//darkplaces implementation: Black, LordHavoc
-void(string s, ...) print = #339; // same number as in EXT_CSQC
-//description:
-//this is identical to dprint except that it always prints regardless of the developer cvar.
-
-//DP_SV_PRECACHEANYTIME
-//idea: id Software (Quake2)
-//darkplaces implementation: LordHavoc
-//description:
-//this extension allows precache_model and precache_sound (and any variants) to be used during the game (with automatic messages to clients to precache the new model/sound indices), also setmodel/sound/ambientsound can be called without precaching first (they will cause an automatic precache).
-
-//DP_SV_QCSTATUS
-//idea: divVerent
-//darkplaces implementation: divVerent
-//1. A global variable
-string worldstatus;
-//Its content is set as "qcstatus" field in the rules.
-//It may be at most 255 characters, and must not contain newlines or backslashes.
-//2. A per-client field
-.string clientstatus;
-//It is sent instead of the "frags" in status responses.
-//It should always be set in a way so that stof(player.clientstatus) is a meaningful score value. Other info may be appended. If used this way, the cvar sv_status_use_qcstatus may be set to 1, and then this value will replace the frags in "status".
-//Currently, qstat does not support this and will not show player info if used and set to anything other than ftos(some integer).
-
-//DP_SV_ROTATINGBMODEL
-//idea: id Software
-//darkplaces implementation: LordHavoc
-//description:
-//this extension merely indicates that MOVETYPE_PUSH supports avelocity, allowing rotating brush models to be created, they rotate around their origin (needs rotation supporting qbsp/light utilities because id ones expected bmodel entity origins to be '0 0 0', recommend setting "origin" key in the entity fields in the map before compiling, there may be other methods depending on your qbsp, most are more complicated however).
-//tip: level designers can create a func_wall with an origin, and avelocity (for example "avelocity" "0 90 0"), and "nextthink" "99999999" to make a rotating bmodel without any qc modifications, such entities will be solid in stock quake but will not rotate)
-
-//DP_SV_SETCOLOR
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(entity ent, float colors) setcolor = #401;
-//engine called QC functions (optional):
-//void(float color) SV_ChangeTeam;
-//description:
-//setcolor sets the color on a client and updates internal color information accordingly (equivalent to stuffing a "color" command but immediate)
-//SV_ChangeTeam is called by the engine whenever a "color" command is recieved, it may decide to do anything it pleases with the color passed by the client, including rejecting it (by doing nothing), or calling setcolor to apply it, preventing team changes is one use for this.
-//the color format is pants + shirt * 16 (0-255 potentially)
-
-//DP_SV_SLOWMO
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//cvars:
-//"slowmo" (0+, default 1)
-//description:
-//sets the time scale of the server, mainly intended for use in singleplayer by the player, however potentially useful for mods, so here's an extension for it.
-//range is 0 to infinite, recommended values to try are 0.1 (very slow, 10% speed), 1 (normal speed), 5 (500% speed).
-
-//DP_SV_WRITEPICTURE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//builtin definitions:
-void(float to, string s, float sz) WritePicture = #501;
-//description:
-//writes a picture to the data stream so CSQC can read it using ReadPicture, which has the definition
-// string(void) ReadPicture = #501;
-//The picture data is sent as at most sz bytes, by compressing to low quality
-//JPEG. The data being sent will be equivalent to:
-// WriteString(to, s);
-// WriteShort(to, imagesize);
-// for(i = 0; i < imagesize; ++i)
-// WriteByte(to, [the i-th byte of the compressed JPEG image]);
-
-//DP_SV_WRITEUNTERMINATEDSTRING
-//idea: FrikaC
-//darkplaces implementation: Sajt
-//builtin definitions:
-void(float to, string s) WriteUnterminatedString = #456;
-//description:
-//like WriteString, but does not write a terminating 0 after the string. This means you can include things like a player's netname in the middle of a string sent over the network. Just be sure to end it up with either a call to WriteString (which includes the trailing 0) or WriteByte(0) to terminate it yourself.
-//A historical note: this extension was suggested by FrikaC years ago, more recently Shadowalker has been badmouthing LordHavoc and Spike for stealing 'his' extension writestring2 which does exactly the same thing but uses a different builtin number and name and extension string, this argument hinges on the idea that it was his idea in the first place, which is incorrect as FrikaC first suggested it and used a rough equivalent of it in his FrikBot mod years ago involving WriteByte calls on each character.
-
-//DP_TE_BLOOD
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org, vector velocity, float howmany) te_blood = #405;
-//temp entity definitions:
-float TE_BLOOD = 50;
-//protocol:
-//vector origin
-//byte xvelocity (-128 to +127)
-//byte yvelocity (-128 to +127)
-//byte zvelocity (-128 to +127)
-//byte count (0 to 255, how much blood)
-//description:
-//creates a blood effect.
-
-//DP_TE_BLOODSHOWER
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406;
-//temp entity definitions:
-//float TE_BLOODSHOWER = 52;
-//protocol:
-//vector mins (minimum corner of the cube)
-//vector maxs (maximum corner of the cube)
-//coord explosionspeed (velocity of blood particles flying out of the center)
-//short count (number of blood particles)
-//description:
-//creates an exploding shower of blood, for making gibbings more convincing.
-
-//DP_TE_CUSTOMFLASH
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org, float radius, float lifetime, vector color) te_customflash = #417;
-//temp entity definitions:
-//float TE_CUSTOMFLASH = 73;
-//protocol:
-//vector origin
-//byte radius ((MSG_ReadByte() + 1) * 8, meaning 8-2048 unit radius)
-//byte lifetime ((MSG_ReadByte() + 1) / 256.0, meaning approximately 0-1 second lifetime)
-//byte red (0.0 to 1.0 converted to 0-255)
-//byte green (0.0 to 1.0 converted to 0-255)
-//byte blue (0.0 to 1.0 converted to 0-255)
-//description:
-//creates a customized light flash.
-
-//DP_TE_EXPLOSIONRGB
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org, vector color) te_explosionrgb = #407;
-//temp entity definitions:
-//float TE_EXPLOSIONRGB = 53;
-//protocol:
-//vector origin
-//byte red (0.0 to 1.0 converted to 0 to 255)
-//byte green (0.0 to 1.0 converted to 0 to 255)
-//byte blue (0.0 to 1.0 converted to 0 to 255)
-//description:
-//creates a colored explosion effect.
-
-//DP_TE_FLAMEJET
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org, vector vel, float howmany) te_flamejet = #457;
-//temp entity definitions:
-//float TE_FLAMEJET = 74;
-//protocol:
-//vector origin
-//vector velocity
-//byte count (0 to 255, how many flame particles)
-//description:
-//creates a single puff of flame particles. (not very useful really)
-
-//DP_TE_PARTICLECUBE
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408;
-//temp entity definitions:
-//float TE_PARTICLECUBE = 54;
-//protocol:
-//vector mins (minimum corner of the cube)
-//vector maxs (maximum corner of the cube)
-//vector velocity
-//short count
-//byte color (palette color)
-//byte gravity (true or false, FIXME should this be a scaler instead?)
-//coord randomvel (how much to jitter the velocity)
-//description:
-//creates a cloud of particles, useful for forcefields but quite customizable.
-
-//DP_TE_PARTICLERAIN
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409;
-//temp entity definitions:
-//float TE_PARTICLERAIN = 55;
-//protocol:
-//vector mins (minimum corner of the cube)
-//vector maxs (maximum corner of the cube)
-//vector velocity (velocity of particles)
-//short count (number of particles)
-//byte color (8bit palette color)
-//description:
-//creates a shower of rain, the rain will appear either at the top (if falling down) or bottom (if falling up) of the cube.
-
-//DP_TE_PARTICLESNOW
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410;
-//temp entity definitions:
-//float TE_PARTICLERAIN = 56;
-//protocol:
-//vector mins (minimum corner of the cube)
-//vector maxs (maximum corner of the cube)
-//vector velocity (velocity of particles)
-//short count (number of particles)
-//byte color (8bit palette color)
-//description:
-//creates a shower of snow, the snow will appear either at the top (if falling down) or bottom (if falling up) of the cube, low velocities are advisable for convincing snow.
-
-//DP_TE_PLASMABURN
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org) te_plasmaburn = #433;
-//temp entity definitions:
-//float TE_PLASMABURN = 75;
-//protocol:
-//vector origin
-//description:
-//creates a small light flash (radius 200, time 0.2) and marks the walls.
-
-//DP_TE_QUADEFFECTS1
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org) te_gunshotquad = #412;
-void(vector org) te_spikequad = #413;
-void(vector org) te_superspikequad = #414;
-void(vector org) te_explosionquad = #415;
-//temp entity definitions:
-//float TE_GUNSHOTQUAD = 57; // [vector] origin
-//float TE_SPIKEQUAD = 58; // [vector] origin
-//float TE_SUPERSPIKEQUAD = 59; // [vector] origin
-//float TE_EXPLOSIONQUAD = 70; // [vector] origin
-//protocol:
-//vector origin
-//description:
-//all of these just take a location, and are equivalent in function (but not appearance :) to the original TE_GUNSHOT, etc.
-
-//DP_TE_SMALLFLASH
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org) te_smallflash = #416;
-//temp entity definitions:
-//float TE_SMALLFLASH = 72;
-//protocol:
-//vector origin
-//description:
-//creates a small light flash (radius 200, time 0.2).
-
-//DP_TE_SPARK
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org, vector vel, float howmany) te_spark = #411;
-//temp entity definitions:
-//float TE_SPARK = 51;
-//protocol:
-//vector origin
-//byte xvelocity (-128 to 127)
-//byte yvelocity (-128 to 127)
-//byte zvelocity (-128 to 127)
-//byte count (number of sparks)
-//description:
-//creates a shower of sparks and a smoke puff.
-
-//DP_TE_STANDARDEFFECTBUILTINS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-void(vector org) te_gunshot = #418;
-void(vector org) te_spike = #419;
-void(vector org) te_superspike = #420;
-void(vector org) te_explosion = #421;
-void(vector org) te_tarexplosion = #422;
-void(vector org) te_wizspike = #423;
-void(vector org) te_knightspike = #424;
-void(vector org) te_lavasplash = #425;
-void(vector org) te_teleport = #426;
-void(vector org, float color, float colorlength) te_explosion2 = #427;
-void(entity own, vector start, vector end) te_lightning1 = #428;
-void(entity own, vector start, vector end) te_lightning2 = #429;
-void(entity own, vector start, vector end) te_lightning3 = #430;
-void(entity own, vector start, vector end) te_beam = #431;
-//description:
-//to make life easier on mod coders.
-
-//DP_TRACE_HITCONTENTSMASK_SURFACEINFO
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//globals:
-.int dphitcontentsmask; // if non-zero on the entity passed to traceline/tracebox/tracetoss this will override the normal collidable contents rules and instead hit these contents values (for example AI can use tracelines that hit DONOTENTER if it wants to, by simply changing this field on the entity passed to traceline), this affects normal movement as well as trace calls
-int trace_dpstartcontents; // DPCONTENTS_ value at start position of trace
-int trace_dphitcontents; // DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit)
-int trace_dphitq3surfaceflags; // Q3SURFACEFLAG_ value of impacted surface
-string trace_dphittexturename; // texture name of impacted surface
-//constants:
-const int DPCONTENTS_SOLID = 1; // hit a bmodel, not a bounding box
-const int DPCONTENTS_WATER = 2;
-const int DPCONTENTS_SLIME = 4;
-const int DPCONTENTS_LAVA = 8;
-const int DPCONTENTS_SKY = 16;
-const int DPCONTENTS_BODY = 32; // hit a bounding box, not a bmodel
-const int DPCONTENTS_CORPSE = 64; // hit a SOLID_CORPSE entity
-const int DPCONTENTS_NODROP = 128; // an area where backpacks should not spawn
-const int DPCONTENTS_PLAYERCLIP = 256; // blocks player movement
-const int DPCONTENTS_MONSTERCLIP = 512; // blocks monster movement
-const int DPCONTENTS_DONOTENTER = 1024; // AI hint brush
-const int DPCONTENTS_LIQUIDSMASK = 14; // WATER | SLIME | LAVA
-const int DPCONTENTS_BOTCLIP = 2048; // AI hint brush
-const int DPCONTENTS_OPAQUE = 4096; // only fully opaque brushes get this (may be useful for line of sight checks)
-const int Q3SURFACEFLAG_NODAMAGE = 1;
-const int Q3SURFACEFLAG_SLICK = 2; // low friction surface
-const int Q3SURFACEFLAG_SKY = 4; // sky surface (also has NOIMPACT and NOMARKS set)
-const int Q3SURFACEFLAG_LADDER = 8; // climbable surface
-const int Q3SURFACEFLAG_NOIMPACT = 16; // projectiles should remove themselves on impact (this is set on sky)
-const int Q3SURFACEFLAG_NOMARKS = 32; // projectiles should not leave marks, such as decals (this is set on sky)
-const int Q3SURFACEFLAG_FLESH = 64; // projectiles should do a fleshy effect (blood?) on impact
-const int Q3SURFACEFLAG_NODRAW = 128; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_HINT = 256; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_SKIP = 512; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_NOLIGHTMAP = 1024; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_POINTLIGHT = 2048; // compiler hint (not important to qc)
-const int Q3SURFACEFLAG_METALSTEPS = 4096; // walking on this surface should make metal step sounds
-const int Q3SURFACEFLAG_NOSTEPS = 8192; // walking on this surface should not make footstep sounds
-const int Q3SURFACEFLAG_NONSOLID = 16384; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_LIGHTFILTER = 32768; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_ALPHASHADOW = 65536; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_NODLIGHT = 131072; // compiler hint (not important to qc)
-//float Q3SURFACEFLAG_DUST = 262144; // translucent 'light beam' effect (not important to qc)
-//description:
-//adds additional information after a traceline/tracebox/tracetoss call.
-//also (very important) sets trace_* globals before calling .touch functions,
-//this allows them to inspect the nature of the collision (for example
-//determining if a projectile hit sky), clears trace_* variables for the other
-//object in a touch event (that is to say, a projectile moving will see the
-//trace results in its .touch function, but the player it hit will see very
-//little information in the trace_ variables as it was not moving at the time)
-
-//DP_VIEWZOOM
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc
-//field definitions:
-.float viewzoom;
-//description:
-//scales fov and sensitivity of player, valid range is 0 to 1 (intended for sniper rifle zooming, and such)
-
-//EXT_BITSHIFT
-//idea: Spike
-//darkplaces implementation: [515]
-//builtin definitions:
-float(float number, float quantity) bitshift = #218;
-//description:
-//multiplies number by a power of 2 corresponding to quantity (0 = *1, 1 = *2, 2 = *4, 3 = *8, -1 = /2, -2 = /4x, etc), and rounds down (due to integer math) like other bit operations do (& and | and the like).
-//note: it is faster to use multiply if you are shifting by a constant, avoiding the quakec function call cost, however that does not do a floor for you.
-
-//FRIK_FILE
-//idea: FrikaC
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-float(string s) stof = #81; // get numerical value from a string
-float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
-void(float fhandle) fclose = #111; // closes a file
-string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
-void(float fhandle, string s, ...) fputs = #113; // writes a line of text to the end of the file
-int(string s) strlen = #114; // returns how many characters are in a string
-string(string s1, string s2, ...) strcat = #115; // concatenates two or more strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
-string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring - see FTE_STRINGS for enhanced version
-vector(string s) stov = #117; // returns vector value from a string
-string(string s, ...) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
-void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
-//constants:
-float FILE_READ = 0;
-float FILE_APPEND = 1;
-float FILE_WRITE = 2;
-//cvars:
-//pr_zone_min_strings : default 64 (64k), min 64 (64k), max 8192 (8mb)
-//description:
-//provides text file access functions and string manipulation functions, note that you may want to set pr_zone_min_strings in the worldspawn function if 64k is not enough string zone space.
-//
-//NOTE: strzone functionality is partially superseded by
-//DP_QC_UNLIMITEDTEMPSTRINGS when longterm storage is not needed
-//NOTE: substring is upgraded by FTE_STRINGS extension with negative start/length handling identical to php 5.2.0
-
-//FTE_CSQC_SKELETONOBJECTS
-//idea: Spike, LordHavoc
-//darkplaces implementation: LordHavoc
-//builtin definitions:
-// all skeleton numbers are 1-based (0 being no skeleton)
-// all bone numbers are 1-based (0 being invalid)
-float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model.
-float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
-float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist
-string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist
-int(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
-int(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity
-vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
-vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
-void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
-void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
-void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
-void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
-void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
-float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found
-float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
-//fields:
-.int skeletonindex; // active skeleton overriding standard animation on model
-.int frame; // primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
-.int frame2; // secondary framegroup animation (strength = lerpfrac)
-.float frame3; // tertiary framegroup animation (strength = lerpfrac3)
-.float frame4; // quaternary framegroup animation (strength = lerpfrac4)
-.float lerpfrac; // strength of framegroup blend
-.float lerpfrac3; // strength of framegroup blend
-.float lerpfrac4; // strength of framegroup blend
-.float frame1time; // start time of framegroup animation
-.float frame2time; // start time of framegroup animation
-.float frame3time; // start time of framegroup animation
-.float frame4time; // start time of framegroup animation
-//description:
-//this extension provides a way to do complex skeletal animation on an entity.
-//
-//see also DP_SKELETONOBJECTS (this extension implemented on server as well as client)
-//
-//notes:
-//each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render).
-//each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files).
-//if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton.
-//proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose.
-//
-//features include:
-//multiple animations blended together.
-//animating a model with animations from another model with a compatible skeleton.
-//restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head.
-//custom bone controllers - for example making eyes track a target location.
-//
-//
-//
-//example code follows...
-//
-//this helper function lets you identify (by parentage) what group a bone
-//belongs to - for example "torso", "leftarm", would return 1 ("torso") for
-//all children of the bone named "torso", unless they are children of
-//"leftarm" (which is a child of "torso") which would return 2 instead...
-float(float skel, float bonenum, string g1, string g2, string g3, string g4, string g5, string g6) example_skel_findbonegroup =
-{
- while (bonenum >= 0)
- {
- string bonename = skel_get_bonename(skel, bonenum);
- if (bonename == g1) return 1;
- if (bonename == g2) return 2;
- if (bonename == g3) return 3;
- if (bonename == g4) return 4;
- if (bonename == g5) return 5;
- if (bonename == g6) return 6;
- bonenum = skel_get_boneparent(skel, bonenum);
- }
- return 0;
-};
-// create a skeletonindex for our player using current modelindex
-void() example_skel_player_setup =
-{
- self.skeletonindex = skel_create(self.modelindex);
-};
-// setup bones of skeleton based on an animation
-// note: animmodelindex can be a different model than self.modelindex
-void(float animmodelindex, float framegroup, float framegroupstarttime) example_skel_player_update_begin =
-{
- // start with our standard animation
- self.frame = framegroup;
- self.frame2 = 0;
- self.frame3 = 0;
- self.frame4 = 0;
- self.frame1time = framegroupstarttime;
- self.frame2time = 0;
- self.frame3time = 0;
- self.frame4time = 0;
- self.lerpfrac = 0;
- self.lerpfrac3 = 0;
- self.lerpfrac4 = 0;
- skel_build(self.skeletonindex, self, animmodelindex, 0, 0, 100000);
-};
-// apply a different framegroup animation to bones with a specified parent
-void(float animmodelindex, float framegroup, float framegroupstarttime, float blendalpha, string groupbonename, string excludegroupname1, string excludegroupname2) example_skel_player_update_applyoverride =
-{
- self.frame = framegroup;
- self.frame2 = 0;
- self.frame3 = 0;
- self.frame4 = 0;
- self.frame1time = framegroupstarttime;
- self.frame2time = 0;
- self.frame3time = 0;
- self.frame4time = 0;
- self.lerpfrac = 0;
- self.lerpfrac3 = 0;
- self.lerpfrac4 = 0;
- float bonenum = 0;
- float numbones = skel_get_numbones(self.skeletonindex);
- while (bonenum < numbones)
- {
- if (example_skel_findbonegroup(self.skeletonindex, bonenum, groupbonename, excludegroupname1, excludegroupname2, "", "", "") == 1)
- skel_build(self.skeletonindex, self, animmodelindex, 1 - blendalpha, bonenum, bonenum + 1);
- bonenum = bonenum + 1;
- }
-};
-// make eyes point at a target location, be sure v_forward, v_right, v_up are set correctly before calling
-void(vector eyetarget, string bonename) example_skel_player_update_eyetarget =
-{
- float bonenum = skel_find_bone(self.skeletonindex, bonename) - 1;
- if (bonenum < 0)
- return;
- vector oldforward = v_forward;
- vector oldright = v_right;
- vector oldup = v_up;
- vector v = eyetarget - self.origin;
- vector modeleyetarget;
- modeleyetarget.x = v * v_forward;
- modeleyetarget.y = 0-v * v_right;
- modeleyetarget.z = v * v_up;
- // this is an eyeball, make it point at the target location
- // first get all the data we can...
- vector relorg = skel_get_bonerel(self.skeletonindex, bonenum);
- vector relforward = v_forward;
- vector relright = v_right;
- vector relup = v_up;
- vector boneorg = skel_get_boneabs(self.skeletonindex, bonenum);
- vector boneforward = v_forward;
- vector boneright = v_right;
- vector boneup = v_up;
- vector parentorg = skel_get_boneabs(self.skeletonindex, skel_get_boneparent(self.skeletonindex, bonenum));
- vector parentforward = v_forward;
- vector parentright = v_right;
- vector parentup = v_up;
- // get the vector from the eyeball to the target
- vector u = modeleyetarget - boneorg;
- // now transform it inversely by the parent matrix to produce new rel vectors
- v.x = u * parentforward;
- v.y = u * parentright;
- v.z = u * parentup;
- vector ang = vectoangles2(v, relup);
- ang.x = 0 - ang.x;
- makevectors(ang);
- // set the relative bone matrix
- skel_set_bone(self.skeletonindex, bonenum, relorg);
- // restore caller's v_ vectors
- v_forward = oldforward;
- v_right = oldright;
- v_up = oldup;
-};
-// delete skeleton when we're done with it
-// note: skeleton remains valid until next frame when it is really deleted
-void() example_skel_player_delete =
-{
- skel_delete(self.skeletonindex);
- self.skeletonindex = 0;
-};
-//
-// END OF EXAMPLES FOR FTE_CSQC_SKELETONOBJECTS
-//
-
-//KRIMZON_SV_PARSECLIENTCOMMAND
-//idea: KrimZon
-//darkplaces implementation: KrimZon, LordHavoc
-//engine-called QC prototypes:
-//void(string s) SV_ParseClientCommand;
-//builtin definitions:
-void(entity e, string s) clientcommand = #440;
-int(string s) tokenize = #441;
-string(float n) argv = #442;
-//description:
-//provides QC the ability to completely control server interpretation of client commands ("say" and "color" for example, clientcommand is necessary for this and substring (FRIK_FILE) is useful) as well as adding new commands (tokenize, argv, and stof (FRIK_FILE) are useful for this)), whenever a clc_stringcmd is received the QC function is called, and it is up to the QC to decide what (if anything) to do with it
-
-//NEH_CMD_PLAY2
-//idea: Nehahra
-//darkplaces implementation: LordHavoc
-//description:
-//shows that the engine supports the "play2" console command (plays a sound without spatialization).
-
-//NEH_RESTOREGAME
-//idea: Nehahra
-//darkplaces implementation: LordHavoc
-//engine-called QC prototypes:
-//void() RestoreGame;
-//description:
-//when a savegame is loaded, this function is called
-
-//NEXUIZ_PLAYERMODEL
-//idea: Nexuiz
-//darkplaces implementation: Black
-//console commands:
-//playermodel <name> - FIXME: EXAMPLE NEEDED
-//playerskin <name> - FIXME: EXAMPLE NEEDED
-//field definitions:
-.string playermodel; // name of player model sent by client
-.string playerskin; // name of player skin sent by client
-//description:
-//these client properties are used by Nexuiz.
-
-//NXQ_GFX_LETTERBOX
-//idea: nxQuake
-//darkplaces implementation: LordHavoc
-//description:
-//shows that the engine supports the "r_letterbox" console variable, set to values in the range 0-100 this restricts the view vertically (and turns off sbar and crosshair), value is a 0-100 percentage of how much to constrict the view, <=0 = normal view height, 25 = 75% of normal view height, 50 = 50%, 75 = 25%, >=100 = no view
-
-//PRYDON_CLIENTCURSOR
-//idea: FrikaC
-//darkplaces implementation: LordHavoc
-//effects bit:
-const int EF_SELECTABLE = 16384; // allows cursor to highlight entity (brighten)
-//field definitions:
-.float cursor_active; // true if cl_prydoncursor mode is on
-.vector cursor_screen; // screen position of cursor as -1 to +1 in _x and _y (_z unused)
-.vector cursor_trace_start; // position of camera
-.vector cursor_trace_endpos; // position of cursor in world (as traced from camera)
-.entity cursor_trace_ent; // entity the cursor is pointing at (server forces this to world if the entity is currently free at time of receipt)
-//cvar definitions:
-//cl_prydoncursor (0/1+, default 0, 1 and above use cursors named gfx/prydoncursor%03i.lmp - or .tga and such if DP_GFX_EXTERNALTEXTURES is implemented)
-//description:
-//shows that the engine supports the cl_prydoncursor cvar, this puts a clientside mouse pointer on the screen and feeds input to the server for the QuakeC to use as it sees fit.
-//the mouse pointer triggers button4 if cursor is at left edge of screen, button5 if at right edge of screen, button6 if at top edge of screen, button7 if at bottom edge of screen.
-//the clientside trace skips transparent entities (except those marked EF_SELECTABLE).
-//the selected entity highlights only if EF_SELECTABLE is set, a typical selection method would be doubling the brightness of the entity by some means (such as colormod[] *= 2).
-//intended to be used by Prydon Gate.
-
-//TENEBRAE_GFX_DLIGHTS
-//idea: Tenebrae
-//darkplaces implementation: LordHavoc
-//fields:
-.float light_lev; // radius (does not affect brightness), typical value 350
-.vector color; // color (does not affect radius), typical value '1 1 1' (bright white), can be up to '255 255 255' (nuclear blast)
-.float style; // light style (like normal light entities, flickering torches or switchable, etc)
-.float pflags; // flags (see PFLAGS_ constants)
-.vector angles; // orientation of the light
-.int skin; // cubemap filter number, can be 1-255 (0 is assumed to be none, and tenebrae only allows 16-255), this selects a projective light filter, a value of 1 loads cubemaps/1posx.tga and cubemaps/1negx.tga and posy, negy, posz, and negz, similar to skybox but some sides need to be rotated or flipped
-//constants:
-float PFLAGS_NOSHADOW = 1; // light does not cast shadows
-float PFLAGS_CORONA = 2; // light has a corona flare
-float PFLAGS_FULLDYNAMIC = 128; // light enable (without this set no light is produced!)
-//description:
-//more powerful dynamic light settings
-//warning: it is best not to use cubemaps on a light entity that has a model, as using a skin number that a model does not have will cause issues in glquake, and produce warnings in darkplaces (use developer 1 to see them)
-//changes compared to tenebrae (because they're too 'leet' for standards):
-//note: networking should send entities with PFLAGS_FULLDYNAMIC set even if they have no model (lights in general do not have a model, nor should they)
-//EF_FULLDYNAMIC effects flag replaced by PFLAGS_FULLDYNAMIC flag (EF_FULLDYNAMIC conflicts with EF_NODRAW)
-
-//TW_SV_STEPCONTROL
-//idea: Transfusion
-//darkplaces implementation: LordHavoc
-//cvars:
-//sv_jumpstep (0/1, default 1)
-//sv_stepheight (default 18)
-//description:
-//sv_jumpstep allows stepping up onto stairs while airborn, sv_stepheight controls how high a single step can be.
-
-//FTE_QC_CHECKPVS
-//idea: Urre
-//darkplaces implementation: divVerent
-//builtin definitions:
-float checkpvs(vector viewpos, entity viewee) = #240;
-//description:
-//returns true if viewee can be seen from viewpos according to PVS data
-
-//FTE_STRINGS
-//idea: many
-//darkplaces implementation: KrimZon
-//builtin definitions:
-int(string str, string sub, float startpos) strstrofs = #221; // returns the offset into a string of the matching text, or -1 if not found, case sensitive
-int(string str, float ofs) str2chr = #222; // returns the character at the specified offset as an integer, or 0 if an invalid index, or byte value - 256 if the engine supports UTF8 and the byte is part of an extended character
-string(int c, ...) chr2str = #223; // returns a string representing the character given, if the engine supports UTF8 this may be a multi-byte sequence (length may be more than 1) for characters over 127.
-string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; // reformat a string with special color characters in the font, DO NOT USE THIS ON UTF8 ENGINES (if you are lucky they will emit ^4 and such color codes instead), the parameter values are 0=same/1=lower/2=upper for ccase, 0=same/1=white/2=red/5=alternate/6=alternate-alternate for redalpha, 0=same/1=white/2=red/3=redspecial/4=whitespecial/5=alternate/6=alternate-alternate for rednum.
-string(float chars, string s, ...) strpad = #225; // pad string with spaces to a specified length, < 0 = left padding, > 0 = right padding
-string(string info, string key, string value, ...) infoadd = #226; // sets or adds a key/value pair to an infostring - note: forbidden characters are \ and "
-string(string info, string key) infoget = #227; // gets a key/value pair in an infostring, returns value or null if not found
-int(string s1, string s2) strcmp = #228; // compare two strings
-int(string s1, string s2, float len) strncmp = #228; // compare two strings up to the specified number of characters, if their length differs and is within the specified limit the result will be negative, otherwise it is the difference in value of their first non-matching character.
-int(string s1, string s2) strcasecmp = #229; // compare two strings with case-insensitive matching, characters a-z are considered equivalent to the matching A-Z character, no other differences, and this does not consider special characters equal even if they look similar
-int(string s1, string s2, float len) strncasecmp = #230; // same as strcasecmp but with a length limit, see strncmp
-//string(string s, float start, float length) substring = #116; // see note below
-//description:
-//various string manipulation functions
-//note: substring also exists in FRIK_FILE but this extension adds negative start and length as valid cases (see note above), substring is consistent with the php 5.2.0 substr function (not 5.2.3 behavior)
-//substring returns a section of a string as a tempstring, if given negative
-// start the start is measured back from the end of the string, if given a
-// negative length the length is the offset back from the end of the string to
-// stop at, rather than being relative to start, if start is negative and
-// larger than length it is treated as 0.
-// examples of substring:
-// substring("blah", -3, 3) returns "lah"
-// substring("blah", 3, 3) returns "h"
-// substring("blah", -10, 3) returns "bla"
-// substring("blah", -10, -3) returns "b"
-
-//DP_CON_BESTWEAPON
-//idea: many
-//darkplaces implementation: divVerent
-//description:
-//allows QC to register weapon properties for use by the bestweapon command, for mods that change required ammo count or type for the weapons
-//it is done using console commands sent via stuffcmd:
-// register_bestweapon quake
-// register_bestweapon clear
-// register_bestweapon <shortname> <impulse> <itemcode> <activeweaponcode> <ammostat> <ammomin>
-//for example, this is what Quake uses:
-// register_bestweapon 1 1 4096 4096 6 0 // STAT_SHELLS is 6
-// register_bestweapon 2 2 1 1 6 1
-// register_bestweapon 3 3 2 2 6 1
-// register_bestweapon 4 4 4 4 7 1 // STAT_NAILS is 7
-// register_bestweapon 5 5 8 8 7 1
-// register_bestweapon 6 6 16 16 8 1 // STAT_ROCKETS is 8
-// register_bestweapon 7 7 32 32 8 1
-// register_bestweapon 8 8 64 64 9 1 // STAT_CELLS is 9
-//after each map client initialization, this is reset back to Quake settings. So you should send these data in ClientConnect.
-//also, this extension introduces a new "cycleweapon" command to the user.
-
-//DP_QC_STRINGBUFFERS
-//idea: ??
-//darkplaces implementation: LordHavoc
-//functions to manage string buffer objects - that is, arbitrary length string arrays that are handled by the engine
-int() buf_create = #460;
-void(float bufhandle) buf_del = #461;
-float(float bufhandle) buf_getsize = #462;
-void(float bufhandle_from, float bufhandle_to) buf_copy = #463;
-void(float bufhandle, float sortpower, float backward) buf_sort = #464;
-string(float bufhandle, string glue) buf_implode = #465;
-string(float bufhandle, float string_index) bufstr_get = #466;
-void(float bufhandle, float string_index, string str) bufstr_set = #467;
-float(float bufhandle, string str, float order) bufstr_add = #468;
-void(float bufhandle, float string_index) bufstr_free = #469;
-
-//DP_QC_STRINGBUFFERS_CVARLIST
-//idea: divVerent
-//darkplaces implementation: divVerent
-//functions to list cvars and store their names into a stringbuffer
-//cvars that start with pattern but not with antipattern will be stored into the buffer
-void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
-
-//DP_QC_STRINGBUFFERS_EXT_WIP
-//idea: VorteX
-//darkplaces implementation: VorteX
-//constant definitions:
-const float MATCH_AUTO = 0;
-const float MATCH_WHOLE = 1;
-const float MATCH_LEFT = 2;
-const float MATCH_RIGHT = 3;
-const float MATCH_MIDDLE = 4;
-const float MATCH_PATTERN = 5;
-//builtin definitions:
-float(string filename, float bufhandle) buf_loadfile = #535; // append each line of file as new buffer string, return 1 if succesful
-float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile = #536; // writes buffer strings as lines, returns 1 if succesful
-float(float bufhandle, string match, float matchrule, float startpos, float step) bufstr_find = #537; // returns string index
-float(string s, string pattern, float matchrule) matchpattern = #538; // returns 0/1
-float(string s, string pattern, float matchrule, float pos) matchpatternofs = #538;
-//description:
-//provides a set of functions to manipulate with string buffers
-//pattern wildcards: * - any character (or no characters), ? - any 1 character
-//Warning: This extension is work-in-progress, it may be changed/revamped/removed at any time, dont use it if you dont want any trouble
-//wip note: UTF8 is not supported yet
-
-//DP_QC_STRREPLACE
-//idea: Sajt
-//darkplaces implementation: Sajt
-//builtin definitions:
-string(string search, string replace, string subject) strreplace = #484;
-string(string search, string replace, string subject) strireplace = #485;
-//description:
-//strreplace replaces all occurrences of 'search' with 'replace' in the string 'subject', and returns the result as a tempstring.
-//strireplace does the same but uses case-insensitive matching of the 'search' term
-
-//DP_SV_SHUTDOWN
-//idea: divVerent
-//darkplaces implementation: divVerent
-//A function that gets called just before progs exit. To save persistent data from.
-//It is not called on a crash or error.
-//void SV_Shutdown();
-
-//EXT_CSQC
-// #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
-void(float index, float type, ...) addstat = #232;
-
-//ZQ_PAUSE
-//idea: ZQuake
-//darkplaces implementation: GreEn`mArine
-//builtin definitions:
-void(float pause) setpause = #531;
-//function definitions:
-//void(float elapsedtime) SV_PausedTic;
-//description:
-//during pause the world is not updated (time does not advance), SV_PausedTic is the only function you can be sure will be called at regular intervals during the pause, elapsedtime is the current system time in seconds since the pause started (not affected by slowmo or anything else).
-//
-//calling setpause(0) will end a pause immediately.
-//
-//Note: it is worth considering that network-related functions may be called during the pause (including customizeentityforclient for example), and it is also important to consider the continued use of the KRIMZON_SV_PARSECLIENTCOMMAND extension while paused (chatting players, etc), players may also join/leave during the pause. In other words, the only things that are not called are think and other time-related functions.
-
-//DP_COVERAGE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//function definitions:
-void coverage() = #642; // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
-
-
-// EXPERIMENTAL (not finalized) EXTENSIONS:
-
-//DP_CRYPTO
-//idea: divVerent
-//darkplaces implementation: divVerent
-//field definitions: (SVQC)
-.string crypto_keyfp; // fingerprint of CA key the player used to authenticate
-.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player
-.string crypto_idfp; // fingerprint of ID used by the player entity, or string_null if not identified
-.float crypto_idfp_signed; // set if the player's ID has been signed
-.string crypto_encryptmethod; // the string "AES128" if encrypting, and string_null if plaintext
-.string crypto_signmethod; // the string "HMAC-SHA256" if signing, and string_null if plaintext
-// there is no field crypto_myidfp, as that info contains no additional information the QC may have a use for
-//builtin definitions: (SVQC)
-float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
-//description:
-//use -1 as buffer handle to justs end delim as postdata
#endif
#pragma noref 1
-///////////////////////////
-// key constants
+//#define float const int
-//
-// these are the key numbers that should be passed to Key_Event
-//
-int K_TAB = 9;
-int K_ENTER = 13;
-int K_ESCAPE = 27;
-int K_SPACE = 32;
+#include "upstream/keycodes.qc"
-// normal keys should be passed as lowercased ascii
-
-int K_BACKSPACE = 127;
-int K_UPARROW = 128;
-int K_DOWNARROW = 129;
-int K_LEFTARROW = 130;
-int K_RIGHTARROW = 131;
-
-int K_ALT = 132;
-int K_CTRL = 133;
-int K_SHIFT = 134;
-
-int K_F1 = 135;
-int K_F2 = 136;
-int K_F3 = 137;
-int K_F4 = 138;
-int K_F5 = 139;
-int K_F6 = 140;
-int K_F7 = 141;
-int K_F8 = 142;
-int K_F9 = 143;
-int K_F10 = 144;
-int K_F11 = 145;
-int K_F12 = 146;
-
-int K_INS = 147;
-int K_DEL = 148;
-int K_PGDN = 149;
-int K_PGUP = 150;
-int K_HOME = 151;
-int K_END = 152;
-
-int K_NUMLOCK = 154;
-int K_CAPSLOCK = 155;
-int K_SCROLLLOCK = 156;
-
-int K_KP_0 = 157;
-int K_KP_INS = 157; // same as K_KP_0
-int K_KP_1 = 158;
-int K_KP_END = 158; // same as K_KP_1
-int K_KP_2 = 159;
-int K_KP_DOWNARROW = 159; // same as K_KP_2
-int K_KP_3 = 160;
-int K_KP_PGDN = 160; // same as K_KP_3
-int K_KP_4 = 161;
-int K_KP_LEFTARROW = 161; // same as K_KP_4
-int K_KP_5 = 162;
-int K_KP_6 = 163;
-int K_KP_RIGHTARROW = 163; // same as K_KP_6
-int K_KP_7 = 164;
-int K_KP_HOME = 164; // same as K_KP_7
-int K_KP_8 = 165;
-int K_KP_UPARROW = 165; // same as K_KP_8
-int K_KP_9 = 166;
-int K_KP_PGUP = 166; // same as K_KP_9
-int K_KP_PERIOD = 167;
-int K_KP_DEL = 167; // same as K_KP_PERIOD
-int K_KP_DIVIDE = 168;
-int K_KP_SLASH = 168; // same as K_KP_DIVIDE
-int K_KP_MULTIPLY = 169;
-int K_KP_MINUS = 170;
-int K_KP_PLUS = 171;
-int K_KP_ENTER = 172;
-int K_KP_EQUALS = 173;
-
-// mouse buttons generate virtual keys
-int K_PAUSE = 153;
-
-//
-// joystick buttons
-//
-int K_JOY1 = 768;
-int K_JOY2 = 769;
-int K_JOY3 = 770;
-int K_JOY4 = 771;
-
-//
-//
-// aux keys are for multi-buttoned joysticks to generate so they can use
-// the normal binding process
-//
-int K_AUX1 = 772;
-int K_AUX2 = 773;
-int K_AUX3 = 774;
-int K_AUX4 = 775;
-int K_AUX5 = 776;
-int K_AUX6 = 777;
-int K_AUX7 = 778;
-int K_AUX8 = 779;
-int K_AUX9 = 780;
-int K_AUX10 = 781;
-int K_AUX11 = 782;
-int K_AUX12 = 783;
-int K_AUX13 = 784;
-int K_AUX14 = 785;
-int K_AUX15 = 786;
-int K_AUX16 = 787;
-int K_AUX17 = 788;
-int K_AUX18 = 789;
-int K_AUX19 = 790;
-int K_AUX20 = 791;
-int K_AUX21 = 792;
-int K_AUX22 = 793;
-int K_AUX23 = 794;
-int K_AUX24 = 795;
-int K_AUX25 = 796;
-int K_AUX26 = 797;
-int K_AUX27 = 798;
-int K_AUX28 = 799;
-int K_AUX29 = 800;
-int K_AUX30 = 801;
-int K_AUX31 = 802;
-int K_AUX32 = 803;
-
-//
-// mouse buttons generate virtual keys
-//
-int K_MOUSE1 = 512;
-int K_MOUSE2 = 513;
-int K_MOUSE3 = 514;
-int K_MWHEELUP = 515;
-int K_MWHEELDOWN = 516;
-int K_MOUSE4 = 517;
-int K_MOUSE5 = 518;
-int K_MOUSE6 = 519;
-int K_MOUSE7 = 520;
-int K_MOUSE8 = 521;
-int K_MOUSE9 = 522;
-int K_MOUSE10 = 523;
-int K_MOUSE11 = 524;
-int K_MOUSE12 = 525;
-int K_MOUSE13 = 526;
-int K_MOUSE14 = 527;
-int K_MOUSE15 = 528;
-int K_MOUSE16 = 529;
+//#undef float
#pragma noref 0
#pragma noref 1
-//////////////////////////////////////////////////////////
-// sys globals
-
-entity self;
-
-/////////////////////////////////////////////////////////
-void end_sys_globals;
-/////////////////////////////////////////////////////////
-// sys fields
-
-/////////////////////////////////////////////////////////
-void end_sys_fields;
-/////////////////////////////////////////////////////////
-// sys functions
-
-void() m_init;
-void(float keynr, float ascii) m_keydown;
-void(float width, float height) m_draw;
-void(float mode) m_toggle;
-void() m_shutdown;
-// optional: float(float) m_gethostcachecategory;
-
-/////////////////////////////////////////////////////////
-// sys constants
-///////////////////////////
-// key dest constants
-
-float KEY_UNKNOWN = -1;
-float KEY_GAME = 0;
-float KEY_MENU = 2;
-float KEY_MENU_GRABBED = 3;
-
-///////////////////////////
-// file constants
-
-float FILE_READ = 0;
-float FILE_APPEND = 1;
-float FILE_WRITE = 2;
-
-///////////////////////////
-// msg constants
-
-float MSG_BROADCAST = 0; // unreliable to all
-float MSG_ONE = 1; // reliable to one (msg_entity)
-float MSG_ALL = 2; // reliable to all
-float MSG_INIT = 3; // write to the init string
-
-/////////////////////////////
-// mouse target constants
-
-float MT_MENU = 1;
-float MT_CLIENT = 2;
-
-/////////////////////////
-// client state constants
-
-float CS_DEDICATED = 0;
-float CS_DISCONNECTED = 1;
-float CS_CONNECTED = 2;
-
-///////////////////////////
-// blend flags
-
-float DRAWFLAG_NORMAL = 0;
-float DRAWFLAG_ADDITIVE = 1;
-float DRAWFLAG_MODULATE = 2;
-float DRAWFLAG_2XMODULATE = 3;
-
-///////////////////////////
-// null entity (actually it is the same like the world entity)
-
-entity null_entity;
-
-///////////////////////////
-// error constants
-
-// file handling
-float ERR_CANNOTOPEN = -1; // fopen
-float ERR_NOTENOUGHFILEHANDLES = -2; // fopen
-float ERR_INVALIDMODE = -3; // fopen
-float ERR_BADFILENAME = -4; // fopen
-
-// drawing functions
-
-float ERR_NULLSTRING = -1;
-float ERR_BADDRAWFLAG = -2;
-float ERR_BADSCALE = -3;
-float ERR_BADSIZE = -3; // same as ERR_BADSCALE
-float ERR_NOTCACHED = -4;
-
-// server list stuff
-float SLIST_HOSTCACHEVIEWCOUNT = 0;
-float SLIST_HOSTCACHETOTALCOUNT = 1;
-float SLIST_MASTERQUERYCOUNT = 2;
-float SLIST_MASTERREPLYCOUNT = 3;
-float SLIST_SERVERQUERYCOUNT = 4;
-float SLIST_SERVERREPLYCOUNT = 5;
-float SLIST_SORTFIELD = 6;
-float SLIST_SORTDESCENDING = 7;
-float SLIST_LEGACY_LINE1 = 1024;
-float SLIST_LEGACY_LINE2 = 1025;
-float SLIST_TEST_CONTAINS = 0;
-float SLIST_TEST_NOTCONTAIN = 1;
-float SLIST_TEST_LESSEQUAL = 2;
-float SLIST_TEST_LESS = 3;
-float SLIST_TEST_EQUAL = 4;
-float SLIST_TEST_GREATER = 5;
-float SLIST_TEST_GREATEREQUAL = 6;
-float SLIST_TEST_NOTEQUAL = 7;
-float SLIST_TEST_STARTSWITH = 8;
-float SLIST_TEST_NOTSTARTSWITH = 9;
-float SLIST_MASK_AND = 0;
-float SLIST_MASK_OR = 512;
-
-// font stuff
-float FONT_DEFAULT = 0;
-float FONT_CONSOLE = 1;
-float FONT_SBAR = 2;
-float FONT_NOTIFY = 3;
-float FONT_CHAT = 4;
-float FONT_CENTERPRINT = 5;
-float FONT_INFOBAR = 6;
-float FONT_MENU = 7;
-float FONT_USER = 8; // add to this the index, like FONT_USER+3 = user3. At least 8 of them are supported.
-float drawfont;
-
-/* not supported at the moment
-///////////////////////////
-// os constants
-
-float OS_WINDOWS = 0;
-float OS_LINUX = 1;
-float OS_MAC = 2;
-*/
-
-
-
-
-
-
-
-
-
-
-//////////////////////////////////////////////////
-// common cmd
-//////////////////////////////////////////////////
-// AK FIXME: Create perhaps a special builtin file for the common cmds
-
-void checkextension(string ext) = #1;
-
-// error cmds
-void error(string err,...) = #2;
-void objerror(string err,...) = #3;
-
-// print
-
-void print(string text,...) = #4;
-void bprint(string text,...) = #5;
-void sprint(float clientnum, string text,...) = #6;
-void centerprint(string text,...) = #7;
-
-// vector stuff
-
-vector normalize(vector v) = #8;
-float vlen(vector v) = #9;
-float vectoyaw(vector v) = #10;
-vector vectoangles(vector v) = #11;
-
-float random(void) = #12;
-
-void cmd(string command, ...) = #13;
-
-// cvar cmds
-
-float cvar(string name) = #14;
-const string str_cvar(string name) = #71;
-void cvar_set(string name, string value) = #15;
-
-void dprint(string text,...) = #16;
-
-// conversion functions
-
-string ftos(float f) = #17;
-float fabs(float f) = #18;
-string vtos(vector v) = #19;
-string etos(entity e) = #20;
-
-float stof(string val,...) = #21;
-
-entity spawn(void) = #22;
-void remove(entity e) = #23;
-
-entity find(entity start, .string field, string match) = #24;
-entity findfloat(entity start, .float field, float match) = #25;
-entity findentity(entity start, .entity field, entity match) = #25;
-
-entity findchainstring(.string field, string match) = #26;
-entity findchainfloat(.float field, float match) = #27;
-entity findchainentity(.entity field, entity match) = #27;
-
-string precache_file(string file) = #28;
-string precache_sound(string sample) = #29;
-
-void crash(void) = #72;
-void coredump(void) = #30;
-void stackdump(void) = #73;
-void traceon(void) = #31;
-void traceoff(void) = #32;
-
-void eprint(entity e) = #33;
-float rint(float f) = #34;
-float floor(float f) = #35;
-float ceil(float f) = #36;
-entity nextent(entity e) = #37;
-float sin(float f) = #38;
-float cos(float f) = #39;
-float sqrt(float f) = #40;
-vector randomvec(void) = #41;
-
-float registercvar(string name, string value, float flags) = #42; // returns 1 if success
-
-float min(float f,...) = #43;
-float max(float f,...) = #44;
-
-float bound(float min,float value, float max) = #45;
-float pow(float a, float b) = #46;
-
-void copyentity(entity src, entity dst) = #47;
-
-float fopen(string filename, float mode) = #48;
-void fclose(float fhandle) = #49;
-string fgets(float fhandle) = #50;
-void fputs(float fhandle, string s) = #51;
-
-float strlen(string s) = #52;
-string strcat(string s1,string s2,...) = #53;
-string substring(string s, float start, float length) = #54;
-
-vector stov(string s) = #55;
-
-string strzone(string s) = #56;
-void strunzone(string s) = #57;
-
-float tokenize(string s) = #58;
-string argv(float n) = #59;
-
-float isserver(void) = #60;
-float clientcount(void) = #61;
-float clientstate(void) = #62;
-void clientcommand(float client, string s) = #63;
-void changelevel(string map) = #64;
-void localsound(string sample) = #65;
-vector getmousepos(void) = #66;
-float gettime(void) = #67;
-void loadfromdata(string data) = #68;
-void loadfromfile(string file) = #69;
-
-float mod(float val, float m) = #70;
-
-float search_begin(string pattern, float caseinsensitive, float quiet) = #74;
-void search_end(float handle) = #75;
-float search_getsize(float handle) = #76;
-string search_getfilename(float handle, float num) = #77;
-
-string chr(float ascii) = #78;
-
-/////////////////////////////////////////////////
-// Write* Functions
-/////////////////////////////////////////////////
-void WriteByte(float data, float dest, float desto) = #401;
-void WriteChar(float data, float dest, float desto) = #402;
-void WriteShort(float data, float dest, float desto) = #403;
-void WriteLong(float data, float dest, float desto) = #404;
-void WriteAngle(float data, float dest, float desto) = #405;
-void WriteCoord(float data, float dest, float desto) = #406;
-void WriteString(string data, float dest, float desto)= #407;
-void WriteEntity(entity data, float dest, float desto) = #408;
-
-//////////////////////////////////////////////////
-// Draw funtions
-//////////////////////////////////////////////////
-
-float iscachedpic(string name) = #451;
-string precache_pic(string name, ...) = #452;
-void freepic(string name) = #453;
-
-float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454;
-
-float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455;
-
-float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) = #467;
-
-vector drawcolorcodedstring2(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #467;
-
-float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456;
-
-float drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457;
-
-void drawsetcliparea(float x, float y, float width, float height) = #458;
-
-void drawresetcliparea(void) = #459;
-
-vector drawgetimagesize(string pic) = #460;
-
-////////////////////////////////////////////////
-// Menu functions
-////////////////////////////////////////////////
-
-void setkeydest(float dest) = #601;
-float getkeydest(void) = #602;
-
-void setmousetarget(float trg) = #603;
-float getmousetarget(void) = #604;
-
-float isfunction(string function_name) = #607;
-void callfunction(...) = #605;
-void writetofile(float fhandle, entity ent) = #606;
-vector getresolution(float number) = #608;
-string keynumtostring(float keynum) = #609;
-
-float gethostcachevalue(float type) = #611;
-string gethostcachestring(float type, float hostnr) = #612;
-
-//DP_CSQC_BINDMAPS
-//idea: daemon, motorsep
-//darkplaces implementation: divVerent
-//builtin definitions:
-string(float key, float bindmap) getkeybind_bindmap = #342;
-float(float key, string bind, float bindmap) setkeybind_bindmap = #630;
-vector(void) getbindmaps = #631;
-float(vector bm) setbindmaps = #632;
-string(string command, float bindmap) findkeysforcommand = #610;
-float(string key) stringtokeynum = #341;
-//<also allowed builtin number to match EXT_CSQC> string(float keynum) keynumtostring = #340;
-//description: key bind setting/getting including support for switchable
-//bindmaps.
-
-//DP_CRYPTO
-//idea: divVerent
-//darkplaces implementation: divVerent
-//field definitions: (MENUQC)
-string(string serveraddress) crypto_getkeyfp = #633; // retrieves the cached host key's CA fingerprint of a server given by IP address
-string(string serveraddress) crypto_getidfp = #634; // retrieves the cached host key fingerprint of a server given by IP address
-float(string serveraddress) crypto_getidstatus = #643; // retrieves the cached host key's key status. See below for CRYPTO_IDSTATUS_ defines.
-string(string serveraddress) crypto_getencryptlevel = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each
-string(float i) crypto_getmykeyfp = #636; // retrieves the CA key fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
-string(float i) crypto_getmyidfp = #637; // retrieves the ID fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
-float CRYPTO_IDSTATUS_OUTOFRANGE = -1;
-float CRYPTO_IDSTATUS_EMPTY = 0;
-float CRYPTO_IDSTATUS_UNSIGNED = 1;
-float CRYPTO_IDSTATUS_SIGNED = 2;
-float(float i) crypto_getmyidstatus = #641; // retrieves the ID's status of a given CA slot, or 0 if slot is unused but more to come, or -1 if end of list
-float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
-//description:
-//use -1 as buffer handle to justs end delim as postdata
-
-//DP_GECKO_SUPPORT
-//idea: Res2k, BlackHC
-//darkplaces implementation: Res2k, BlackHC
-//constant definitions:
-float GECKO_BUTTON_DOWN = 0;
-float GECKO_BUTTON_UP = 1;
-// either use down and up or just press but not all of them!
-float GECKO_BUTTON_PRESS = 2;
-// use this for mouse events if needed?
-float GECKO_BUTTON_DOUBLECLICK = 3;
-//builtin definitions:
-float gecko_create( string name ) = #487;
-void gecko_destroy( string name ) = #488;
-void gecko_navigate( string name, string URI ) = #489;
-float gecko_keyevent( string name, float key, float eventtype ) = #490;
-void gecko_mousemove( string name, float x, float y ) = #491;
-void gecko_resize( string name, float w, float h ) = #492;
-vector gecko_get_texture_extent( string name ) = #493;
-//engine-called QC prototypes:
-//string(string name, string query) Qecko_Query;
-//description:
-//provides an interface to the offscreengecko library and allows for internet browsing in games
-
-//FTE_STRINGS
-//idea: many
-//darkplaces implementation: KrimZon
-//description:
-//various string manipulation functions
-int(string str, string sub, float startpos) strstrofs = #221;
-int(string str, float ofs) str2chr = #222;
-string(int c, ...) chr2str = #223;
-string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
-string(float chars, string s, ...) strpad = #225;
-string(string info, string key, string value, ...) infoadd = #226;
-string(string info, string key) infoget = #227;
-int(string s1, string s2) strcmp = #228;
-int(string s1, string s2, float len) strncmp = #228;
-int(string s1, string s2) strcasecmp = #229;
-int(string s1, string s2, float len) strncasecmp = #230;
-
-//DP_PRECACHE_PIC_FLAGS
-//idea: divVerent
-//darkplaces implementation: divVerent
-//constant definitions:
-float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC
-float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused
-float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense
-//notes: these constants are given as optional second argument to precache_pic()
-
-//DP_QC_CRC16
-//idea: div0
-//darkplaces implementation: div0
-//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
-//When caseinsensitive is set, the CRC is calculated of the lower cased string.
-float(float caseinsensitive, string s, ...) crc16 = #494;
-
-//DP_QC_CVAR_TYPE
-float(string name) cvar_type = #495;
-float CVAR_TYPEFLAG_EXISTS = 1;
-float CVAR_TYPEFLAG_SAVED = 2;
-float CVAR_TYPEFLAG_PRIVATE = 4;
-float CVAR_TYPEFLAG_ENGINE = 8;
-float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
-float CVAR_TYPEFLAG_READONLY = 32;
-
-//DP_QC_STRINGBUFFERS
-//idea: ??
-//darkplaces implementation: LordHavoc
-//functions to manage string buffer objects - that is, arbitrary length string arrays that are handled by the engine
-int() buf_create = #440;
-void(float bufhandle) buf_del = #441;
-float(float bufhandle) buf_getsize = #442;
-void(float bufhandle_from, float bufhandle_to) buf_copy = #443;
-void(float bufhandle, float sortpower, float backward) buf_sort = #444;
-string(float bufhandle, string glue) buf_implode = #445;
-string(float bufhandle, float string_index) bufstr_get = #446;
-void(float bufhandle, float string_index, string str) bufstr_set = #447;
-float(float bufhandle, string str, float order) bufstr_add = #448;
-void(float bufhandle, float string_index) bufstr_free = #449;
-void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
-
-//DP_QC_STRING_CASE_FUNCTIONS
-//idea: Dresk
-//darkplaces implementation: LordHavoc / Dresk
-//builtin definitions:
-string(string s) strtolower = #480; // returns the passed in string in pure lowercase form
-string(string s) strtoupper = #481; // returns the passed in string in pure uppercase form
-//description:
-//provides simple string uppercase and lowercase functions
-
-//DP_QC_CVAR_DESCRIPTION
-//idea: divVerent
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-string(string name) cvar_description = #518;
-//description:
-//returns the description of a cvar
-
-//DP_QC_DIGEST
-//idea: motorsep, Spike
-//DarkPlaces implementation: divVerent
-//builtin definitions:
-string(string digest, string data, ...) digest_hex = #639;
-//description:
-//returns a given hex digest of given data
-//the returned digest is always encoded in hexadecimal
-//only the "MD4" digest is always supported!
-//if the given digest is not supported, string_null is returned
-//the digest string is matched case sensitively, use "MD4", not "md4"!
-
-//DP_QC_URI_ESCAPE
-//idea: div0
-//darkplaces implementation: div0
-//URI::Escape's functionality
-string(string in) uri_escape = #510;
-string(string in) uri_unescape = #511;
-
-//DP_QC_URI_GET
-//idea: divVerent
-//darkplaces implementation: divVerent
-//loads text from an URL into a string
-//returns 1 on success of initiation, 0 if there are too many concurrent
-//connections already or if the URL is invalid
-//the following callback will receive the data and MUST exist!
-// void(float id, float status, string data) URI_Get_Callback;
-//status is either
-// negative for an internal error,
-// 0 for success, or
-// the HTTP response code on server error (e.g. 404)
-//if 1 is returned by uri_get, the callback will be called in the future
-float(string url, float id) uri_get = #513;
-//DP_QC_URI_POST
-//idea: divVerent
-//darkplaces implementation: divVerent
-//loads text from an URL into a string after POSTing via HTTP
-//works like uri_get, but uri_post sends data with Content-Type: content_type to the server
-//and uri_post sends the string buffer buf, joined using the delimiter delim
-float(string url, float id, string content_type, string data) uri_post = #513;
-float(string url, float id, string content_type, string delim, float buf) uri_postbuf = #513;
-
-//DP_QC_ENTITYDATA
-//idea: KrimZon
-//darkplaces implementation: KrimZon
-//builtin definitions:
-float() numentityfields = #496;
-string(float fieldnum) entityfieldname = #497;
-float(float fieldnum) entityfieldtype = #498;
-string(float fieldnum, entity ent) getentityfieldstring = #499;
-float(float fieldnum, entity ent, string s) putentityfieldstring = #500;
-//constants:
-//Returned by entityfieldtype
-float FIELD_STRING = 1;
-float FIELD_FLOAT = 2;
-float FIELD_VECTOR = 3;
-float FIELD_ENTITY = 4;
-float FIELD_FUNCTION = 6;
-//description:
-//Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame.
-//WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers.
-//numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z.
-//entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever.
-//entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers.
-//getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
-//putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
-
-//DP_COVERAGE
-//idea: divVerent
-//darkplaces implementation: divVerent
-//function definitions:
-void coverage() = #642; // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
-
-// assorted undocumented extensions
-string(string, float) netaddress_resolve = #625;
-string(string search, string replace, string subject) strreplace = #484;
-string(float uselocaltime, string format, ...) strftime = #478;
-float(string s) tokenize_console = #514;
-float(float i) argv_start_index = #515;
-float(float i) argv_end_index = #516;
-string(float, float) getgamedirinfo = #626;
-const float GETGAMEDIRINFO_NAME = 0;
-const float GETGAMEDIRINFO_DESCRIPTION = 1;
-float log(float f) = #532;
-string(string format, ...) sprintf = #627;
-string(string s) strdecolorize = #477;
-entity findflags(entity start, .float field, float match) = #87;
-entity findchainflags(.float field, float match) = #88;
-float(string s, string separator1, ...) tokenizebyseparator = #479;
-float etof(entity ent) = #79;
-entity ftoe(float num) = #80;
-float validstring(string str) = #81;
-float altstr_count(string str) = #82;
-string altstr_prepare(string str) = #83;
-string altstr_get(string str, float num) = #84;
-string altstr_set(string str, float num, string set) = #85;
-string altstr_ins(string str, float num, string set) = #86;
-float isdemo() = #349;
-float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #469;
-//vector getresolution(float number, ...) = #608; // optional argument "isfullscreen"
-void parseentitydata(entity ent, string data) = #613;
-void resethostcachemasks(void) = #615;
-void sethostcachemaskstring(float mask, float fld, string str, float op) = #616;
-void sethostcachemasknumber(float mask, float fld, float num, float op) = #617;
-void resorthostcache(void) = #618;
-float SLSF_DESCENDING = 1;
-float SLSF_FAVORITES = 2;
-float SLSF_CATEGORIES = 4;
-void sethostcachesort(float fld, float slsf) = #619;
-void refreshhostcache(...) = #620; // optional boolean argument "clear_list"
-float gethostcachenumber(float fld, float hostnr) = #621;
-float gethostcacheindexforkey(string key) = #622;
-void addwantedhostcachekey(string key) = #623;
-string getextresponse(void) = #624;
-const string cvar_string(string name) = #71;
-const string cvar_defstring(string name) = #89;
-float stringwidth(string text, float handleColors, vector size) = #468;
+#define true _true
+#define false _false
+#define TRUE _TRUE
+#define FALSE _FALSE
+
+#include "upstream/menudefs.qc"
+
+#undef true
+#undef false
+#undef TRUE
+#undef FALSE
+
+int(string str, string sub, int startpos) _strstrofs = #221;
+#define strstrofs _strstrofs
+int(string str, int ofs) _str2chr = #222;
+#define str2chr _str2chr
+string(int c, ...) _chr2str = #223;
+#define chr2str _chr2str
+
+int(string s1, string s2) _strcmp = #228;
+#define strcmp _strcmp
+int(string s1, string s2, int len) _strncmp = #228;
+#define strncmp _strncmp
+int(string s1, string s2) _strcasecmp = #229;
+#define strcasecmp _strcasecmp
+int(string s1, string s2, int len) _strncasecmp = #230;
+#define strncasecmp _strncasecmp
+
+int() _buf_create = #440;
+#define buf_create _buf_create
#pragma noref 0
#ifndef PROGSDEFS_H
#define PROGSDEFS_H
-/*
-==============================================================================
+#pragma noref 1
- SOURCE FOR GLOBALVARS_T C STRUCTURE
- MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+#define true _true
+#define false _false
+#define TRUE _TRUE
+#define FALSE _FALSE
-==============================================================================
-*/
+#include "upstream/progsdefs.qc"
-//
-// system globals
-//
-entity self;
-entity other;
-entity world;
-float time;
-float frametime;
+#undef true
+#undef false
+#undef TRUE
+#undef FALSE
-float force_retouch; // force all entities to touch triggers
- // next frame. this is needed because
- // non-moving things don't normally scan
- // for triggers, and when a trigger is
- // created (like a teleport trigger), it
- // needs to catch everything.
- // decremented each frame, so set to 2
- // to guarantee everything is touched
-string mapname;
+#pragma noref 0
-float deathmatch;
-float coop;
-float teamplay;
-
-int serverflags; // propagated from level to level, used to
- // keep track of completed episodes
-
-float total_secrets;
-float total_monsters;
-
-float found_secrets; // number of secrets found
-float killed_monsters; // number of monsters killed
-
-
-// spawnparms are used to encode information about clients across server
-// level changes
-float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
-
-//
-// global variables set by built in functions
-//
-vector v_forward, v_up, v_right; // set by makevectors()
-
-// set by traceline / tracebox
-float trace_allsolid;
-float trace_startsolid;
-float trace_fraction;
-vector trace_endpos;
-vector trace_plane_normal;
-float trace_plane_dist;
-entity trace_ent;
-float trace_inopen;
-float trace_inwater;
-
-entity msg_entity; // destination of single entity writes
-
-//
-// required prog functions
-//
-void() main; // only for testing
-
-void() StartFrame;
-
-void() PlayerPreThink;
-void() PlayerPostThink;
-
-void() ClientKill;
-#ifdef DP_EXT_PRECONNECT
-void() ClientPreConnect;
-#endif
-void() ClientConnect;
-void() PutClientInServer; // call after setting the parm1... parms
-void() ClientDisconnect;
-
-void() SetNewParms; // called when a client first connects to
- // a server. sets parms so they can be
- // saved off for restarts
-
-void() SetChangeParms; // call to set parms for self so they can
- // be saved for a level transition
-
-
-//================================================
-void end_sys_globals; // flag for structure dumping
-//================================================
-
-/*
-==============================================================================
-
- SOURCE FOR ENTVARS_T C STRUCTURE
- MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
-
-==============================================================================
-*/
-
-//
-// system fields (*** = do not set in prog code, maintained by C code)
-//
-.int modelindex; // *** model index in the precached list
-.vector absmin, absmax; // *** origin + mins / maxs
-
-.float ltime; // local time for entity
-.float movetype;
-.float solid;
-
-.vector origin; // ***
-.vector oldorigin; // ***
-.vector velocity;
-.vector angles;
-.vector avelocity;
-
-.vector punchangle; // temp angle adjust from damage or recoil
-
-.string classname; // spawn function
-.string model;
-.int frame;
-.int skin;
-.int effects;
-
-.vector mins, maxs; // bounding box extents reletive to origin
-.vector size; // maxs - mins
-
-.void() touch;
-.void() use;
-.void() think;
-.void() blocked; // for doors or plats, called when can't push other
-
-.float nextthink;
-.entity groundentity;
-
-// stats
-.float health;
-.float frags;
-.int weapon; // one of the IT_SHOTGUN, etc flags
-.string weaponmodel;
-.float weaponframe;
-.float currentammo;
-.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
-
-.int items; // bit flags
-
-.float takedamage;
-.entity chain;
-.float deadflag;
-
-.vector view_ofs; // add to origin to get eye point
-
-
-.float button0; // fire
-.float button1; // use
-.float button2; // jump
-
-.float impulse; // weapon changes
-
-.float fixangle;
-.vector v_angle; // view / targeting angle for players
-.float idealpitch; // calculated pitch angle for lookup up slopes
-
-
-.string netname;
-
-.entity enemy;
-
-.int flags;
-
-.int colormap;
-.float team;
-
-.float max_health; // players maximum health is stored here
-
-.float teleport_time; // don't back up
-
-.float armortype; // save this fraction of incoming damage
-.float armorvalue;
-
-.float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes
-.float watertype; // a contents value
-
-.float ideal_yaw;
-.float yaw_speed;
-
-.entity aiment;
-
-.entity goalentity; // a movetarget or an enemy
-
-.int spawnflags;
-
-.string target;
-.string targetname;
-
-// damage is accumulated through a frame. and sent as one single
-// message, so the super shotgun doesn't generate huge messages
-.float dmg_take;
-.float dmg_save;
-.entity dmg_inflictor;
-
-.entity owner; // who launched a missile
-.vector movedir; // mostly for doors, but also used for waterjump
-
-.string message; // trigger messages
-
-.float sounds; // either a cd track number or sound number
-
-.string noise, noise1, noise2, noise3; // contains names of wavs to play
-
-//================================================
-void end_sys_fields; // flag for structure dumping
-//================================================
-
-/*
-==============================================================================
-
- CONSTANT DEFINITIONS
-
-==============================================================================
-*/
-
-
-//
-// constants
-//
-
-// edict.flags
-const int FL_FLY = 1;
-const int FL_SWIM = 2;
-const int FL_CLIENT = 8; // set for all client edicts
-const int FL_INWATER = 16; // for enter / leave water splash
-const int FL_MONSTER = 32;
-const int FL_GODMODE = 64; // player cheat
-const int FL_NOTARGET = 128; // player cheat
-const int FL_ITEM = 256; // extra wide size for bonus items
-const int FL_ONGROUND = 512; // standing on something
-const int FL_PARTIALGROUND = 1024; // not all corners are valid
-const int FL_WATERJUMP = 2048; // player jumping out of water
-const int FL_JUMPRELEASED = 4096; // for jump debouncing
-
-// edict.movetype values
-const int MOVETYPE_NONE = 0; // never moves
-//const int MOVETYPE_ANGLENOCLIP= 1;
-//const int MOVETYPE_ANGLECLIP = 2;
-const int MOVETYPE_WALK = 3; // players only
-const int MOVETYPE_STEP = 4; // discrete, not real time unless fall
-const int MOVETYPE_FLY = 5;
-const int MOVETYPE_TOSS = 6; // gravity
-const int MOVETYPE_PUSH = 7; // no clip to world, push and crush
-const int MOVETYPE_NOCLIP = 8;
-const int MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters
-const int MOVETYPE_BOUNCE = 10;
-const int MOVETYPE_BOUNCEMISSILE= 11; // bounce with extra size
-
-// edict.solid values
-const int SOLID_NOT = 0; // no interaction with other objects
-const int SOLID_TRIGGER = 1; // touch on edge, but not blocking
-const int SOLID_BBOX = 2; // touch on edge, block
-const int SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
-const int SOLID_BSP = 4; // bsp clip, touch on edge, block
-
-// range values
-const int RANGE_MELEE = 0;
-const int RANGE_NEAR = 1;
-const int RANGE_MID = 2;
-const int RANGE_FAR = 3;
-
-// deadflag values
-
-const int DEAD_NO = 0;
-const int DEAD_DYING = 1;
-const int DEAD_DEAD = 2;
-const int DEAD_RESPAWNABLE = 3;
-const int DEAD_RESPAWNING = 4; // dead, waiting for buttons to be released
-
-// takedamage values
-
-const int DAMAGE_NO = 0;
-const int DAMAGE_YES = 1;
-const int DAMAGE_AIM = 2;
-
-// items
-const int IT_AXE = 4096;
-const int IT_SHOTGUN = 1;
-const int IT_SUPER_SHOTGUN = 2;
-const int IT_NAILGUN = 4;
-const int IT_SUPER_NAILGUN = 8;
-const int IT_GRENADE_LAUNCHER = 16;
-const int IT_ROCKET_LAUNCHER = 32;
-const int IT_LIGHTNING = 64;
-const int IT_EXTRA_WEAPON = 128;
-
-//const int IT_SHELLS = 256;
-//const int IT_NAILS = 512;
-//const int IT_ROCKETS = 1024;
-//const int IT_CELLS = 2048;
-
-const int IT_ARMOR1 = 8192;
-const int IT_ARMOR2 = 16384;
-const int IT_ARMOR3 = 32768;
-const int IT_SUPERHEALTH = 65536;
-
-//const int IT_KEY1 = 131072;
-//const int IT_KEY2 = 262144;
-
-const int IT_INVISIBILITY = 524288;
-const int IT_INVULNERABILITY = 1048576;
-const int IT_SUIT = 2097152;
-const int IT_QUAD = 4194304;
-
-// point content values
-
-const int CONTENT_EMPTY = -1;
-const int CONTENT_SOLID = -2;
-const int CONTENT_WATER = -3;
-const int CONTENT_SLIME = -4;
-const int CONTENT_LAVA = -5;
-const int CONTENT_SKY = -6;
-
-const int STATE_TOP = 0;
-const int STATE_BOTTOM = 1;
-const int STATE_UP = 2;
-const int STATE_DOWN = 3;
-
-const vector VEC_ORIGIN = '0 0 0';
-const vector VEC_HULL_MIN = '-16 -16 -24';
-const vector VEC_HULL_MAX = '16 16 32';
-
-const vector VEC_HULL2_MIN = '-32 -32 -24';
-const vector VEC_HULL2_MAX = '32 32 64';
-
-// protocol bytes
-const int SVC_TEMPENTITY = 23;
-const int SVC_KILLEDMONSTER = 27;
-const int SVC_FOUNDSECRET = 28;
-const int SVC_INTERMISSION = 30;
-const int SVC_FINALE = 31;
-const int SVC_CDTRACK = 32;
-const int SVC_SELLSCREEN = 33;
-
-
-const int TE_SPIKE = 0;
-const int TE_SUPERSPIKE = 1;
-const int TE_GUNSHOT = 2;
-const int TE_EXPLOSION = 3;
-const int TE_TAREXPLOSION = 4;
-const int TE_LIGHTNING1 = 5;
-const int TE_LIGHTNING2 = 6;
-const int TE_WIZSPIKE = 7;
-const int TE_KNIGHTSPIKE = 8;
-const int TE_LIGHTNING3 = 9;
-const int TE_LAVASPLASH = 10;
-const int TE_TELEPORT = 11;
-
-// sound channels
-// channel 0 never willingly overrides
-// other channels (1-7) allways override a playing sound on that channel
-const int CHAN_AUTO = 0;
-const int CHAN_WEAPON = 1;
-const int CHAN_VOICE = 2;
-const int CHAN_ITEM = 3;
-const int CHAN_BODY = 4;
-
-const int ATTN_NONE = 0;
-const int ATTN_NORM = 1;
-const int ATTN_IDLE = 2;
-const int ATTN_STATIC = 3;
-
-// update types
-
-const int UPDATE_GENERAL = 0;
-const int UPDATE_STATIC = 1;
-const int UPDATE_BINARY = 2;
-const int UPDATE_TEMP = 3;
-
-// entity effects
-
-const int EF_BRIGHTFIELD = 1;
-const int EF_MUZZLEFLASH = 2;
-const int EF_BRIGHTLIGHT = 4;
-const int EF_DIMLIGHT = 8;
-
-
-// messages
-const int MSG_BROADCAST = 0; // unreliable to all
-const int MSG_ONE = 1; // reliable to one (msg_entity)
-const int MSG_ALL = 2; // reliable to all
-const int MSG_INIT = 3; // write to the init string
-
-//===========================================================================
-
-//
-// builtin functions
-//
-
-void(vector ang) makevectors = #1; // sets v_forward, etc globals
-void(entity e, vector o) setorigin = #2;
-void(entity e, string m) setmodel = #3; // set movetype and solid first
-void(entity e, vector min, vector max) setsize = #4;
-// #5 was removed
-void() break_to_debugger = #6;
-float() random = #7; // returns 0 - 1
-void(entity e, float chan, string samp, float vol, float atten) sound = #8;
-vector(vector v) normalize = #9;
-void(string e, ...) error = #10;
-void(string e, ...) objerror = #11;
-float(vector v) vlen = #12;
-float(vector v) vectoyaw = #13;
-entity() spawn = #14;
-void(entity e) remove = #15;
-
-// sets trace_* globals
-// nomonsters can be:
-// An entity will also be ignored for testing if forent == test,
-// forent->owner == test, or test->owner == forent
-// a forent of world is ignored
-void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
-
-entity() checkclient = #17; // returns a client to look for
-entity(entity start, .string fld, string match) find = #18;
-string(string s) precache_sound = #19;
-string(string s) precache_model = #20;
-void(entity client, string s, ...)stuffcmd = #21;
-entity(vector org, float rad) findradius = #22;
-void(string s, ...) bprint = #23;
-void(entity client, string s, ...) sprint = #24;
-void(string s, ...) dprint = #25;
-string(float f) ftos = #26;
-string(vector v) vtos = #27;
-void() coredump = #28; // prints all edicts
-void() traceon = #29; // turns statment trace on
-void() traceoff = #30;
-void(entity e) eprint = #31; // prints an entire edict
-float(float yaw, float dist) walkmove = #32; // returns true or false
-// #33 was removed
-float() droptofloor= #34; // true if landed on floor
-void(float style, string value) lightstyle = #35;
-float(float v) rint = #36; // round to nearest int
-float(float v) floor = #37; // largest integer <= v
-float(float v) ceil = #38; // smallest integer >= v
-// #39 was removed
-float(entity e) checkbottom = #40; // true if self is on ground
-float(vector v) pointcontents = #41; // returns a CONTENT_*
-// #42 was removed
-float(float f) fabs = #43;
-vector(entity e, float speed) aim = #44; // returns the shooting vector
-float(string s) cvar = #45; // return cvar.value
-void(string s, ...) localcmd = #46; // put string into local que
-entity(entity e) nextent = #47; // for looping through all ents
-void(vector o, vector d, float color, float count) particle = #48;// start a particle effect
-void() ChangeYaw = #49; // turn towards self.ideal_yaw
- // at self.yaw_speed
-// #50 was removed
-vector(vector v) vectoangles = #51;
-
-//
-// direct client message generation
-//
-void(float to, float f) WriteByte = #52;
-void(float to, float f) WriteChar = #53;
-void(float to, float f) WriteShort = #54;
-void(float to, float f) WriteLong = #55;
-void(float to, float f) WriteCoord = #56;
-void(float to, float f) WriteAngle = #57;
-void(float to, string s, ...) WriteString = #58;
-void(float to, entity s) WriteEntity = #59;
-
-//
-// broadcast client message generation
-//
-
-// void(float f) bWriteByte = #59;
-// void(float f) bWriteChar = #60;
-// void(float f) bWriteShort = #61;
-// void(float f) bWriteLong = #62;
-// void(float f) bWriteCoord = #63;
-// void(float f) bWriteAngle = #64;
-// void(string s) bWriteString = #65;
-// void(entity e) bWriteEntity = #66;
-
-void(float step) movetogoal = #67;
-
-string(string s) precache_file = #68; // no effect except for -copy
-void(entity e) makestatic = #69;
-void(string s) changelevel = #70;
-
-//#71 was removed
-
-void(string name, string value) cvar_set = #72; // sets cvar.value
-
-void(entity client, string s, ...) centerprint = #73; // sprint, but in middle
-
-void(vector pos, string samp, float vol, float atten) ambientsound = #74;
-
-string(string s) precache_model2 = #75; // registered version only
-string(string s) precache_sound2 = #76; // registered version only
-string(string s) precache_file2 = #77; // registered version only
-
-void(entity e) setspawnparms = #78; // set parm1... to the
- // values at level start
- // for coop respawn
-
-//============================================================================
#endif
--- /dev/null
+/*
+==============================================================================
+
+ SOURCE FOR GLOBALVARS_T C STRUCTURE
+ MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+
+==============================================================================
+*/
+
+//
+// system globals
+//
+entity self;
+entity other;
+entity world;
+float time;
+float frametime;
+
+float player_localentnum; //the entnum
+float player_localnum; //the playernum
+float maxclients; //a constant filled in by the engine. gah, portability eh?
+
+float clientcommandframe; //player movement
+float servercommandframe; //clientframe echoed off the server
+
+string mapname;
+
+//
+// global variables set by built in functions
+//
+vector v_forward, v_up, v_right; // set by makevectors()
+
+// set by traceline / tracebox
+float trace_allsolid;
+float trace_startsolid;
+float trace_fraction;
+vector trace_endpos;
+vector trace_plane_normal;
+float trace_plane_dist;
+entity trace_ent;
+float trace_inopen;
+float trace_inwater;
+
+//
+// required prog functions
+//
+void() CSQC_Init;
+void() CSQC_Shutdown;
+float(float f, float t, float n) CSQC_InputEvent;
+void(float w, float h) CSQC_UpdateView;
+float(string s) CSQC_ConsoleCommand;
+
+//these fields are read and set by the default player physics
+vector pmove_org;
+vector pmove_vel;
+vector pmove_mins;
+vector pmove_maxs;
+//retrieved from the current movement commands (read by player physics)
+float input_timelength;
+vector input_angles;
+vector input_movevalues; //forwards, right, up.
+float input_buttons; //attack, use, jump (default physics only uses jump)
+
+float movevar_gravity;
+float movevar_stopspeed;
+float movevar_maxspeed;
+float movevar_spectatormaxspeed; //used by NOCLIP movetypes.
+float movevar_accelerate;
+float movevar_airaccelerate;
+float movevar_wateraccelerate;
+float movevar_friction;
+float movevar_waterfriction;
+float movevar_entgravity; //the local player's gravity field. Is a multiple (1 is the normal value)
+
+//================================================
+void end_sys_globals; // flag for structure dumping
+//================================================
+
+/*
+==============================================================================
+
+ SOURCE FOR ENTVARS_T C STRUCTURE
+ MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+
+==============================================================================
+*/
+
+//
+// system fields (*** = do not set in prog code, maintained by C code)
+//
+.float modelindex; // *** model index in the precached list
+.vector absmin, absmax; // *** origin + mins / maxs
+
+.float entnum; // *** the ent number as on the server
+.float drawmask;
+.void() predraw;
+
+.float movetype;
+.float solid;
+
+.vector origin; // ***
+.vector oldorigin; // ***
+.vector velocity;
+.vector angles;
+.vector avelocity;
+
+.string classname; // spawn function
+.string model;
+.float frame;
+.float skin;
+.float effects;
+
+.vector mins, maxs; // bounding box extents reletive to origin
+.vector size; // maxs - mins
+
+.void() touch;
+.void() use;
+.void() think;
+.void() blocked; // for doors or plats, called when can't push other
+
+.float nextthink;
+
+.entity chain;
+
+.string netname;
+
+.entity enemy;
+
+.float flags;
+
+.float colormap;
+
+.entity owner; // who launched a missile
+
+//================================================
+void end_sys_fields; // flag for structure dumping
+//================================================
+
+/*
+==============================================================================
+
+ OPTIONAL FIELDS AND GLOBALS
+
+==============================================================================
+*/
+
+// Additional OPTIONAL Fields and Globals
+float intermission; // indicates intermission state (0 = normal, 1 = scores, 2 = finale text)
+
+vector view_angles; // same as input_angles
+vector view_punchangle; // from server
+vector view_punchvector; // from server
+
+/*
+==============================================================================
+
+ CONSTANT DEFINITIONS
+
+==============================================================================
+*/
+
+const float MASK_ENGINE = 1;
+const float MASK_ENGINEVIEWMODELS = 2;
+const float MASK_NORMAL = 4;
+
+const float RF_VIEWMODEL = 1;
+const float RF_EXTERNALMODEL = 2;
+const float RF_DEPTHHACK = 4;
+const float RF_ADDITIVE = 8;
+const float RF_USEAXIS = 16;
+
+const float VF_MIN = 1; //(vector)
+const float VF_MIN_X = 2; //(float)
+const float VF_MIN_Y = 3; //(float)
+const float VF_SIZE = 4; //(vector) (viewport size)
+const float VF_SIZE_Y = 5; //(float)
+const float VF_SIZE_X = 6; //(float)
+const float VF_VIEWPORT = 7; //(vector, vector)
+const float VF_FOV = 8; //(vector)
+const float VF_FOVX = 9; //(float)
+const float VF_FOVY = 10; //(float)
+const float VF_ORIGIN = 11; //(vector)
+const float VF_ORIGIN_X = 12; //(float)
+const float VF_ORIGIN_Y = 13; //(float)
+const float VF_ORIGIN_Z = 14; //(float)
+const float VF_ANGLES = 15; //(vector)
+const float VF_ANGLES_X = 16; //(float)
+const float VF_ANGLES_Y = 17; //(float)
+const float VF_ANGLES_Z = 18; //(float)
+const float VF_DRAWWORLD = 19; //(float)
+const float VF_DRAWENGINESBAR = 20; //(float)
+const float VF_DRAWCROSSHAIR = 21; //(float)
+
+const float VF_CL_VIEWANGLES = 33; //(vector)
+const float VF_CL_VIEWANGLES_X = 34; //(float)
+const float VF_CL_VIEWANGLES_Y = 35; //(float)
+const float VF_CL_VIEWANGLES_Z = 36; //(float)
+
+const float VF_PERSPECTIVE = 200;
+
+const float STAT_HEALTH = 0;
+const float STAT_WEAPONMODEL = 2;
+const float STAT_AMMO = 3;
+const float STAT_ARMOR = 4;
+const float STAT_WEAPONFRAME = 5;
+const float STAT_SHELLS = 6;
+const float STAT_NAILS = 7;
+const float STAT_ROCKETS = 8;
+const float STAT_CELLS = 9;
+const float STAT_ACTIVEWEAPON = 10;
+const float STAT_TOTALSECRETS = 11;
+const float STAT_TOTALMONSTERS = 12;
+const float STAT_SECRETS = 13;
+const float STAT_MONSTERS = 14;
+const float STAT_ITEMS = 15;
+const float STAT_VIEWHEIGHT = 16;
+
+// Quake Sound Constants
+const float CHAN_AUTO = 0;
+const float CHAN_WEAPON = 1;
+const float CHAN_VOICE = 2;
+const float CHAN_ITEM = 3;
+const float CHAN_BODY = 4;
+
+const float ATTN_NONE = 0;
+const float ATTN_NORM = 1;
+const float ATTN_IDLE = 2;
+const float ATTN_STATIC = 3;
+
+// Frik File Constants
+const float FILE_READ = 0;
+const float FILE_APPEND = 1;
+const float FILE_WRITE = 2;
+
+// Quake Point Contents
+const float CONTENT_EMPTY = -1;
+const float CONTENT_SOLID = -2;
+const float CONTENT_WATER = -3;
+const float CONTENT_SLIME = -4;
+const float CONTENT_LAVA = -5;
+const float CONTENT_SKY = -6;
+
+// Quake Solid Constants
+const float SOLID_NOT = 0;
+const float SOLID_TRIGGER = 1;
+const float SOLID_BBOX = 2;
+const float SOLID_SLIDEBOX = 3;
+const float SOLID_BSP = 4;
+const float SOLID_CORPSE = 5;
+
+// Quake Move Constants
+const float MOVE_NORMAL = 0;
+const float MOVE_NOMONSTERS = 1;
+const float MOVE_MISSILE = 2;
+
+// Boolean Constants
+const float true = 1;
+const float false = 0;
+const float TRUE = 1;
+const float FALSE = 0;
+
+const float EXTRA_LOW = -99999999;
+const float EXTRA_HIGH = 99999999;
+
+const vector VEC_1 = '1 1 1';
+const vector VEC_0 = '0 0 0';
+const vector VEC_M1 = '-1 -1 -1';
+
+const float M_PI = 3.14159265358979323846;
+
+vector VEC_HULL_MIN = '-16 -16 -24';
+vector VEC_HULL_MAX = '16 16 32';
+
+// Quake Temporary Entity Constants
+const float TE_SPIKE = 0;
+const float TE_SUPERSPIKE = 1;
+const float TE_GUNSHOT = 2;
+const float TE_EXPLOSION = 3;
+const float TE_TAREXPLOSION = 4;
+const float TE_LIGHTNING1 = 5;
+const float TE_LIGHTNING2 = 6;
+const float TE_WIZSPIKE = 7;
+const float TE_KNIGHTSPIKE = 8;
+const float TE_LIGHTNING3 = 9;
+const float TE_LAVASPLASH = 10;
+const float TE_TELEPORT = 11;
+const float TE_EXPLOSION2 = 12;
+ // Darkplaces Additions
+ const float TE_EXPLOSIONRGB = 53;
+ const float TE_GUNSHOTQUAD = 57;
+ const float TE_EXPLOSIONQUAD = 70;
+ const float TE_SPIKEQUAD = 58;
+ const float TE_SUPERSPIKEQUAD = 59;
+
+// PFlags for Dynamic Lights
+const float PFLAGS_NOSHADOW = 1;
+const float PFLAGS_CORONA = 2;
+const float PFLAGS_FULLDYNAMIC = 128;
+
+const float EF_ADDITIVE = 32;
+const float EF_BLUE = 64;
+const float EF_FLAME = 1024;
+const float EF_FULLBRIGHT = 512;
+const float EF_NODEPTHTEST = 8192;
+const float EF_NODRAW = 16;
+const float EF_NOSHADOW = 4096;
+const float EF_RED = 128;
+const float EF_STARDUST = 2048;
+const float EF_SELECTABLE = 16384;
+
+const float PFL_ONGROUND = 1;
+const float PFL_CROUCH = 2;
+const float PFL_DEAD = 4;
+const float PFL_GIBBED = 8;
+
+// draw flags
+const float DRAWFLAG_NORMAL = 0;
+const float DRAWFLAG_ADDITIVE = 1;
+const float DRAWFLAG_MODULATE = 2;
+const float DRAWFLAG_2XMODULATE = 3;
+const float DRAWFLAG_SCREEN = 4;
+const float DRAWFLAG_MIPMAP = 0x100; // only for R_BeginPolygon
+
+/*
+==============================================================================
+
+ BUILTIN DEFINITIONS
+ EXTENSIONS ARE NOT ADDED HERE, BUT BELOW!
+
+==============================================================================
+*/
+
+void(vector ang) makevectors = #1;
+void(entity e, vector o) setorigin = #2;
+void(entity e, string m) setmodel = #3;
+void(entity e, vector min, vector max) setsize = #4;
+
+void() break_to_debugger = #6;
+float() random = #7;
+void(entity e, float chan, string samp) sound = #8;
+vector(vector v) normalize = #9;
+void(string e) error = #10;
+void(string e) objerror = #11;
+float(vector v) vlen = #12;
+float(vector v) vectoyaw = #13;
+entity() spawn = #14;
+void(entity e) remove = #15;
+float(vector v1, vector v2, float tryents, entity ignoreentity) traceline = #16;
+
+entity(entity start, .string fld, string match) find = #18;
+void(string s) precache_sound = #19;
+void(string s) precache_model = #20;
+
+entity(vector org, float rad) findradius = #22;
+
+void(string s, ...) dprint = #25;
+string(float f) ftos = #26;
+string(vector v) vtos = #27;
+void() coredump = #28;
+void() traceon = #29;
+void() traceoff = #30;
+void(entity e) eprint = #31;
+// settrace optional
+float(float yaw, float dist, float settrace) walkmove = #32;
+
+float() droptofloor = #34;
+void(float style, string value) lightstyle = #35;
+float(float v) rint = #36;
+float(float v) floor = #37;
+float(float v) ceil = #38;
+
+float(entity e) checkbottom = #40;
+float(vector v) pointcontents = #41;
+
+float(float f) fabs = #43;
+
+float(string s) cvar = #45;
+void(string s, ...) localcmd = #46;
+entity(entity e) nextent = #47;
+void(vector o, vector d, float color, float count) particle = #48;
+void() ChangeYaw = #49;
+
+vector(vector v) vectoangles = #51;
+vector(vector v, vector w) vectoangles2 = #51;
+
+float(float f) sin = #60;
+float(float f) cos = #61;
+float(float f) sqrt = #62;
+void(entity ent) changepitch = #63;
+void(entity e, entity ignore) tracetoss = #64;
+string(entity ent) etos = #65;
+
+string(string s) precache_file = #68;
+void(entity e) makestatic = #69;
+
+void(string var, string val) cvar_set = #72;
+
+void(vector pos, string samp, float vol, float atten) ambientsound = #74;
+string(string s) precache_model2 = #75;
+string(string s) precache_sound2 = #76;
+string(string s) precache_file2 = #77;
+
+float(string s) stof = #81;
+
+
+void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox = #90;
+vector() randomvec = #91;
+vector(vector org) getlight = #92;
+vector(vector org, float lpflags) getlight2 = #92;
+vector getlight_dir;
+vector getlight_ambient;
+vector getlight_diffuse;
+const float LP_LIGHTMAP = 1;
+const float LP_RTWORLD = 2;
+const float LP_DYNLIGHT = 4;
+const float LP_COMPLETE = 7;
+
+float(string name, string value) registercvar = #93;
+float( float a, ... ) min = #94;
+float( float b, ... ) max = #95;
+float(float minimum, float val, float maximum) bound = #96;
+float(float f, float f) pow = #97;
+entity(entity start, .float fld, float match) findfloat = #98;
+entity(entity start, .entity fld, entity match) findentity = #98;
+float(string s) checkextension = #99;
+// FrikaC and Telejano range #100-#199
+
+float(string filename, float mode) fopen = #110;
+void(float fhandle) fclose = #111;
+string(float fhandle) fgets = #112;
+void(float fhandle, string s) fputs = #113;
+float(string s) strlen = #114;
+string(...) strcat = #115;
+string(string s, float start, float length) substring = #116;
+vector(string) stov = #117;
+string(string s) strzone = #118;
+void(string s) strunzone = #119;
+
+// FTEQW range #200-#299
+
+float(float number, float quantity) bitshift = #218;
+
+//float(string str, string sub[, float startpos]) strstrofs = #221;
+float(string str, string sub, float startpos) strstrofs = #221;
+float(string str, float ofs) str2chr = #222;
+string(float c, ...) chr2str = #223;
+string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
+string(float chars, string s, ...) strpad = #225;
+string(string info, string key, string value, ...) infoadd = #226;
+string(string info, string key) infoget = #227;
+float(string s1, string s2) strcmp = #228;
+float(string s1, string s2, float len) strncmp = #228;
+float(string s1, string s2) strcasecmp = #229;
+float(string s1, string s2, float len) strncasecmp = #230;
+
+// CSQC range #300-#399
+void() clearscene = #300;
+void(float mask) addentities = #301;
+void(entity ent) addentity = #302;
+float(float property, ...) setproperty = #303;
+float(float property) getproperty = #309;
+vector(float property) getpropertyvec = #309;
+void() renderscene = #304;
+void(vector org, float radius, vector lightcolours) adddynamiclight = #305;
+void(vector org, float radius, vector lightcolours, float style, string cubemapname, float pflags) adddynamiclight2 = #305;
+//void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon = #306;
+void(string texturename, float flag, ...) R_BeginPolygon = #306;
+void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307;
+void() R_EndPolygon = #308;
+vector (vector v) cs_unproject = #310;
+vector (vector v) cs_project = #311;
+
+void(float width, vector pos1, vector pos2, float flag) drawline = #315;
+float(string name) iscachedpic = #316;
+string(string name, ...) precache_pic = #317;
+string(string name) precache_cubemap = #317;
+vector(string picname) draw_getimagesize = #318;
+void(string name) freepic = #319;
+float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter = #320;
+float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #321;
+float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic = #322;
+float(vector position, vector size, vector rgb, float alpha, float flag) drawfill = #323;
+void(float x, float y, float width, float height) drawsetcliparea = #324;
+void(void) drawresetcliparea = #325;
+float(vector position, string text, vector scale, float alpha, float flag) drawcolorcodedstring = #326;
+vector(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawcolorcodedstring2 = #326;
+
+float(float stnum) getstatf = #330;
+float(float stnum, ...) getstati = #331; // can optionally take first bit and count
+string(float firststnum) getstats = #332;
+void(entity e, float mdlindex) setmodelindex = #333;
+string(float mdlindex) modelnameforindex = #334;
+float(string effectname) particleeffectnum = #335;
+void(entity ent, float effectnum, vector start, vector end) trailparticles = #336;
+//void(float effectnum, vector origin [, vector dir, float count]) pointparticles = #337;
+void(float effectnum, vector origin , vector dir, float count) pointparticles = #337;
+void(string s, ...) centerprint = #338;
+void(string s, ...) print = #339;
+string(float keynum) keynumtostring = #340;
+float(string keyname) stringtokeynum = #341;
+string(float keynum) getkeybind = #342;
+void(float usecursor) setcursormode = #343;
+vector() getmousepos = #344;
+float(float framenum) getinputstate = #345;
+void(float sens) setsensitivityscale = #346;
+void(...) runstandardplayerphysics = #347; // this may or may not take a player ent
+string(float playernum, string keyname) getplayerkeyvalue = #348;
+float() isdemo = #349;
+float() isserver = #350;
+void(vector origin, vector forward, vector right, vector up) SetListener = #351;
+void(string cmdname) registercommand = #352;
+float(entity ent) wasfreed = #353;
+string(string key) serverkey = #354;
+
+// Use proper case; refer to the id1 Write* functions!
+float() ReadByte = #360;
+float() ReadChar = #361;
+float() ReadShort = #362;
+float() ReadLong = #363;
+float() ReadCoord = #364;
+float() ReadAngle = #365;
+string() ReadString = #366;
+float() ReadFloat = #367;
+
+// LordHavoc's range #400-#499
+void(entity from, entity to) copyentity = #400;
+
+entity(.string fld, string match) findchain = #402;
+entity(.float fld, float match) findchainfloat = #403;
+void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404;
+void(vector org, vector velocity, float howmany) te_blood = #405;
+void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406;
+void(vector org, vector color) te_explosionrgb = #407;
+void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408;
+void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409;
+void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410;
+void(vector org, vector vel, float howmany) te_spark = #411;
+void(vector org) te_gunshotquad = #412;
+void(vector org) te_spikequad = #413;
+void(vector org) te_superspikequad = #414;
+void(vector org) te_explosionquad = #415;
+void(vector org) te_smallflash = #416;
+void(vector org, float radius, float lifetime, vector color) te_customflash = #417;
+void(vector org) te_gunshot = #418;
+void(vector org) te_spike = #419;
+void(vector org) te_superspike = #420;
+void(vector org) te_explosion = #421;
+void(vector org) te_tarexplosion = #422;
+void(vector org) te_wizspike = #423;
+void(vector org) te_knightspike = #424;
+void(vector org) te_lavasplash = #425;
+void(vector org) te_teleport = #426;
+void(vector org, float colorstart, float colorlength) te_explosion2 = #427;
+void(entity own, vector start, vector end) te_lightning1 = #428;
+void(entity own, vector start, vector end) te_lightning2 = #429;
+void(entity own, vector start, vector end) te_lightning3 = #430;
+void(entity own, vector start, vector end) te_beam = #431;
+void(vector dir) vectorvectors = #432;
+void(vector org) te_plasmaburn = #433;
+float(entity e, float s) getsurfacenumpoints = #434;
+vector(entity e, float s, float n) getsurfacepoint = #435;
+vector(entity e, float s) getsurfacenormal = #436;
+string(entity e, float s) getsurfacetexture = #437;
+float(entity e, vector p) getsurfacenearpoint = #438;
+vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
+
+float(string s) tokenize = #441;
+string(float n) argv = #442;
+void(entity e, entity tagentity, string tagname) setattachment = #443;
+float(string pattern, float caseinsensitive, float quiet) search_begin = #444;
+void(float handle) search_end = #445;
+float(float handle) search_getsize = #446;
+string(float handle, float num) search_getfilename = #447;
+string(string s) cvar_string = #448;
+entity(entity start, .float fld, float match) findflags = #449;
+entity(.float fld, float match) findchainflags = #450;
+float(entity ent, string tagname) gettagindex = #451;
+vector(entity ent, float tagindex) gettaginfo = #452;
+
+void(vector org, vector vel, float howmany) te_flamejet = #457;
+
+entity(float num) entitybyindex = #459;
+float() buf_create = #460;
+void(float bufhandle) buf_del = #461;
+float(float bufhandle) buf_getsize = #462;
+void(float bufhandle_from, float bufhandle_to) buf_copy = #463;
+void(float bufhandle, float sortpower, float backward) buf_sort = #464;
+string(float bufhandle, string glue) buf_implode = #465;
+string(float bufhandle, float string_index) bufstr_get = #466;
+void(float bufhandle, float string_index, string str) bufstr_set = #467;
+float(float bufhandle, string str, float order) bufstr_add = #468;
+void(float bufhandle, float string_index) bufstr_free = #469;
+
+float(float s) asin = #471;
+float(float c) acos = #472;
+float(float t) atan = #473;
+float(float c, float s) atan2 = #474;
+float(float a) tan = #475;
+float(string s) strippedstringlen = #476;
+float(string s) strlennocol = #476; // This is the correct name for the function, but not removing the decolorizedstring mapping.
+string(string s) decolorizedstring = #477;
+string(string s) strdecolorize = #477; // This is the correct name for the function, but not removing the decolorizedstring mapping.
+string(float uselocaltime, string format, ...) strftime = #478;
+string(string s) strtolower = #480;
+string(string s) strtoupper = #481;
+string(string s) cvar_defstring = #482;
+void(vector origin, string sample, float volume, float attenuation) pointsound = #483;
+string(string search, string replace, string subject) strreplace = #484;
+string(string search, string replace, string subject) strireplace = #485;
+vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
+#ifdef SUPPORT_GECKO
+float gecko_create( string name ) = #487;
+void gecko_destroy( string name ) = #488;
+void gecko_navigate( string name, string URI ) = #489;
+float gecko_keyevent( string name, float key, float eventtype ) = #490;
+void gecko_mousemove( string name, float x, float y ) = #491;
+void gecko_resize( string name, float w, float h ) = #492;
+vector gecko_get_texture_extent( string name ) = #493;
+#else
+
+#endif
+
+/*
+==============================================================================
+
+ EXTENSION DEFINITIONS
+
+==============================================================================
+*/
+
+// DP_CSQC_SPAWNPARTICLE
+// idea: VorteX
+// darkplaces implementation: VorteX
+// constant definitions:
+// particle base behavior:
+float PT_ALPHASTATIC = 1;
+float PT_STATIC = 2;
+float PT_SPARK = 3;
+float PT_BEAM = 4;
+float PT_RAIN = 5;
+float PT_RAINDECAL = 6;
+float PT_SNOW = 7;
+float PT_BUBBLE = 8;
+float PT_BLOOD = 9;
+float PT_SMOKE = 10;
+float PT_DECAL = 11;
+float PT_ENTITYPARTICLE = 12;
+// particle blendtypes:
+float PBLEND_ALPHA = 0;
+float PBLEND_ADD = 1;
+float PBLEND_INVMOD = 2;
+// particle orientation:
+float PARTICLE_BILLBOARD = 0;
+float PARTICLE_SPARK = 1;
+float PARTICLE_ORIENTED_DOUBLESIDED = 2;
+float PARTICLE_BEAM = 3;
+// global definitions:
+float particle_type; // one of PT_
+float particle_blendmode; // one of PBLEND_ values
+float particle_orientation; // one of PARTICLE_ values
+vector particle_color1;
+vector particle_color2;
+float particle_tex; // number of chunk in particlefont
+float particle_size;
+float particle_sizeincrease;
+float particle_alpha;
+float particle_alphafade;
+float particle_time;
+float particle_gravity;
+float particle_bounce;
+float particle_airfriction;
+float particle_liquidfriction;
+float particle_originjitter;
+float particle_velocityjitter;
+float particle_qualityreduction; // enable culling of this particle when FPS is low
+float particle_stretch;
+vector particle_staincolor1;
+vector particle_staincolor2;
+float particle_staintex;
+float particle_stainalpha;
+float particle_stainsize;
+float particle_delayspawn;
+float particle_delaycollision;
+float particle_angle;
+float particle_spin;
+// builtin definitions:
+float(float max_themes) initparticlespawner = #522; // check fields/globals for integration and enable particle spawner, return 1 is succeded, otherwise returns 0
+void() resetparticle = #523; // reset p_ globals to default theme #0
+void(float theme) particletheme = #524; // restore p_ globals from saved theme
+float() particlethemesave = #525; // save p_ globals to new particletheme and return it's index
+void(float theme) particlethemeupdate = #525; // save p_ globals to new particletheme and return it's index
+void(float theme) particlethemefree = #526; // delete a particle theme
+float(vector org, vector vel) spawnparticle = #527; // returns 0 when failed, 1 when spawned
+float(vector org, vector vel, float theme) quickparticle = #527; // not reading globals, just theme, returns 0 when failed, 1 when spawned
+float(vector org, vector vel, float delay, float collisiondelay) delayedparticle = #528;
+float(vector org, vector vel, float delay, float collisiondelay, float theme) quickdelayedparticle = #528;
+// description: this builtin provides an easy and flexible way to spawn particles,
+// it is not created as replace for DP_SV_POINTPARTICLES but as an addition to it.
+// With this extension you can create a specific particles like rain particles, or entity particles
+// notes:
+// 1) 0 is default particle template, it could be changed
+// 2) color vectors could have value 0-255 of each component
+// restrictions: max themes could be between 4 and 2048
+// warning: you should call initparticlespawner() at very beginning BEFORE all other particle spawner functions
+// function to query particle info
+// don't remove this function as it protects all particle_ globals from FTEQCC/FRIKQCC non-referenced removal optimisation
+void() printparticle =
+{
+ // vortex: this also protects from 'non-referenced' optimisation on some compilers
+ print("PARTICLE:\n");
+ print(strcat(" type: ", ftos(particle_type), "\n"));
+ print(strcat(" blendmode: ", ftos(particle_blendmode), "\n"));
+ print(strcat(" orientation: ", ftos(particle_orientation), "\n"));
+ print(strcat(" color1: ", vtos(particle_color1), "\n"));
+ print(strcat(" color2: ", vtos(particle_color2), "\n"));
+ print(strcat(" tex: ", ftos(particle_tex), "\n"));
+ print(strcat(" size: ", ftos(particle_size), "\n"));
+ print(strcat(" sizeincrease: ", ftos(particle_sizeincrease), "\n"));
+ print(strcat(" alpha: ", ftos(particle_alpha), "\n"));
+ print(strcat(" alphafade: ", ftos(particle_alphafade), "\n"));
+ print(strcat(" time: ", ftos(particle_time), "\n"));
+ print(strcat(" gravity: ", ftos(particle_gravity), "\n"));
+ print(strcat(" bounce: ", ftos(particle_bounce), "\n"));
+ print(strcat(" airfriction: ", ftos(particle_airfriction), "\n"));
+ print(strcat(" liquidfriction: ", ftos(particle_liquidfriction), "\n"));
+ print(strcat(" originjitter: ", ftos(particle_originjitter), "\n"));
+ print(strcat(" velocityjitter: ", ftos(particle_velocityjitter), "\n"));
+ print(strcat(" qualityreduction: ", ftos(particle_qualityreduction), "\n"));
+ print(strcat(" stretch: ", ftos(particle_stretch), "\n"));
+ print(strcat(" staincolor1: ", vtos(particle_staincolor1), "\n"));
+ print(strcat(" staincolor2: ", vtos(particle_staincolor2), "\n"));
+ print(strcat(" staintex: ", ftos(particle_staintex), "\n"));
+ print(strcat(" stainalpha: ", ftos(particle_stainalpha), "\n"));
+ print(strcat(" stainsize: ", ftos(particle_stainsize), "\n"));
+ print(strcat(" delayspawn: ", ftos(particle_delayspawn), "\n"));
+ print(strcat(" delaycollision: ", ftos(particle_delaycollision), "\n"));
+ print(strcat(" angle: ", ftos(particle_angle), "\n"));
+ print(strcat(" spin: ", ftos(particle_spin), "\n"));
+}
+
+// DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET
+// idea: VorteX
+// darkplaces implementation: VorteX
+float RF_USETRANSPARENTOFFSET = 64; // enables transparent origin offsetting
+// global definitions
+float transparent_offset; // should be set before entity is added
+// description: offset a model's meshes origin used for transparent sorting. Could be used to tweak sorting bugs on very large transparent entities or hacking transparent sorting order for certain objects
+// example: transparent_offset = 1000000; // entity always appear on background of other transparents
+// note: offset is done in view forward axis
+
+// DP_CSQC_ENTITYWORLDOBJECT
+// idea: VorteX
+// darkplaces implementation: VorteX
+const float RF_WORLDOBJECT = 128;
+// description: when renderflag is set, engine will not use culling methods for this entity, e.g. it will always be drawn
+// useful for large outdoor objects (like asteroids on sky horizon or sky models)
+
+// DP_CSQC_ENTITYMODELLIGHT
+// idea: VorteX
+// darkplaces implementation: VorteX
+const float RF_MODELLIGHT = 4096;
+.vector modellight_ambient;
+.vector modellight_diffuse;
+.vector modellight_dir;
+// description: allows CSQC to override directional model lightning on entity
+
+// DP_CSQC_SETPAUSE
+// idea: VorteX
+// darkplaces implementation: VorteX
+// builtin definitions:
+void(float ispaused) setpause = #531;
+// description: provides ability to set pause in local games (similar to one set once console is activated)
+// not stopping sound/cd track, useful for inventory screens, ingame menus with input etc.
+
+// DP_CSQC_QUERYRENDERENTITY
+// idea: VorteX
+// darkplaces implementation: VorteX
+// constant definitions:
+// render entity fields:
+float E_ACTIVE = 0; // float 0/1
+float E_ORIGIN = 1; // vector
+float E_FORWARD = 2; // vector
+float E_RIGHT = 3; // vector
+float E_UP = 4; // vector
+float E_SCALE = 5; // float
+float E_ORIGINANDVECTORS = 6; // returns origin, + sets v_* vectors to orientation
+float E_ALPHA = 7; // float
+float E_COLORMOD = 8; // vector
+float E_PANTSCOLOR = 9; // vector
+float E_SHIRTCOLOR = 10; // vector
+float E_SKIN = 11; // float
+float E_MINS = 12; // vector
+float E_MAXS = 13; // vector
+float E_ABSMIN = 14; // vector
+float E_ABSMAX = 15; // vector
+float E_LIGHT = 16; // vector - modellight
+// builtin definitions:
+float(float entitynum, float fldnum) getentity = #504;
+vector(float entitynum, float fldnum) getentityvec = #504;
+// description: allows to query parms from render entities, especially useful with attaching CSQC ents to
+// server entities networked and interpolated by engine (monsters, players), number of entity is it's SVQC number
+// you can send it via tempentity/CSQC entity message. Note that this builtin doesnt know about entity removing/reallocating
+// so it's meaning to work for short period of time, dont use it on missiles/grenades whatever will be removed next five seconds
+
+//DP_GFX_FONTS
+//idea: Blub\0, divVerent
+//darkplaces implementation: Blub\0
+//console commands:
+// loadfont fontname fontmaps size1 size2 ...
+// A font can simply be gfx/tgafile (freetype fonts doent need extension),
+// or alternatively you can specify multiple fonts and faces
+// Like this: gfx/vera-sans:2,gfx/fallback:1
+// to load face 2 of the font gfx/vera-sans and use face 1
+// of gfx/fallback as fallback font
+// You can also specify a list of font sizes to load, like this:
+// loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32
+// In many cases, 8 12 16 24 32 should be a good choice.
+// for slots see:
+//constant definitions:
+float drawfont; // set it before drawstring()/drawchar() calls
+float FONT_DEFAULT = 0; // 'default'
+float FONT_CONSOLE = 1; // 'console', REALLY should be fixed width (ls!)
+float FONT_SBAR = 2; // 'sbar', used on hud, must be fixed width
+float FONT_NOTIFY = 3; // 'notify', used on sprint/bprint
+float FONT_CHAT = 4; // 'chat'
+float FONT_CENTERPRINT = 5;// 'centerprint'
+float FONT_INFOBAR = 6; // 'infobar'
+float FONT_MENU = 7; // 'menu', should be fixed width
+float FONT_USER0 = 8; // 'user0', userdefined fonts
+float FONT_USER1 = 9; // 'user1', userdefined fonts
+float FONT_USER2 = 10; // 'user2', userdefined fonts
+float FONT_USER3 = 11; // 'user3', userdefined fonts
+float FONT_USER4 = 12; // 'user4', userdefined fonts
+float FONT_USER5 = 13; // 'user5', userdefined fonts
+float FONT_USER6 = 14; // 'user6', userdefined fonts
+float FONT_USER7 = 15; // 'user7' slot, userdefined fonts
+//builtin definitions:
+float findfont(string s) = #356; // find font by fontname and return it's index
+float loadfont(string fontname, string fontmaps, string sizes, float slot, float fix_scale, float fix_voffset) = #357;
+// loads font immediately so stringwidth() function can be used just after builtin call
+// returns a font slotnum (which is used to set drawfont to)
+// first 3 parms are identical to "loadfont" console command ones
+// slot could be one of FONT_ constants or result of findfont() or -1 to not use it
+// if slot is given, font will be loaded to this slotnum and fontname become new title for it
+// this way you can rename user* fonts to something more usable
+// fix_* parms let you fix badly made fonts by applying some transformations to them
+// fix_scale : per-character center-oriented scale (doesn't change line height at all)
+// fix_voffset : vertical offset for each character, it's a multiplier to character height
+float stringwidth(string text, float allowColorCodes, vector size) = #327; // get a width of string with given font and char size
+float stringwidth_menu(string text, float allowColorCodes, vector size) = #468; // in menu.dat it has different builtin #
+//description: engine support for custom fonts in console, hud, qc etc.
+// limits:
+// max 128 chars for font name
+// max 3 font fallbacks
+// max 8 sizes per font
+
+//DP_GFX_FONTS_FREETYPE
+//idea: Blub\0, divVerent
+//darkplaces implementation: Blub\0
+//cvar definitions:
+// r_font_disable_freetype 0/1 : disable freetype fonts loading (uttetly disables freetype library initialization)
+// r_font_antialias 0/1 : antialiasing when loading font
+// r_font_hint 0/1/2/3 : hinting when loading font, 0 is no hinting, 1 light autohinting , 2 full autohinting, 3 full hinting
+// r_font_postprocess_blur X : font outline blur amount
+// r_font_postprocess_outline X : font outline width
+// r_font_postprocess_shadow_x X : font outline shadow x shift amount, applied during outlining
+// r_font_postprocess_shadow_y X : font outline shadow y shift amount, applied during outlining
+// r_font_postprocess_shadow_z X : font outline shadow z shift amount, applied during blurring
+//description: engine support for truetype/freetype fonts
+//so .AFM+.PFB/.OTF/.TTF files could be stuffed as fontmaps in loadfont()
+//(console command version will support them as well)
+
+//DP_CSQC_BINDMAPS
+//idea: daemon, motorsep
+//darkplaces implementation: divVerent
+//builtin definitions:
+string(float key, float bindmap) getkeybind_bindmap = #342;
+float(float key, string bind, float bindmap) setkeybind_bindmap = #630;
+vector(void) getbindmaps = #631;
+float(vector bm) setbindmaps = #632;
+string(string command, float bindmap) findkeysforcommand = #610;
+//<already in EXT_CSQC> float(string key) stringtokeynum = #341;
+//<already in EXT_CSQC> string(float keynum) keynumtostring = #340;
+//description: key bind setting/getting including support for switchable
+//bindmaps.
+
+//DP_CRYPTO
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions: (CSQC)
+float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
+//description:
+//use -1 as buffer handle to justs end delim as postdata
+
+//DP_CSQC_MAINVIEW
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+const float VF_MAINVIEW = 400;
+//use setproperty(VF_MAINVIEW, 1); before calling R_RenderView for the render
+//that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR
+//this flag is set for the first scene, and not cleared by R_ClearScene
+//this flag is automatically cleared by R_RenderView
+//so when not using this extension, the first view rendered is the main view
+
+//DP_CSQC_MINFPS_QUALITY
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+const float VF_MINFPS_QUALITY = 401;
+//use getproperty(VF_MINFPS_QUALITY); to do CSQC based LOD based on cl_minfps
+//1 should lead to an unmodified view
+
+//DP_CSQC_V_CALCREFDEF_WIP1
+//DP_CSQC_V_CALCREFDEF_WIP2
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+void(entity e, float refdefflags) V_CalcRefdef = #640;
+//constant definitions:
+float PMF_DUCKED = 4;
+float PMF_ONGROUND = 8;
+float REFDEFFLAG_TELEPORTED = 1;
+float REFDEFFLAG_JUMPING = 2;
+float REFDEFFLAG_DEAD = 4;
+float REFDEFFLAG_INTERMISSION = 8;
+//- use this on the player entity after performing prediction
+//- pass REFDEFFLAG_TELEPORTED if the player teleported since last frame
+//- pass REFDEFFLAG_JUMPING if jump button is pressed
+//- pass REFDEFFLAG_DEAD if dead (DP_CSQC_V_CALCREFDEF_WIP2)
+//- pass REFDEFFLAG_INTERMISSION if in intermission (DP_CSQC_V_CALCREFDEF_WIP2)
+//- the player entity needs to have origin, velocity, pmove_flags set according
+// to prediction (the above two PMF_ flags are used in the player's pmove_flags)
+//- NOTE: to check for this, ALSO OR a check with DP_CSQC_V_CALCREFDEF to also support
+// the finished extension once done
+
+// assorted builtins
+float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #328;
+vector drawgetimagesize(string pic) = #318;
+#define SPA_POSITION 0
+#define SPA_S_AXIS 1
+#define SPA_T_AXIS 2
+#define SPA_R_AXIS 3
+#define SPA_TEXCOORDS0 4
+#define SPA_LIGHTMAP0_TEXCOORDS 5
+#define SPA_LIGHTMAP_COLOR 6
+// float (entity e, float s) getsurfacenumpoints = #434;
+// vector (entity e, float s, float n) getsurfacepoint = #435;
+// vector (entity e, float s) getsurfacenormal = #436;
+// string (entity e, float s) getsurfacetexture = #437;
+// float (entity e, vector p) getsurfacenearpoint = #438;
+// vector (entity e, float s, vector p) getsurfaceclippedpoint = #439;
+// vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
+float(entity e, float s) getsurfacenumtriangles = #628;
+vector(entity e, float s, float n) getsurfacetriangle = #629;
+
+//DP_QC_ASINACOSATANATAN2TAN
+//idea: Urre
+//darkplaces implementation: LordHavoc
+//constant definitions:
+float DEG2RAD = 0.0174532925199432957692369076848861271344287188854172545609719144;
+float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612;
+float PI = 3.1415926535897932384626433832795028841971693993751058209749445923;
+//builtin definitions:
+/* -Wdouble-declaration
+float(float s) asin = #471; // returns angle in radians for a given sin() value, the result is in the range -PI*0.5 to PI*0.5
+float(float c) acos = #472; // returns angle in radians for a given cos() value, the result is in the range 0 to PI
+float(float t) atan = #473; // returns angle in radians for a given tan() value, the result is in the range -PI*0.5 to PI*0.5
+float(float c, float s) atan2 = #474; // returns angle in radians for a given cos() and sin() value pair, the result is in the range -PI to PI (this is identical to vectoyaw except it returns radians rather than degrees)
+float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(a)) for the given angle in radians, the result is in the range -infinity to +infinity
+*/
+//description:
+//useful math functions for analyzing vectors, note that these all use angles in radians (just like the cos/sin functions) not degrees unlike makevectors/vectoyaw/vectoangles, so be sure to do the appropriate conversions (multiply by DEG2RAD or RAD2DEG as needed).
+//note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v)
+
+//DP_QC_SPRINTF
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+string(string format, ...) sprintf = #627;
+//description:
+//you know sprintf :P
+//supported stuff:
+// %
+// optional: <argpos>$ for the argument to format (the arg counter then is not increased)
+// flags: #0- +
+// optional: <width>, *, or *<argpos>$ for the field width (width is read before value and precision)
+// optional: .<precision>, .*, or .*<argpos>$ for the precision (precision is read before value)
+// length modifiers: h for forcing a float, l for forcing an int/entity (by default, %d etc. cast a float to int)
+// conversions:
+// d takes a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an int
+// i takes an int/entity if no length is specified or i is, and a float if h is specified as length, and cast it to an int
+// ouxXc take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an unsigned int
+// eEfFgG take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to a double
+// s takes a string
+// vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space
+// For conversions s and c, the flag # makes precision and width interpreted
+// as byte count, by default it is interpreted as character count in UTF-8
+// enabled engines. No other conversions can create wide characters, and #
+// has another meaning in these.
+
+//DP_QC_GETTIME
+//idea: tZork
+//darkplaces implementation: tZork, divVerent
+//constant definitions:
+float GETTIME_FRAMESTART = 0; // time of start of frame
+float GETTIME_REALTIME = 1; // current time (may be OS specific)
+float GETTIME_HIRES = 2; // like REALTIME, but may reset between QC invocations and thus can be higher precision
+float GETTIME_UPTIME = 3; // time since start of the engine
+//builtin definitions:
+float(float tmr) gettime = #519;
+//description:
+//some timers to query...
+
+//DP_QC_GETTIME_CDTRACK
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+float GETTIME_CDTRACK = 4;
+//description:
+//returns the playing time of the current cdtrack when passed to gettime()
+//see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels
+
+//DP_QC_TOKENIZEBYSEPARATOR
+//idea: Electro, SavageX, LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+float(string s, string separator1, ...) tokenizebyseparator = #479;
+//description:
+//this function returns tokens separated by any of the supplied separator strings, example:
+//numnumbers = tokenizebyseparator("10.2.3.4", ".");
+//returns 4 and the tokens are "10" "2" "3" "4"
+//possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000")
+
+//DP_QC_TOKENIZE_CONSOLE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+float(string s) tokenize_console = #514;
+float(float i) argv_start_index = #515;
+float(float i) argv_end_index = #516;
+//description:
+//this function returns tokens separated just like the console does
+//also, functions are provided to get the index of the first and last character of each token in the original string
+//Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token.
+
+//DP_SND_SOUND7_WIP1
+//DP_SND_SOUND7_WIP2
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8;
+float SOUNDFLAG_RELIABLE = 1;
+//description:
+//plays a sound, with some more flags
+//extensions to sound():
+//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto",
+// i.e. support multiple sounds at once, but cannot be stopped/restarted
+//- a value 0 in the speed parameter means no change; otherwise, it is a
+// percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is
+// half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2)
+//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send
+// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default);
+// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE
+//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by
+// snd_channel1volume, etc. (so, a channel shares the cvar with its respective
+// auto-channel); however, the mod MUST define snd_channel8volume and upwards
+// in default.cfg if they are to be used, as the engine does not create them
+// to not litter the cvar list
+//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and
+// flags as extra 7th and 8th argument
+//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP
+//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support
+// the finished extension once done
+
+//DP_PRECACHE_PIC_FLAGS
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC
+float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused
+float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense
+//notes: these constants are given as optional second argument to precache_pic()
+
+//DP_QC_TRACE_MOVETYPE_WORLDONLY
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//constant definitions:
+float MOVE_WORLDONLY = 3;
+//description:
+//allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions
+
+//DP_SND_GETSOUNDTIME
+//idea: VorteX
+//darkplaces implementation: VorteX
+//constant definitions:
+float(entity e, float channel) getsoundtime = #533; // get currently sound playing position on entity channel, -1 if not playing or error
+float(string sample) soundlength = #534; // returns length of sound sample in seconds, -1 on error (sound not precached, sound system not initialized etc.)
+//description: provides opportunity to query length of sound samples and realtime tracking of sound playing on entities (similar to DP_GETTIME_CDTRACK)
+//note: beware dedicated server not running sound engine at all, so in dedicated mode this builtins will not work in server progs
+//note also: menu progs not supporting getsoundtime() (will give a warning) since it has no sound playing on entities
+//examples of use:
+// - QC-driven looped sounds
+// - QC events when sound playing is finished
+// - toggleable ambientsounds
+// - subtitles
+
+//DP_QC_NUM_FOR_EDICT
+//idea: Blub\0
+//darkplaces implementation: Blub\0
+//Function to get the number of an entity - a clean way.
+float(entity num) num_for_edict = #512;
+
+//DP_TRACE_HITCONTENTSMASK_SURFACEINFO
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//globals:
+.float dphitcontentsmask; // if non-zero on the entity passed to traceline/tracebox/tracetoss this will override the normal collidable contents rules and instead hit these contents values (for example AI can use tracelines that hit DONOTENTER if it wants to, by simply changing this field on the entity passed to traceline), this affects normal movement as well as trace calls
+float trace_dpstartcontents; // DPCONTENTS_ value at start position of trace
+float trace_dphitcontents; // DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit)
+float trace_dphitq3surfaceflags; // Q3SURFACEFLAG_ value of impacted surface
+string trace_dphittexturename; // texture name of impacted surface
+//constants:
+float DPCONTENTS_SOLID = 1; // hit a bmodel, not a bounding box
+float DPCONTENTS_WATER = 2;
+float DPCONTENTS_SLIME = 4;
+float DPCONTENTS_LAVA = 8;
+float DPCONTENTS_SKY = 16;
+float DPCONTENTS_BODY = 32; // hit a bounding box, not a bmodel
+float DPCONTENTS_CORPSE = 64; // hit a SOLID_CORPSE entity
+float DPCONTENTS_NODROP = 128; // an area where backpacks should not spawn
+float DPCONTENTS_PLAYERCLIP = 256; // blocks player movement
+float DPCONTENTS_MONSTERCLIP = 512; // blocks monster movement
+float DPCONTENTS_DONOTENTER = 1024; // AI hint brush
+float DPCONTENTS_LIQUIDSMASK = 14; // WATER | SLIME | LAVA
+float DPCONTENTS_BOTCLIP = 2048; // AI hint brush
+float DPCONTENTS_OPAQUE = 4096; // only fully opaque brushes get this (may be useful for line of sight checks)
+float Q3SURFACEFLAG_NODAMAGE = 1;
+float Q3SURFACEFLAG_SLICK = 2; // low friction surface
+float Q3SURFACEFLAG_SKY = 4; // sky surface (also has NOIMPACT and NOMARKS set)
+float Q3SURFACEFLAG_LADDER = 8; // climbable surface
+float Q3SURFACEFLAG_NOIMPACT = 16; // projectiles should remove themselves on impact (this is set on sky)
+float Q3SURFACEFLAG_NOMARKS = 32; // projectiles should not leave marks, such as decals (this is set on sky)
+float Q3SURFACEFLAG_FLESH = 64; // projectiles should do a fleshy effect (blood?) on impact
+float Q3SURFACEFLAG_NODRAW = 128; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_HINT = 256; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_SKIP = 512; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_NOLIGHTMAP = 1024; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_POINTLIGHT = 2048; // compiler hint (not important to qc)
+float Q3SURFACEFLAG_METALSTEPS = 4096; // walking on this surface should make metal step sounds
+float Q3SURFACEFLAG_NOSTEPS = 8192; // walking on this surface should not make footstep sounds
+float Q3SURFACEFLAG_NONSOLID = 16384; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_LIGHTFILTER = 32768; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_ALPHASHADOW = 65536; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_NODLIGHT = 131072; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_DUST = 262144; // translucent 'light beam' effect (not important to qc)
+//description:
+//adds additional information after a traceline/tracebox/tracetoss call.
+//also (very important) sets trace_* globals before calling .touch functions,
+//this allows them to inspect the nature of the collision (for example
+//determining if a projectile hit sky), clears trace_* variables for the other
+//object in a touch event (that is to say, a projectile moving will see the
+//trace results in its .touch function, but the player it hit will see very
+//little information in the trace_ variables as it was not moving at the time)
+
+//DP_QC_CVAR_TYPE
+//idea: divVerent
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+float(string name) cvar_type = #495;
+float CVAR_TYPEFLAG_EXISTS = 1;
+float CVAR_TYPEFLAG_SAVED = 2;
+float CVAR_TYPEFLAG_PRIVATE = 4;
+float CVAR_TYPEFLAG_ENGINE = 8;
+float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
+float CVAR_TYPEFLAG_READONLY = 32;
+
+//DP_QC_CRC16
+//idea: divVerent
+//darkplaces implementation: divVerent
+//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
+//When caseinsensitive is set, the CRC is calculated of the lower cased string.
+float(float caseinsensitive, string s, ...) crc16 = #494;
+
+//DP_QC_URI_ESCAPE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//URI::Escape's functionality
+string(string in) uri_escape = #510;
+string(string in) uri_unescape = #511;
+
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
+
+//DP_QC_DIGEST_SHA256
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//description:
+//"SHA256" is also an allowed digest type
+
+//DP_QC_LOG
+//darkplaces implementation: divVerent
+//builtin definitions:
+float log(float f) = #532;
+//description:
+//logarithm
+
+//FTE_CSQC_SKELETONOBJECTS
+//idea: Spike, LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+// all skeleton numbers are 1-based (0 being no skeleton)
+// all bone numbers are 1-based (0 being invalid)
+float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model.
+float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
+float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist
+string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist
+float(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
+float(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity
+vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
+vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
+void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
+void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
+void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
+float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found
+float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
+//fields:
+.float skeletonindex; // active skeleton overriding standard animation on model
+.float frame; // primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
+.float frame2; // secondary framegroup animation (strength = lerpfrac)
+.float frame3; // tertiary framegroup animation (strength = lerpfrac3)
+.float frame4; // quaternary framegroup animation (strength = lerpfrac4)
+.float lerpfrac; // strength of framegroup blend
+.float lerpfrac3; // strength of framegroup blend
+.float lerpfrac4; // strength of framegroup blend
+.float frame1time; // start time of framegroup animation
+.float frame2time; // start time of framegroup animation
+.float frame3time; // start time of framegroup animation
+.float frame4time; // start time of framegroup animation
+//description:
+//this extension provides a way to do complex skeletal animation on an entity.
+//
+//see also DP_SKELETONOBJECTS (this extension implemented on server as well as client)
+//
+//notes:
+//each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render).
+//each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files).
+//if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton.
+//proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose.
+//
+//features include:
+//multiple animations blended together.
+//animating a model with animations from another model with a compatible skeleton.
+//restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head.
+//custom bone controllers - for example making eyes track a target location.
+//
+//
+//
+//example code follows...
+//
+//this helper function lets you identify (by parentage) what group a bone
+//belongs to - for example "torso", "leftarm", would return 1 ("torso") for
+//all children of the bone named "torso", unless they are children of
+//"leftarm" (which is a child of "torso") which would return 2 instead...
+float(float skel, float bonenum, string g1, string g2, string g3, string g4, string g5, string g6) example_skel_findbonegroup =
+{
+ local string bonename;
+ while (bonenum >= 0)
+ {
+ bonename = skel_get_bonename(skel, bonenum);
+ if (bonename == g1) return 1;
+ if (bonename == g2) return 2;
+ if (bonename == g3) return 3;
+ if (bonename == g4) return 4;
+ if (bonename == g5) return 5;
+ if (bonename == g6) return 6;
+ bonenum = skel_get_boneparent(skel, bonenum);
+ }
+ return 0;
+};
+// create a skeletonindex for our player using current modelindex
+void() example_skel_player_setup =
+{
+ self.skeletonindex = skel_create(self.modelindex);
+};
+// setup bones of skeleton based on an animation
+// note: animmodelindex can be a different model than self.modelindex
+void(float animmodelindex, float framegroup, float framegroupstarttime) example_skel_player_update_begin =
+{
+ // start with our standard animation
+ self.frame = framegroup;
+ self.frame2 = 0;
+ self.frame3 = 0;
+ self.frame4 = 0;
+ self.frame1time = framegroupstarttime;
+ self.frame2time = 0;
+ self.frame3time = 0;
+ self.frame4time = 0;
+ self.lerpfrac = 0;
+ self.lerpfrac3 = 0;
+ self.lerpfrac4 = 0;
+ skel_build(self.skeletonindex, self, animmodelindex, 0, 0, 100000);
+};
+// apply a different framegroup animation to bones with a specified parent
+void(float animmodelindex, float framegroup, float framegroupstarttime, float blendalpha, string groupbonename, string excludegroupname1, string excludegroupname2) example_skel_player_update_applyoverride =
+{
+ local float bonenum;
+ local float numbones;
+ self.frame = framegroup;
+ self.frame2 = 0;
+ self.frame3 = 0;
+ self.frame4 = 0;
+ self.frame1time = framegroupstarttime;
+ self.frame2time = 0;
+ self.frame3time = 0;
+ self.frame4time = 0;
+ self.lerpfrac = 0;
+ self.lerpfrac3 = 0;
+ self.lerpfrac4 = 0;
+ bonenum = 0;
+ numbones = skel_get_numbones(self.skeletonindex);
+ while (bonenum < numbones)
+ {
+ if (example_skel_findbonegroup(self.skeletonindex, bonenum, groupbonename, excludegroupname1, excludegroupname2, "", "", "") == 1)
+ skel_build(self.skeletonindex, self, animmodelindex, 1 - blendalpha, bonenum, bonenum + 1);
+ bonenum = bonenum + 1;
+ }
+};
+// make eyes point at a target location, be sure v_forward, v_right, v_up are set correctly before calling
+void(vector eyetarget, string bonename) example_skel_player_update_eyetarget =
+{
+ local float bonenum;
+ local vector ang;
+ local vector oldforward, oldright, oldup;
+ local vector relforward, relright, relup, relorg;
+ local vector boneforward, boneright, boneup, boneorg;
+ local vector parentforward, parentright, parentup, parentorg;
+ local vector u, v;
+ local vector modeleyetarget;
+ bonenum = skel_find_bone(self.skeletonindex, bonename) - 1;
+ if (bonenum < 0)
+ return;
+ oldforward = v_forward;
+ oldright = v_right;
+ oldup = v_up;
+ v = eyetarget - self.origin;
+ modeleyetarget_x = v * v_forward;
+ modeleyetarget_y = 0-v * v_right;
+ modeleyetarget_z = v * v_up;
+ // this is an eyeball, make it point at the target location
+ // first get all the data we can...
+ relorg = skel_get_bonerel(self.skeletonindex, bonenum);
+ relforward = v_forward;
+ relright = v_right;
+ relup = v_up;
+ boneorg = skel_get_boneabs(self.skeletonindex, bonenum);
+ boneforward = v_forward;
+ boneright = v_right;
+ boneup = v_up;
+ parentorg = skel_get_boneabs(self.skeletonindex, skel_get_boneparent(self.skeletonindex, bonenum));
+ parentforward = v_forward;
+ parentright = v_right;
+ parentup = v_up;
+ // get the vector from the eyeball to the target
+ u = modeleyetarget - boneorg;
+ // now transform it inversely by the parent matrix to produce new rel vectors
+ v_x = u * parentforward;
+ v_y = u * parentright;
+ v_z = u * parentup;
+ ang = vectoangles2(v, relup);
+ ang_x = 0 - ang_x;
+ makevectors(ang);
+ // set the relative bone matrix
+ skel_set_bone(self.skeletonindex, bonenum, relorg);
+ // restore caller's v_ vectors
+ v_forward = oldforward;
+ v_right = oldright;
+ v_up = oldup;
+};
+// delete skeleton when we're done with it
+// note: skeleton remains valid until next frame when it is really deleted
+void() example_skel_player_delete =
+{
+ skel_delete(self.skeletonindex);
+ self.skeletonindex = 0;
+};
+//
+// END OF EXAMPLES FOR FTE_CSQC_SKELETONOBJECTS
+//
+
+//DP_QC_ENTITYDATA
+//idea: KrimZon
+//darkplaces implementation: KrimZon
+//builtin definitions:
+float() numentityfields = #496;
+string(float fieldnum) entityfieldname = #497;
+float(float fieldnum) entityfieldtype = #498;
+string(float fieldnum, entity ent) getentityfieldstring = #499;
+float(float fieldnum, entity ent, string s) putentityfieldstring = #500;
+//constants:
+//Returned by entityfieldtype
+float FIELD_STRING = 1;
+float FIELD_FLOAT = 2;
+float FIELD_VECTOR = 3;
+float FIELD_ENTITY = 4;
+float FIELD_FUNCTION = 6;
+//description:
+//Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame.
+//WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers.
+//numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z.
+//entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever.
+//entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers.
+//getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
+//putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
+
+//DP_QC_ENTITYSTRING
+void(string s) loadfromdata = #529;
+void(string s) loadfromfile = #530;
+void(string s) callfunction = #605;
+void(float fh, entity e) writetofile = #606;
+float(string s) isfunction = #607;
+void(entity e, string s) parseentitydata = #608;
+
+//DP_COVERAGE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//function definitions:
+void coverage() = #642; // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
+
+// assorted builtins
+const float STAT_MOVEVARS_TICRATE = 240;
+const float STAT_MOVEVARS_TIMESCALE = 241;
+const float STAT_FRAGLIMIT = 235;
+const float STAT_TIMELIMIT = 236;
+const float STAT_MOVEVARS_GRAVITY = 242;
+string(void) ReadPicture = #501;
+float PARTICLES_USEALPHA = 1;
+float particles_alphamin, particles_alphamax;
+float PARTICLES_USECOLOR = 2;
+vector particles_colormin, particles_colormax;
+float PARTICLES_USEFADE = 4; // fades the COUNT (fade alpha using alphamin/alphamax)
+float particles_fade;
+float PARTICLES_DRAWASTRAIL = 128;
+void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, float flags) boxparticles = #502;
+float trace_networkentity;
+const float RF_FULLBRIGHT = 256;
+const float RF_NOSHADOW = 512;
+float RF_DYNAMICMODELLIGHT = 8192;
+
+float gettaginfo_parent;
+string gettaginfo_name;
+vector gettaginfo_offset;
+vector gettaginfo_forward;
+vector gettaginfo_right;
+vector gettaginfo_up;
+float checkpvs(vector viewpos, entity viewee) = #240;
--- /dev/null
+
+//DarkPlaces supported extension list, draft version 1.04
+
+//things that don't have extensions yet:
+.float disableclientprediction;
+
+//definitions that id Software left out:
+//these are passed as the 'nomonsters' parameter to traceline/tracebox (yes really this was supported in all quake engines, nomonsters is misnamed)
+float MOVE_NORMAL = 0; // same as FALSE
+float MOVE_NOMONSTERS = 1; // same as TRUE
+float MOVE_MISSILE = 2; // save as movement with .movetype == MOVETYPE_FLYMISSILE
+
+//checkextension function
+//idea: expected by almost everyone
+//darkplaces implementation: LordHavoc
+float(string s) checkextension = #99;
+//description:
+//check if (cvar("pr_checkextension")) before calling this, this is the only
+//guaranteed extension to be present in the extension system, it allows you
+//to check if an extension is available, by name, to check for an extension
+//use code like this:
+//// (it is recommended this code be placed in worldspawn or a worldspawn called function somewhere)
+//if (cvar("pr_checkextension"))
+//if (checkextension("DP_SV_SETCOLOR"))
+// ext_setcolor = TRUE;
+//from then on you can check ext_setcolor to know if that extension is available
+
+//BX_WAL_SUPPORT
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//description:
+//indicates the engine supports .wal textures for filenames in the textures/ directory
+//(note: DarkPlaces has supported this since 2001 or 2002, but did not advertise it as an extension, then I noticed Betwix was advertising it and added the extension accordingly)
+
+//DP_BUTTONCHAT
+//idea: Vermeulen
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float buttonchat;
+//description:
+//true if the player is currently chatting (in messagemode, menus or console)
+
+//DP_BUTTONUSE
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float buttonuse;
+//client console commands:
+//+use
+//-use
+//description:
+//made +use and -use commands work, they now control the .buttonuse field (.button1 was used by many mods for other purposes).
+
+//DP_CL_LOADSKY
+//idea: Nehahra, LordHavoc
+//darkplaces implementation: LordHavoc
+//client console commands:
+//"loadsky" (parameters: "basename", example: "mtnsun_" would load "mtnsun_up.tga" and "mtnsun_rt.tga" and similar names, use "" to revert to quake sky, note: this is the same as Quake2 skybox naming)
+//description:
+//sets global skybox for the map for this client (can be stuffed to a client by QC), does not hurt much to repeatedly execute this command, please don't use this in mods if it can be avoided (only if changing skybox is REALLY needed, otherwise please use DP_GFX_SKYBOX).
+
+//DP_CON_SET
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//description:
+//indicates this engine supports the "set" console command which creates or sets a non-archived cvar (not saved to config.cfg on exit), it is recommended that set and seta commands be placed in default.cfg for mod-specific cvars.
+
+//DP_CON_SETA
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//description:
+//indicates this engine supports the "seta" console command which creates or sets an archived cvar (saved to config.cfg on exit), it is recommended that set and seta commands be placed in default.cfg for mod-specific cvars.
+
+//DP_CON_ALIASPARAMETERS
+//idea: many
+//darkplaces implementation: Black
+//description:
+//indicates this engine supports aliases containing $1 through $9 parameter macros (which when called will expand to the parameters passed to the alias, for example alias test "say $2 $1", then you can type test hi there and it will execute say there hi), as well as $0 (name of the alias) and $* (all parameters $1 onward).
+
+//DP_CON_EXPANDCVAR
+//idea: many, PHP
+//darkplaces implementation: Black
+//description:
+//indicates this engine supports console commandlines containing $cvarname which will expand to the contents of that cvar as a parameter, for instance say my fov is $fov, will say "my fov is 90", or similar.
+
+//DP_CON_STARTMAP
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//adds two engine-called aliases named startmap_sp and startmap_dm which are called when the engine tries to start a singleplayer game from the menu (startmap_sp) or the -listen or -dedicated options are used or the engine is a dedicated server (uses startmap_dm), these allow a mod or game to specify their own map instead of start, and also distinguish between singleplayer and -listen/-dedicated, also these need not be a simple "map start" command, they can do other things if desired, startmap_sp and startmap_dm both default to "map start".
+
+//DP_EF_ADDITIVE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_ADDITIVE = 32;
+//description:
+//additive blending when this object is rendered
+
+//DP_EF_BLUE
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_BLUE = 64;
+//description:
+//entity emits blue light (used for quad)
+
+//DP_EF_DOUBLESIDED
+//idea: LordHavoc
+//darkplaces implementation: [515] and LordHavoc
+//effects bit:
+float EF_DOUBLESIDED = 32768;
+//description:
+//render entity as double sided (backfaces are visible, I.E. you see the 'interior' of the model, rather than just the front), can be occasionally useful on transparent stuff.
+
+//DP_EF_DYNAMICMODELLIGHT
+//idea: C.Brutail, divVerent, maikmerten
+//darkplaces implementation: divVerent
+//effects bit:
+float EF_DYNAMICMODELLIGHT = 131072;
+//description:
+//force dynamic model light on the entity, even if it's a BSP model (or anything else with lightmaps or light colors)
+
+//DP_EF_FLAME
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_FLAME = 1024;
+//description:
+//entity is on fire
+
+//DP_EF_FULLBRIGHT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_FULLBRIGHT = 512;
+//description:
+//entity is always brightly lit
+
+//DP_EF_NODEPTHTEST
+//idea: Supa
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_NODEPTHTEST = 8192;
+//description:
+//makes entity show up to client even through walls, useful with EF_ADDITIVE for special indicators like where team bases are in a map, so that people don't get lost
+
+//DP_EF_NODRAW
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_NODRAW = 16;
+//description:
+//prevents server from sending entity to client (forced invisible, even if it would have been a light source or other such things)
+
+//DP_EF_NOGUNBOB
+//idea: Chris Page, Dresk
+//darkplaces implementation: LordHAvoc
+//effects bit:
+float EF_NOGUNBOB = 256;
+//description:
+//this has different meanings depending on the entity it is used on:
+//player entity - prevents gun bobbing on player.viewmodel
+//viewmodelforclient entity - prevents gun bobbing on an entity attached to the player's view
+//other entities - no effect
+//uses:
+//disabling gun bobbing on a diving mask or other model used as a .viewmodel.
+//disabling gun bobbing on view-relative models meant to be part of the heads up display. (note: if fov is changed these entities may be off-screen, or too near the center of the screen, so use fov 90 in this case)
+
+//DP_EF_NOSHADOW
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_NOSHADOW = 4096;
+//description:
+//realtime lights will not cast shadows from this entity (but can still illuminate it)
+
+//DP_EF_RED
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_RED = 128;
+//description:
+//entity emits red light (used for invulnerability)
+
+//DP_EF_RESTARTANIM_BIT
+//idea: id software
+//darkplaces implementation: divVerent
+//effects bit:
+float EF_RESTARTANIM_BIT = 1048576;
+//description:
+//when toggled, the current animation is restarted. Useful for weapon animation.
+//to toggle this bit in QC, you can do:
+// self.effects += (EF_RESTARTANIM_BIT - 2 * (self.effects & EF_RESTARTANIM_BIT));
+
+//DP_EF_STARDUST
+//idea: MythWorks Inc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_STARDUST = 2048;
+//description:
+//entity emits bouncing sparkles in every direction
+
+//DP_EF_TELEPORT_BIT
+//idea: id software
+//darkplaces implementation: divVerent
+//effects bit:
+float EF_TELEPORT_BIT = 2097152;
+//description:
+//when toggled, interpolation of the entity is skipped for one frame. Useful for teleporting.
+//to toggle this bit in QC, you can do:
+// self.effects += (EF_TELEPORT_BIT - 2 * (self.effects & EF_TELEPORT_BIT));
+
+//DP_ENT_ALPHA
+//idea: Nehahra
+//darkplaces implementation: LordHavoc
+//fields:
+.float alpha;
+//description:
+//controls opacity of the entity, 0.0 is forced to be 1.0 (otherwise everything would be invisible), use -1 if you want to make something invisible, 1.0 is solid (like normal).
+
+//DP_ENT_COLORMOD
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definition:
+.vector colormod;
+//description:
+//controls color of the entity, '0 0 0', is forced to be '1 1 1' (otherwise everything would be black), used for tinting objects, for instance using '1 0.6 0.4' on an ogre would give you an orange ogre (order is red green blue), note the colors can go up to '8 8 8' (8x as bright as normal).
+
+//DP_ENT_CUSTOMCOLORMAP
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//if .colormap is set to 1024 + pants + shirt * 16, those colors will be used for colormapping the entity, rather than looking up a colormap by player number.
+
+/*
+//NOTE: no longer supported by darkplaces because all entities are delta compressed now
+//DP_ENT_DELTACOMPRESS // no longer supported
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_DELTA = 8388608;
+//description:
+//(obsolete) applies delta compression to the network updates of the entity, making updates smaller, this might cause some unreliable behavior in packet loss situations, so it should only be used on numerous (nails/plasma shots/etc) or unimportant objects (gibs/shell casings/bullet holes/etc).
+*/
+
+//DP_ENT_EXTERIORMODELTOCLIENT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//fields:
+.entity exteriormodeltoclient;
+//description:
+//the entity is visible to all clients with one exception: if the specified client is using first person view (not using chase_active) the entity will not be shown. Also if tag attachments are supported any entities attached to the player entity will not be drawn in first person.
+
+//DP_ENT_GLOW
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float glow_color;
+.float glow_size;
+.float glow_trail;
+//description:
+//customizable glowing light effect on the entity, glow_color is a paletted (8bit) color in the range 0-255 (note: 0 and 254 are white), glow_size is 0 or higher (up to the engine what limit to cap it to, darkplaces imposes a 1020 limit), if glow_trail is true it will leave a trail of particles of the same color as the light.
+
+//DP_ENT_GLOWMOD
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definition:
+.vector glowmod;
+//description:
+//controls color of the entity's glow texture (fullbrights), '0 0 0', is forced to be '1 1 1' (otherwise everything would be black), used for tinting objects, see colormod (same color restrictions apply).
+
+//DP_ENT_LOWPRECISION
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_LOWPRECISION = 4194304;
+//description:
+//uses low quality origin coordinates, reducing network traffic compared to the default high precision, intended for numerous objects (projectiles/gibs/bullet holes/etc).
+
+//DP_ENT_SCALE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float scale;
+//description:
+//controls rendering scale of the object, 0 is forced to be 1, darkplaces uses 1/16th accuracy and a limit of 15.9375, can be used to make an object larger or smaller.
+
+//DP_ENT_TRAILEFFECTNUM
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float traileffectnum;
+//description:
+//use a custom effectinfo.txt effect on this entity, assign it like this:
+//self.traileffectnum = particleeffectnum("mycustomeffect");
+//this will do both the dlight and particle trail as described in the effect, basically equivalent to trailparticles() in CSQC but performed on a server entity.
+
+//DP_ENT_VIEWMODEL
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.entity viewmodelforclient;
+//description:
+//this is a very special capability, attachs the entity to the view of the client specified, origin and angles become relative to the view of that client, all effects can be used (multiple skins on a weapon model etc)... the entity is not visible to any other client.
+
+//DP_GFX_EXTERNALTEXTURES
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//loads external textures found in various directories (tenebrae compatible)...
+/*
+in all examples .tga is merely the base texture, it can be any of these:
+.tga (base texture)
+_glow.tga (fullbrights or other glowing overlay stuff, NOTE: this is done using additive blend, not alpha)
+_pants.tga (pants overlay for colormapping on models, this should be shades of grey (it is tinted by pants color) and black wherever the base texture is not black, as this is an additive blend)
+_shirt.tga (same idea as pants, but for shirt color)
+_diffuse.tga (this may be used instead of base texture for per pixel lighting)
+_gloss.tga (specular texture for per pixel lighting, note this can be in color (tenebrae only supports greyscale))
+_norm.tga (normalmap texture for per pixel lighting)
+_bump.tga (bumpmap, converted to normalmap at load time, supported only for reasons of tenebrae compatibility)
+_luma.tga (same as _glow but supported only for reasons of tenebrae compatibility)
+
+due to glquake's incomplete Targa(r) loader, this section describes
+required Targa(r) features support:
+types:
+type 1 (uncompressed 8bit paletted with 24bit/32bit palette)
+type 2 (uncompressed 24bit/32bit true color, glquake supported this)
+type 3 (uncompressed 8bit greyscale)
+type 9 (RLE compressed 8bit paletted with 24bit/32bit palette)
+type 10 (RLE compressed 24bit/32bit true color, glquake supported this)
+type 11 (RLE compressed 8bit greyscale)
+attribute bit 0x20 (Origin At Top Left, top to bottom, left to right)
+
+image formats guaranteed to be supported: tga, pcx, lmp
+image formats that are optional: png, jpg
+
+mdl/spr/spr32 examples:
+skins are named _A (A being a number) and skingroups are named like _A_B
+these act as suffixes on the model name...
+example names for skin _2_1 of model "progs/armor.mdl":
+game/override/progs/armor.mdl_2_1.tga
+game/textures/progs/armor.mdl_2_1.tga
+game/progs/armor.mdl_2_1.tga
+example names for skin _0 of the model "progs/armor.mdl":
+game/override/progs/armor.mdl_0.tga
+game/textures/progs/armor.mdl_0.tga
+game/progs/armor.mdl_0.tga
+note that there can be more skins files (of the _0 naming) than the mdl
+contains, this is only useful to save space in the .mdl file if classic quake
+compatibility is not a concern.
+
+bsp/md2/md3 examples:
+example names for the texture "quake" of model "maps/start.bsp":
+game/override/quake.tga
+game/textures/quake.tga
+game/quake.tga
+
+sbar/menu/console textures: for example the texture "conchars" (console font) in gfx.wad
+game/override/gfx/conchars.tga
+game/textures/gfx/conchars.tga
+game/gfx/conchars.tga
+*/
+
+//DP_GFX_EXTERNALTEXTURES_PERMAPTEXTURES
+//idea: Fuh?
+//darkplaces implementation: LordHavoc
+//description:
+//Q1BSP and HLBSP map loading loads external textures found in textures/<mapname>/ as well as textures/.
+//Where mapname is the bsp filename minus the extension (typically .bsp) and minus maps/ if it is in maps/ (any other path is not removed)
+//example:
+//maps/e1m1.bsp uses textures in the directory textures/e1m1/ and falls back to textures/
+//maps/b_batt0.bsp uses textures in the directory textures/b_batt0.bsp and falls back to textures/
+//as a more extreme example:
+//progs/something/blah.bsp uses textures in the directory textures/progs/something/blah/ and falls back to textures/
+
+//DP_GFX_FOG
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//worldspawn fields:
+//"fog" (parameters: "density red green blue", example: "0.1 0.3 0.3 0.3")
+//description:
+//global fog for the map, can not be changed by QC
+
+//DP_GFX_QUAKE3MODELTAGS
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//field definitions:
+.entity tag_entity; // entity this is attached to (call setattachment to set this)
+.float tag_index; // which tag on that entity (0 is relative to the entity, > 0 is an index into the tags on the model if it has any) (call setattachment to set this)
+//builtin definitions:
+void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
+//description:
+//allows entities to be visually attached to model tags (which follow animations perfectly) on other entities, for example attaching a weapon to a player's hand, or upper body attached to lower body, allowing it to change angles and frame separately (note: origin and angles are relative to the tag, use '0 0 0' for both if you want it to follow exactly, this is similar to viewmodelforclient's behavior).
+//note 2: if the tag is not found, it defaults to "" (attach to origin/angles of entity)
+//note 3: attaching to world turns off attachment
+//note 4: the entity that this is attached to must be visible for this to work
+//note 5: if an entity is attached to the player entity it will not be drawn in first person.
+
+//DP_GFX_SKINFILES
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//alias models (mdl, md2, md3) can have .skin files to replace conventional texture naming, these have a naming format such as:
+//progs/test.md3_0.skin
+//progs/test.md3_1.skin
+//...
+//
+//these files contain replace commands (replace meshname shadername), example:
+//replace "helmet" "progs/test/helmet1.tga" // this is a mesh shader replacement
+//replace "teamstripes" "progs/test/redstripes.tga"
+//replace "visor" "common/nodraw" // this makes the visor mesh invisible
+////it is not possible to rename tags using this format
+//
+//Or the Quake3 syntax (100% compatible with Quake3's .skin files):
+//helmet,progs/test/helmet1.tga // this is a mesh shader replacement
+//teamstripes,progs/test/redstripes.tga
+//visor,common/nodraw // this makes the visor mesh invisible
+//tag_camera, // this defines that the first tag in the model is called tag_camera
+//tag_test, // this defines that the second tag in the model is called tag_test
+//
+//any names that are not replaced are automatically show up as a grey checkerboard to indicate the error status, and "common/nodraw" is a special case that is invisible.
+//this feature is intended to allow multiple skin sets on md3 models (which otherwise only have one skin set).
+//other commands might be added someday but it is not expected.
+
+//DP_GFX_SKYBOX
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//worldspawn fields:
+//"sky" (parameters: "basename", example: "mtnsun_" would load "mtnsun_up.tga" and "mtnsun_rt.tga" and similar names, note: "sky" is also used the same way by Quake2)
+//description:
+//global skybox for the map, can not be changed by QC
+
+//DP_UTF8
+//idea: Blub\0, divVerent
+//darkplaces implementation: Blub\0
+//cvar definitions:
+// utf8_enable: enable utf8 encoding
+//description: utf8 characters are allowed inside cvars, protocol strings, files, progs strings, etc.,
+//and count as 1 char for string functions like strlen, substring, etc.
+// note: utf8_enable is run-time cvar, could be changed during execution
+// note: beware that str2chr() could return value bigger than 255 once utf8 is enabled
+
+//DP_HALFLIFE_MAP
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//simply indicates that the engine supports HalfLife maps (BSP version 30, NOT the QER RGBA ones which are also version 30).
+
+//DP_HALFLIFE_MAP_CVAR
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//cvars:
+//halflifebsp 0/1
+//description:
+//engine sets this cvar when loading a map to indicate if it is halflife format or not.
+
+//DP_HALFLIFE_SPRITE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//simply indicates that the engine supports HalfLife sprites.
+
+//DP_INPUTBUTTONS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float button3;
+.float button4;
+.float button5;
+.float button6;
+.float button7;
+.float button8;
+.float button9;
+.float button10;
+.float button11;
+.float button12;
+.float button13;
+.float button14;
+.float button15;
+.float button16;
+//description:
+//set to the state of the +button3, +button4, +button5, +button6, +button7, and +button8 buttons from the client, this does not involve protocol changes (the extra 6 button bits were simply not used).
+//the exact mapping of protocol button bits on the server is:
+//self.button0 = (bits & 1) != 0;
+///* button1 is skipped because mods abuse it as a variable, and accordingly it has no bit */
+//self.button2 = (bits & 2) != 0;
+//self.button3 = (bits & 4) != 0;
+//self.button4 = (bits & 8) != 0;
+//self.button5 = (bits & 16) != 0;
+//self.button6 = (bits & 32) != 0;
+//self.button7 = (bits & 64) != 0;
+//self.button8 = (bits & 128) != 0;
+
+// DP_LIGHTSTYLE_STATICVALUE
+// idea: VorteX
+// darkplaces implementation: VorteX
+// description: allows alternative 'static' lightstyle syntax : "=value"
+// examples: "=0.5", "=2.0", "=2.75"
+// could be used to control switchable lights or making styled lights with brightness > 2
+// Warning: this extension is experimental. It safely works in CSQC, but SVQC use is limited by the fact
+// that other engines (which do not support this extension) could connect to a game and misunderstand this kind of lightstyle syntax
+
+//DP_LITSPRITES
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//indicates this engine supports lighting on sprites, any sprite with ! in its filename (both on disk and in the qc) will be lit rather than having forced EF_FULLBRIGHT (EF_FULLBRIGHT on the entity can still force these sprites to not be lit).
+
+//DP_LITSUPPORT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//indicates this engine loads .lit files for any quake1 format .bsp files it loads to enhance maps with colored lighting.
+//implementation description: these files begin with the header QLIT followed by version number 1 (as little endian 32bit), the rest of the file is a replacement lightmaps lump, except being 3x as large as the lightmaps lump of the map it matches up with (and yes the between-lightmap padding is expanded 3x to keep this consistent), so the lightmap offset in each surface is simply multiplied by 3 during loading to properly index the lit data, and the lit file is loaded instead of the lightmap lump, other renderer changes are needed to display these of course... see the litsupport.zip sample code (almost a tutorial) at http://icculus.org/twilight/darkplaces for more information.
+
+//DP_MONSTERWALK
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//MOVETYPE_WALK is permitted on non-clients, so bots can move smoothly, run off ledges, etc, just like a real player.
+
+//DP_MOVETYPEBOUNCEMISSILE
+//idea: id Software
+//darkplaces implementation: id Software
+//movetype definitions:
+//float MOVETYPE_BOUNCEMISSILE = 11; // already in defs.qc
+//description:
+//MOVETYPE_BOUNCE but without gravity, and with full reflection (no speed loss like grenades have), in other words - bouncing laser bolts.
+
+//DP_MOVETYPEFLYWORLDONLY
+//idea: Samual
+//darkplaces implementation: Samual
+//movetype definitions:
+float MOVETYPE_FLY_WORLDONLY = 33;
+//description:
+//like MOVETYPE_FLY, but does all traces with MOVE_WORLDONLY, and is ignored by MOVETYPE_PUSH. Should only be combined with SOLID_NOT and SOLID_TRIGGER.
+
+//DP_NULL_MODEL
+//idea: Chris
+//darkplaces implementation: divVerent
+//definitions:
+//string dp_null_model = "null";
+//description:
+//setmodel(e, "null"); makes an entity invisible, have a zero bbox, but
+//networked. useful for shared CSQC entities.
+
+//DP_MOVETYPEFOLLOW
+//idea: id Software, LordHavoc (redesigned)
+//darkplaces implementation: LordHavoc
+//movetype definitions:
+float MOVETYPE_FOLLOW = 12;
+//description:
+//MOVETYPE_FOLLOW implemented, this uses existing entity fields in unusual ways:
+//aiment - the entity this is attached to.
+//punchangle - the original angles when the follow began.
+//view_ofs - the relative origin (note that this is un-rotated by punchangle, and that is actually the only purpose of punchangle).
+//v_angle - the relative angles.
+//here's an example of how you would set a bullet hole sprite to follow a bmodel it was created on, even if the bmodel rotates:
+//hole.movetype = MOVETYPE_FOLLOW; // make the hole follow
+//hole.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid
+//hole.aiment = bmodel; // make the hole follow bmodel
+//hole.punchangle = bmodel.angles; // the original angles of bmodel
+//hole.view_ofs = hole.origin - bmodel.origin; // relative origin
+//hole.v_angle = hole.angles - bmodel.angles; // relative angles
+
+//DP_QC_ASINACOSATANATAN2TAN
+//idea: Urre
+//darkplaces implementation: LordHavoc
+//constant definitions:
+float DEG2RAD = 0.0174532925199432957692369076848861271344287188854172545609719144;
+float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612;
+float PI = 3.1415926535897932384626433832795028841971693993751058209749445923;
+//builtin definitions:
+float(float s) asin = #471; // returns angle in radians for a given sin() value, the result is in the range -PI*0.5 to PI*0.5
+float(float c) acos = #472; // returns angle in radians for a given cos() value, the result is in the range 0 to PI
+float(float t) atan = #473; // returns angle in radians for a given tan() value, the result is in the range -PI*0.5 to PI*0.5
+float(float c, float s) atan2 = #474; // returns angle in radians for a given cos() and sin() value pair, the result is in the range -PI to PI (this is identical to vectoyaw except it returns radians rather than degrees)
+float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(a)) for the given angle in radians, the result is in the range -infinity to +infinity
+//description:
+//useful math functions for analyzing vectors, note that these all use angles in radians (just like the cos/sin functions) not degrees unlike makevectors/vectoyaw/vectoangles, so be sure to do the appropriate conversions (multiply by DEG2RAD or RAD2DEG as needed).
+//note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v)
+
+//DP_QC_AUTOCVARS
+//idea: divVerent
+//darkplaces implementation: divVerent
+//description:
+//allows QC variables to be bound to cvars
+//(works for float, string, vector types)
+//example:
+// float autocvar_developer;
+// float autocvar_registered;
+// string autocvar__cl_name;
+//NOTE: copying a string-typed autocvar to another variable/field, and then
+//changing the cvar or returning from progs is UNDEFINED. Writing to autocvar
+//globals is UNDEFINED. Accessing autocvar globals after changing that cvar in
+//the same frame by any means other than cvar_set() from the same QC VM is
+//IMPLEMENTATION DEFINED (an implementation may either yield the previous, or
+//the current, value). Changing them via cvar_set() in the same QC VM
+//immediately must reflect on the autocvar globals. Whether autocvar globals,
+//after restoring a savegame, have the cvar's current value, or the original
+//value at time of saving, is UNDEFINED. Restoring a savegame however must not
+//restore the cvar values themselves.
+//In case the cvar does NOT exist, then it is automatically created with the
+//value of the autocvar initializer, if given. This is possible with e.g.
+//frikqcc and fteqcc the following way:
+// var float autocvar_whatever = 42;
+//If no initializer is given, the cvar will be initialized to a string
+//equivalent to the NULL value of the given data type, that is, the empty
+//string, 0, or '0 0 0'. However, when automatic cvar creation took place, a
+//warning is printed to the game console.
+//NOTE: to prevent an ambiguity with float names for vector types, autocvar
+//names MUST NOT end with _x, _y or _z!
+
+//DP_QC_CHANGEPITCH
+//idea: id Software
+//darkplaces implementation: id Software
+//field definitions:
+.float idealpitch;
+.float pitch_speed;
+//builtin definitions:
+void(entity ent) changepitch = #63;
+//description:
+//equivalent to changeyaw, ent is normally self. (this was a Q2 builtin)
+
+//DP_QC_COPYENTITY
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(entity from, entity to) copyentity = #400;
+//description:
+//copies all data in the entity to another entity.
+
+//DP_QC_CRC16
+//idea: divVerent
+//darkplaces implementation: divVerent
+//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
+//When caseinsensitive is set, the CRC is calculated of the lower cased string.
+float(float caseinsensitive, string s, ...) crc16 = #494;
+
+//DP_QC_CVAR_DEFSTRING
+//idea: id Software (Doom3), LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+string(string s) cvar_defstring = #482;
+//description:
+//returns the default value of a cvar, as a tempstring.
+
+//DP_QC_CVAR_DESCRIPTION
+//idea: divVerent
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string name) cvar_description = #518;
+//description:
+//returns the description of a cvar
+
+//DP_QC_CVAR_STRING
+//idea: VorteX
+//DarkPlaces implementation: VorteX, LordHavoc
+//builtin definitions:
+string(string s) cvar_string = #448;
+//description:
+//returns the value of a cvar, as a tempstring.
+
+//DP_QC_CVAR_TYPE
+//idea: divVerent
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+float(string name) cvar_type = #495;
+float CVAR_TYPEFLAG_EXISTS = 1;
+float CVAR_TYPEFLAG_SAVED = 2;
+float CVAR_TYPEFLAG_PRIVATE = 4;
+float CVAR_TYPEFLAG_ENGINE = 8;
+float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
+float CVAR_TYPEFLAG_READONLY = 32;
+
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
+
+//DP_QC_DIGEST_SHA256
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//description:
+//"SHA256" is also an allowed digest type
+
+//DP_QC_EDICT_NUM
+//idea: 515
+//DarkPlaces implementation: LordHavoc
+//builtin definitions:
+entity(float entnum) edict_num = #459;
+float(entity ent) wasfreed = #353; // same as in EXT_CSQC extension
+//description:
+//edict_num returns the entity corresponding to a given number, this works even for freed entities, but you should call wasfreed(ent) to see if is currently active.
+//wasfreed returns whether an entity slot is currently free (entities that have never spawned are free, entities that have had remove called on them are also free).
+
+//DP_QC_ENTITYDATA
+//idea: KrimZon
+//darkplaces implementation: KrimZon
+//builtin definitions:
+float() numentityfields = #496;
+string(float fieldnum) entityfieldname = #497;
+float(float fieldnum) entityfieldtype = #498;
+string(float fieldnum, entity ent) getentityfieldstring = #499;
+float(float fieldnum, entity ent, string s) putentityfieldstring = #500;
+//constants:
+//Returned by entityfieldtype
+float FIELD_STRING = 1;
+float FIELD_FLOAT = 2;
+float FIELD_VECTOR = 3;
+float FIELD_ENTITY = 4;
+float FIELD_FUNCTION = 6;
+//description:
+//Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame.
+//WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers.
+//numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z.
+//entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever.
+//entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers.
+//getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
+//putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
+
+//DP_QC_ENTITYSTRING
+void(string s) loadfromdata = #529;
+void(string s) loadfromfile = #530;
+void(string s) callfunction = #605;
+void(float fh, entity e) writetofile = #606;
+float(string s) isfunction = #607;
+void(entity e, string s) parseentitydata = #608;
+
+//DP_QC_ETOS
+//idea: id Software
+//darkplaces implementation: id Software
+//builtin definitions:
+string(entity ent) etos = #65;
+//description:
+//prints "entity 1" or similar into a string. (this was a Q2 builtin)
+
+//DP_QC_EXTRESPONSEPACKET
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+string(void) getextresponse = #624;
+//description:
+//returns a string of the form "\"ipaddress:port\" data...", or the NULL string
+//if no packet was found. Packets can be queued into the client/server by
+//sending a packet starting with "\xFF\xFF\xFF\xFFextResponse " to the
+//listening port.
+
+//DP_QC_FINDCHAIN
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+entity(.string fld, string match) findchain = #402;
+//description:
+//similar to find() but returns a chain of entities like findradius.
+
+//DP_QC_FINDCHAIN_TOFIELD
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+entity(.string fld, float match, .entity tofield) findradius_tofield = #22;
+entity(.string fld, string match, .entity tofield) findchain_tofield = #402;
+entity(.string fld, float match, .entity tofield) findchainflags_tofield = #450;
+entity(.string fld, float match, .entity tofield) findchainfloat_tofield = #403;
+//description:
+//similar to findchain() etc, but stores the chain into .tofield instead of .chain
+//actually, the .entity tofield is an optional field of the the existing findchain* functions
+
+//DP_QC_FINDCHAINFLAGS
+//idea: Sajt
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+entity(.float fld, float match) findchainflags = #450;
+//description:
+//similar to findflags() but returns a chain of entities like findradius.
+
+//DP_QC_FINDCHAINFLOAT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+entity(.entity fld, entity match) findchainentity = #403;
+entity(.float fld, float match) findchainfloat = #403;
+//description:
+//similar to findentity()/findfloat() but returns a chain of entities like findradius.
+
+//DP_QC_FINDFLAGS
+//idea: Sajt
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+entity(entity start, .float fld, float match) findflags = #449;
+//description:
+//finds an entity with the specified flag set in the field, similar to find()
+
+//DP_QC_FINDFLOAT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+entity(entity start, .entity fld, entity match) findentity = #98;
+entity(entity start, .float fld, float match) findfloat = #98;
+//description:
+//finds an entity or float field value, similar to find(), but for entity and float fields.
+
+//DP_QC_FS_SEARCH
+//idea: Black
+//darkplaces implementation: Black
+//builtin definitions:
+float(string pattern, float caseinsensitive, float quiet) search_begin = #444;
+void(float handle) search_end = #445;
+float(float handle) search_getsize = #446;
+string(float handle, float num) search_getfilename = #447;
+//description:
+//search_begin performs a filename search with the specified pattern (for example "maps/*.bsp") and stores the results in a search slot (minimum of 128 supported by any engine with this extension), the other functions take this returned search slot number, be sure to search_free when done (they are also freed on progs reload).
+//search_end frees a search slot (also done at progs reload).
+//search_getsize returns how many filenames were found.
+//search_getfilename returns a filename from the search.
+
+//DP_QC_GETLIGHT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+vector(vector org) getlight = #92;
+//description:
+//returns the lighting at the requested location (in color), 0-255 range (can exceed 255).
+
+//DP_QC_GETSURFACE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+float(entity e, float s) getsurfacenumpoints = #434;
+vector(entity e, float s, float n) getsurfacepoint = #435;
+vector(entity e, float s) getsurfacenormal = #436;
+string(entity e, float s) getsurfacetexture = #437;
+float(entity e, vector p) getsurfacenearpoint = #438;
+vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
+//description:
+//functions to query surface information.
+
+//DP_QC_GETSURFACEPOINTATTRIBUTE
+//idea: BlackHC
+//darkplaces implementation: BlackHC
+// constants
+float SPA_POSITION = 0;
+float SPA_S_AXIS = 1;
+float SPA_T_AXIS = 2;
+float SPA_R_AXIS = 3; // same as SPA_NORMAL
+float SPA_TEXCOORDS0 = 4;
+float SPA_LIGHTMAP0_TEXCOORDS = 5;
+float SPA_LIGHTMAP0_COLOR = 6;
+//builtin definitions:
+vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
+
+//description:
+//function to query extended information about a point on a certain surface
+
+//DP_QC_GETSURFACETRIANGLE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+float(entity e, float s) getsurfacenumtriangles = #628;
+vector(entity e, float s, float n) getsurfacetriangle = #629;
+//description:
+//function to query triangles of a surface
+
+//DP_QC_GETTAGINFO
+//idea: VorteX, LordHavoc
+//DarkPlaces implementation: VorteX
+//builtin definitions:
+float(entity ent, string tagname) gettagindex = #451;
+vector(entity ent, float tagindex) gettaginfo = #452;
+//description:
+//gettagindex returns the number of a tag on an entity, this number is the same as set by setattachment (in the .tag_index field), allowing the qc to save a little cpu time by keeping the number around if it wishes (this could already be done by calling setattachment and saving off the tag_index).
+//gettaginfo returns the origin of the tag in worldspace and sets v_forward, v_right, and v_up to the current orientation of the tag in worldspace, this automatically resolves all dependencies (attachments, including viewmodelforclient), this means you could fire a shot from a tag on a gun entity attached to the view for example.
+
+//DP_QC_GETTAGINFO_BONEPROPERTIES
+//idea: daemon
+//DarkPlaces implementation: divVerent
+//global definitions:
+float gettaginfo_parent;
+string gettaginfo_name;
+vector gettaginfo_offset;
+vector gettaginfo_forward;
+vector gettaginfo_right;
+vector gettaginfo_up;
+//description:
+//when this extension is present, gettaginfo fills in some globals with info about the bone that had been queried
+//gettaginfo_parent is set to the number of the parent bone, or 0 if it is a root bone
+//gettaginfo_name is set to the name of the bone whose index had been specified in gettaginfo
+//gettaginfo_offset, gettaginfo_forward, gettaginfo_right, gettaginfo_up contain the transformation matrix of the bone relative to its parent. Note that the matrix may contain a scaling component.
+
+//DP_QC_GETTIME
+//idea: tZork
+//darkplaces implementation: tZork, divVerent
+//constant definitions:
+float GETTIME_FRAMESTART = 0; // time of start of frame relative to an arbitrary point in time
+float GETTIME_REALTIME = 1; // current absolute time (OS specific)
+float GETTIME_HIRES = 2; // like REALTIME, but may reset between QC invocations and thus can be higher precision
+float GETTIME_UPTIME = 3; // time of start of frame since start of the engine
+//builtin definitions:
+float(float tmr) gettime = #519;
+//description:
+//some timers to query...
+
+//DP_QC_GETTIME_CDTRACK
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+float GETTIME_CDTRACK = 4;
+//description:
+//returns the playing time of the current cdtrack when passed to gettime()
+//see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels
+
+//DP_QC_I18N
+//idea: divVerent
+//darkplaces implementation: divVerent
+//description:
+//
+//The engine supports translating by gettext compatible .po files.
+//progs.dat uses progs.dat.<LANGUAGE>.po
+//menu.dat uses menu.dat.<LANGUAGE>.po
+//csprogs.dat uses csprogs.dat.<LANGUAGE>.po
+//
+//To create a string that can be translated, define it as
+// string dotranslate_FILENOTFOUND = "File not found";
+//Note: if the compiler does constant folding, this will only work if there is
+//no other "File not found" string in the progs!
+//
+//Alternatively, if using the Xonotic patched fteqcc compiler, you can simplify
+//this by using _("File not found") directly in the source code.
+//
+//The language is set by the "prvm_language" cvar: if prvm_language is set to
+//"de", it will read progs.dat.de.po for translating strings in progs.dat.
+//
+//If prvm_language is set to the special name "dump", progs.dat.pot will be
+//written, which is a translation template to be edited by filling out the
+//msgstr entries.
+
+//DP_QC_LOG
+//darkplaces implementation: divVerent
+//builtin definitions:
+float log(float f) = #532;
+//description:
+//logarithm
+
+//DP_QC_MINMAXBOUND
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+float(float a, float b, ...) min = #94;
+float(float a, float b, float c) min3 = #94;
+float(float a, float b, float c, float d) min4 = #94;
+float(float a, float b, float c, float d, float e) min5 = #94;
+float(float a, float b, float c, float d, float e, float f) min6 = #94;
+float(float a, float b, float c, float d, float e, float f, float g) min7 = #94;
+float(float a, float b, float c, float d, float e, float f, float g, float h) min8 = #94;
+float(float a, float b, ...) max = #95;
+float(float a, float b, float c) max3 = #95;
+float(float a, float b, float c, float d) max4 = #95;
+float(float a, float b, float c, float d, float e) max5 = #95;
+float(float a, float b, float c, float d, float e, float f) max6 = #95;
+float(float a, float b, float c, float d, float e, float f, float g) max7 = #95;
+float(float a, float b, float c, float d, float e, float f, float g, float h) max8 = #95;
+float(float minimum, float val, float maximum) bound = #96;
+//description:
+//min returns the lowest of all the supplied numbers.
+//max returns the highest of all the supplied numbers.
+//bound clamps the value to the range and returns it.
+
+//DP_QC_MULTIPLETEMPSTRINGS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//this extension makes all builtins returning tempstrings (ftos for example)
+//cycle through a pool of multiple tempstrings (at least 16), allowing
+//multiple ftos results to be gathered before putting them to use, normal
+//quake only had 1 tempstring, causing many headaches.
+//
+//Note that for longer term storage (or compatibility on engines having
+//FRIK_FILE but not this extension) the FRIK_FILE extension's
+//strzone/strunzone builtins provide similar functionality (slower though).
+//
+//NOTE: this extension is superseded by DP_QC_UNLIMITEDTEMPSTRINGS
+
+//DP_QC_NUM_FOR_EDICT
+//idea: Blub\0
+//darkplaces implementation: Blub\0
+//Function to get the number of an entity - a clean way.
+float(entity num) num_for_edict = #512;
+
+//DP_QC_RANDOMVEC
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+vector() randomvec = #91;
+//description:
+//returns a vector of length < 1, much quicker version of this QC: do {v_x = random()*2-1;v_y = random()*2-1;v_z = random()*2-1;} while(vlen(v) > 1)
+
+//DP_QC_SINCOSSQRTPOW
+//idea: id Software, LordHavoc
+//darkplaces implementation: id Software, LordHavoc
+//builtin definitions:
+float(float val) sin = #60;
+float(float val) cos = #61;
+float(float val) sqrt = #62;
+float(float a, float b) pow = #97;
+//description:
+//useful math functions, sine of val, cosine of val, square root of val, and raise a to power b, respectively.
+
+//DP_QC_SPRINTF
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+string(string format, ...) sprintf = #627;
+//description:
+//you know sprintf :P
+//supported stuff:
+// %
+// optional: <argpos>$ for the argument to format (the arg counter then is not increased)
+// flags: #0- +
+// optional: <width>, *, or *<argpos>$ for the field width (width is read before value and precision)
+// optional: .<precision>, .*, or .*<argpos>$ for the precision (precision is read before value)
+// length modifiers: h for forcing a float, l for forcing an entity (by default, %d etc. cast a float to int), ll for forcing an int
+// conversions:
+// d takes a float if no length is specified or h is, and an entity if l is specified as length, and an int if ll is specified as length, and cast it to an int
+// i takes an entity if no length is specified or l is, and a float if h is specified as length, and an int if ll is specified as length, and cast it to an int
+// ouxXc take a float if no length is specified or h is, and an entity if l is specified as length, and an int if ll is specified as length, and cast it to an unsigned int
+// eEfFgG take a float if no length is specified or h is, and an entity if l is specified as length, and an int if ll is specified as length, and cast it to a double
+// s takes a string
+// vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space
+// For conversions s and c, the flag # makes precision and width interpreted
+// as byte count, by default it is interpreted as character count in UTF-8
+// enabled engines. No other conversions can create wide characters, and #
+// has another meaning in these. When in character count mode, color codes
+// are ignored. To get UTF-8 semantics WITHOUT color code parsing, use
+// the + flag.
+
+//DP_QC_STRFTIME
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+string(float uselocaltime, string format, ...) strftime = #478;
+//description:
+//provides the ability to get the local (in your timezone) or world (Universal Coordinated Time) time as a string using the formatting of your choice:
+//example: "%Y-%m-%d %H:%M:%S" (result looks like: 2007-02-08 01:03:15)
+//note: "%F %T" gives the same result as "%Y-%m-%d %H:%M:%S" (ISO 8601 date format and 24-hour time)
+//for more format codes please do a web search for strftime 3 and you should find the man(3) pages for this standard C function.
+//
+//practical uses:
+//changing day/night cycle (shops closing, monsters going on the prowl) in an RPG, for this you probably want to use s = strftime(TRUE, "%H");hour = stof(s);
+//printing current date/time for competitive multiplayer games, such as the beginning/end of each round in real world time.
+//activating eastereggs in singleplayer games on certain dates.
+//
+//note: some codes such as %x and %X use your locale settings and thus may not make sense to international users, it is not advisable to use these as the server and clients may be in different countries.
+//note: if you display local time to a player, it would be a good idea to note whether it is local time using a string like "%F %T (local)", and otherwise use "%F %T (UTC)".
+//note: be aware that if the game is saved and reloaded a week later the date and time will be different, so if activating eastereggs in a singleplayer game or something you may want to only check when a level is loaded and then keep the same easteregg state throughout the level so that the easteregg does not deactivate when reloading from a savegame (also be aware that precaches should not depend on such date/time code because reloading a savegame often scrambles the precaches if so!).
+//note: this function can return a NULL string (you can check for it with if (!s)) if the localtime/gmtime functions returned NULL in the engine code, such as if those functions don't work on this platform (consoles perhaps?), so be aware that this may return nothing.
+
+//DP_QC_STRINGCOLORFUNCTIONS
+//idea: Dresk
+//darkplaces implementation: Dresk
+//builtin definitions:
+float(string s) strlennocol = #476; // returns how many characters are in a string, minus color codes
+string(string s) strdecolorize = #477; // returns a string minus the color codes of the string provided
+//description:
+//provides additional functionality to strings by supporting functions that isolate and identify strings with color codes
+
+//DP_QC_STRING_CASE_FUNCTIONS
+//idea: Dresk
+//darkplaces implementation: LordHavoc / Dresk
+//builtin definitions:
+string(string s) strtolower = #480; // returns the passed in string in pure lowercase form
+string(string s) strtoupper = #481; // returns the passed in string in pure uppercase form
+//description:
+//provides simple string uppercase and lowercase functions
+
+//DP_QC_TOKENIZEBYSEPARATOR
+//idea: Electro, SavageX, LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+float(string s, string separator1, ...) tokenizebyseparator = #479;
+//description:
+//this function returns tokens separated by any of the supplied separator strings, example:
+//numnumbers = tokenizebyseparator("10.2.3.4", ".");
+//returns 4 and the tokens are "10" "2" "3" "4"
+//possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000")
+
+//DP_QC_TOKENIZE_CONSOLE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+float(string s) tokenize_console = #514;
+float(float i) argv_start_index = #515;
+float(float i) argv_end_index = #516;
+//description:
+//this function returns tokens separated just like the console does
+//also, functions are provided to get the index of the first and last character of each token in the original string
+//Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token.
+
+//DP_QC_TRACEBOX
+//idea: id Software
+//darkplaces implementation: id Software
+//builtin definitions:
+void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox = #90;
+//description:
+//similar to traceline but much more useful, traces a box of the size specified (technical note: in quake1 and halflife bsp maps the mins and maxs will be rounded up to one of the hull sizes, quake3 bsp does not have this problem, this is the case with normal moving entities as well).
+
+//DP_QC_TRACETOSS
+//idea: id Software
+//darkplaces implementation: id Software
+//builtin definitions:
+void(entity ent, entity ignore) tracetoss = #64;
+//description:
+//simulates movement of the entity as if it is MOVETYPE_TOSS and starting with it's current state (location, velocity, etc), returns relevant trace_ variables (trace_fraction is always 0, all other values are supported - trace_ent, trace_endpos, trace_plane_normal), does not actually alter the entity.
+
+//DP_QC_TRACE_MOVETYPE_HITMODEL
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//constant definitions:
+float MOVE_HITMODEL = 4;
+//description:
+//allows traces to hit alias models (not sprites!) instead of entity boxes, use as the nomonsters parameter to trace functions, note that you can hit invisible model entities (alpha < 0 or EF_NODRAW or model "", it only checks modelindex)
+
+//DP_QC_TRACE_MOVETYPE_WORLDONLY
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//constant definitions:
+float MOVE_WORLDONLY = 3;
+//description:
+//allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions
+
+//DP_QC_UNLIMITEDTEMPSTRINGS
+//idea: divVerent
+//darkplaces implementation: LordHavoc
+//description:
+//this extension alters Quake behavior such that instead of reusing a single
+//tempstring (or multiple) there are an unlimited number of tempstrings, which
+//are removed only when a QC function invoked by the engine returns,
+//eliminating almost all imaginable concerns with string handling in QuakeC.
+//
+//in short:
+//you can now use and abuse tempstrings as much as you like, you still have to
+//use strzone (FRIK_FILE) for permanent storage however.
+//
+//
+//
+//implementation notes for other engine coders:
+//these tempstrings are expected to be stored in a contiguous buffer in memory
+//which may be fixed size or controlled by a cvar, or automatically grown on
+//demand (in the case of DarkPlaces).
+//
+//this concept is similar to quake's Zone system, however these are all freed
+//when the QC interpreter returns.
+//
+//this is basically a poor man's garbage collection system for strings.
+
+//DP_QC_VECTOANGLES_WITH_ROLL
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+vector(vector forward, vector up) vectoangles2 = #51; // same number as vectoangles
+//description:
+//variant of vectoangles that takes an up vector to calculate roll angle (also uses this to calculate yaw correctly if the forward is straight up or straight down)
+//note: just like normal vectoangles you need to negate the pitch of the returned angles if you want to feed them to makevectors or assign to self.v_angle
+
+//DP_QC_VECTORVECTORS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector dir) vectorvectors = #432;
+//description:
+//creates v_forward, v_right, and v_up vectors given a forward vector, similar to makevectors except it takes a forward direction vector instead of angles.
+
+//DP_QC_WHICHPACK
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+string(string filename) whichpack = #503;
+//description:
+//for files in a pak/pk3/whatever, returns the pack's file name in FRIK_FILE name space.
+//for physical files, returns "".
+//in case of error, returns string_null.
+
+//DP_QC_URI_ESCAPE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//URI::Escape's functionality
+string(string in) uri_escape = #510;
+string(string in) uri_unescape = #511;
+
+//DP_QC_URI_GET
+//idea: divVerent
+//darkplaces implementation: divVerent
+//loads text from an URL into a string
+//returns 1 on success of initiation, 0 if there are too many concurrent
+//connections already or if the URL is invalid
+//the following callback will receive the data and MUST exist!
+// void(float id, float status, string data) URI_Get_Callback;
+//status is either
+// negative for an internal error,
+// 0 for success, or
+// the HTTP response code on server error (e.g. 404)
+//if 1 is returned by uri_get, the callback will be called in the future
+float(string url, float id) uri_get = #513;
+
+//DP_QC_URI_POST
+//idea: divVerent
+//darkplaces implementation: divVerent
+//loads text from an URL into a string after POSTing via HTTP
+//works like uri_get, but uri_post sends data with Content-Type: content_type to the server
+//and uri_post sends the string buffer buf, joined using the delimiter delim
+float(string url, float id, string content_type, string data) uri_post = #513;
+float(string url, float id, string content_type, string delim, float buf) uri_postbuf = #513;
+
+//DP_SKELETONOBJECTS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//this extension indicates that FTE_CSQC_SKELETONOBJECTS functionality is available in server QC (as well as CSQC).
+
+//DP_SV_SPAWNFUNC_PREFIX
+//idea: divVerent
+//darkplaces implementation: divVerent
+//Make functions whose name start with spawnfunc_ take precedence as spawn function for loading entities.
+//Useful if you have a field ammo_shells (required in any Quake mod) but want to support spawn functions called ammo_shells (like in Q3A).
+//Optionally, you can declare a global "float require_spawnfunc_prefix;" which will require ANY spawn function to start with that prefix.
+
+
+//DP_QUAKE2_MODEL
+//idea: quake community
+//darkplaces implementation: LordHavoc
+//description:
+//shows that the engine supports Quake2 .md2 files.
+
+//DP_QUAKE2_SPRITE
+//idea: LordHavoc
+//darkplaces implementation: Elric
+//description:
+//shows that the engine supports Quake2 .sp2 files.
+
+//DP_QUAKE3_MAP
+//idea: quake community
+//darkplaces implementation: LordHavoc
+//description:
+//shows that the engine supports Quake3 .bsp files.
+
+//DP_QUAKE3_MODEL
+//idea: quake community
+//darkplaces implementation: LordHavoc
+//description:
+//shows that the engine supports Quake3 .md3 files.
+
+//DP_REGISTERCVAR
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+float(string name, string value) registercvar = #93;
+//description:
+//adds a new console cvar to the server console (in singleplayer this is the player's console), the cvar exists until the mod is unloaded or the game quits.
+//NOTE: DP_CON_SET is much better.
+
+//DP_SND_DIRECTIONLESSATTNNONE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//make sounds with ATTN_NONE have no spatialization (enabling easy use as music sources).
+
+//DP_SND_FAKETRACKS
+//idea: requested
+
+//darkplaces implementation: Elric
+//description:
+//the engine plays sound/cdtracks/track001.wav instead of cd track 1 and so on if found, this allows games and mods to have music tracks without using ambientsound.
+//Note: also plays .ogg with DP_SND_OGGVORBIS extension.
+
+//DP_SND_SOUND7_WIP1
+//DP_SND_SOUND7_WIP2
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8;
+float SOUNDFLAG_RELIABLE = 1;
+//description:
+//plays a sound, with some more flags
+//extensions to sound():
+//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto",
+// i.e. support multiple sounds at once, but cannot be stopped/restarted
+//- a value 0 in the speed parameter means no change; otherwise, it is a
+// percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is
+// half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2)
+//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send
+// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default);
+// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE
+//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by
+// snd_channel1volume, etc. (so, a channel shares the cvar with its respective
+// auto-channel); however, the mod MUST define snd_channel8volume and upwards
+// in default.cfg if they are to be used, as the engine does not create them
+// to not litter the cvar list
+//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and
+// flags as extra 7th and 8th argument
+//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP
+//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support
+// the finished extension once done
+
+//DP_SND_OGGVORBIS
+//idea: Transfusion
+//darkplaces implementation: Elric
+//description:
+//the engine supports loading Ogg Vorbis sound files. Use either the .ogg filename directly, or a .wav of the same name (will try to load the .wav first and then .ogg).
+
+//DP_SND_STEREOWAV
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//the engine supports stereo WAV files. (useful with DP_SND_DIRECTIONLESSATTNNONE for music)
+
+//DP_SND_GETSOUNDTIME
+//idea: VorteX
+//darkplaces implementation: VorteX
+//constant definitions:
+float(entity e, float channel) getsoundtime = #533; // get currently sound playing position on entity channel, -1 if not playing or error
+float(string sample) soundlength = #534; // returns length of sound sample in seconds, -1 on error (sound not precached, sound system not initialized etc.)
+//description: provides opportunity to query length of sound samples and realtime tracking of sound playing on entities (similar to DP_GETTIME_CDTRACK)
+//note: beware dedicated server not running sound engine at all, so in dedicated mode this builtins will not work in server progs
+//note also: menu progs not supporting getsoundtime() (will give a warning) since it has no sound playing on entities
+//examples of use:
+// - QC-driven looped sounds
+// - QC events when sound playing is finished
+// - toggleable ambientsounds
+// - subtitles
+
+//DP_VIDEO_DPV
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//console commands:
+// playvideo <videoname> - start playing video
+// stopvideo - stops current video
+//description: indicated that engine support playing videos in DPV format
+
+//DP_VIDEO_SUBTITLES
+//idea: VorteX
+//darkplaces implementation: VorteX
+//cvars:
+// cl_video_subtitles - toggles subtitles showing
+// cl_video_subtitles_lines - how many lines to reserve for subtitles
+// cl_video_subtitles_textsize - font size
+//console commands:
+// playvideo <videoname> <custom_subtitles_file> - start playing video
+// stopvideo - stops current video
+//description: indicates that engine support subtitles on videos
+//subtitles stored in external text files, each video file has it's default subtitles file ( <videoname>.dpsubs )
+//example: for video/act1.dpv default subtitles file will be video/act1.dpsubs
+//also video could be played with custom subtitles file by utilizing second parm of playvideo command
+//syntax of .dpsubs files: each line in .dpsubs file defines 1 subtitle, there are three tokens:
+// <start> <end> "string"
+// start: subtitle start time in seconds
+// end: subtitle time-to-show in seconds, if 0 - subtitle will be showed until next subtitle is started,
+// if below 0 - show until next subtitles minus this number of seconds
+// text: subtitle text, color codes (Q3-style and ^xRGB) are allowed
+//example of subtitle file:
+// 3 0 "Vengeance! Vengeance for my eternity of suffering!"
+// 9 0 "Whelp! As if you knew what eternity was!"
+// 13 0 "Grovel before your true master."
+// 17 0 "Never!"
+// 18 7 "I'll hack you from crotch to gizzard and feed what's left of you to your brides..."
+
+//DP_SOLIDCORPSE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//solid definitions:
+float SOLID_CORPSE = 5;
+//description:
+//the entity will not collide with SOLID_CORPSE and SOLID_SLIDEBOX entities (and likewise they will not collide with it), this is useful if you want dead bodies that are shootable but do not obstruct movement by players and monsters, note that if you traceline with a SOLID_SLIDEBOX entity as the ignoreent, it will ignore SOLID_CORPSE entities, this is desirable for visibility and movement traces, but not for bullets, for the traceline to hit SOLID_CORPSE you must temporarily force the player (or whatever) to SOLID_BBOX and then restore to SOLID_SLIDEBOX after the traceline.
+
+//DP_SPRITE32
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//the engine supports .spr32 sprites.
+
+//DP_SV_BOTCLIENT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//constants:
+float CLIENTTYPE_DISCONNECTED = 0;
+float CLIENTTYPE_REAL = 1;
+float CLIENTTYPE_BOT = 2;
+float CLIENTTYPE_NOTACLIENT = 3;
+//builtin definitions:
+entity() spawnclient = #454; // like spawn but for client slots (also calls relevant connect/spawn functions), returns world if no clients available
+float(entity clent) clienttype = #455; // returns one of the CLIENTTYPE_* constants
+//description:
+//spawns a client with no network connection, to allow bots to use client slots with no hacks.
+//How to use:
+/*
+ // to spawn a bot
+ local entity oldself;
+ oldself = self;
+ self = spawnclient();
+ if (!self)
+ {
+ bprint("Can not add bot, server full.\n");
+ self = oldself;
+ return;
+ }
+ self.netname = "Yoyobot";
+ self.clientcolors = 12 * 16 + 4; // yellow (12) shirt and red (4) pants
+ ClientConnect();
+ PutClientInServer();
+ self = oldself;
+
+ // to remove all bots
+ local entity head;
+ head = find(world, classname, "player");
+ while (head)
+ {
+ if (clienttype(head) == CLIENTTYPE_BOT)
+ dropclient(head);
+ head = find(head, classname, "player");
+ }
+
+ // to identify if a client is a bot (for example in PlayerPreThink)
+ if (clienttype(self) == CLIENTTYPE_BOT)
+ botthink();
+*/
+//see also DP_SV_CLIENTCOLORS DP_SV_CLIENTNAME DP_SV_DROPCLIENT
+//How it works:
+//creates a new client, calls SetNewParms and stores the parms, and returns the client.
+//this intentionally does not call SV_SendServerinfo to allow the QuakeC a chance to set the netname and clientcolors fields before actually spawning the bot by calling ClientConnect and PutClientInServer manually
+//on level change ClientConnect and PutClientInServer are called by the engine to spawn in the bot (this is why clienttype() exists to tell you on the next level what type of client this is).
+//parms work the same on bot clients as they do on real clients, and do carry from level to level
+
+//DP_SV_BOUNCEFACTOR
+//idea: divVerent
+//darkplaces implementation: divVerent
+//field definitions:
+.float bouncefactor; // velocity multiplier after a bounce
+.float bouncestop; // bounce stops if velocity to bounce plane is < bouncestop * gravity AFTER the bounce
+//description:
+//allows qc to customize MOVETYPE_BOUNCE a bit
+
+//DP_SV_CLIENTCAMERA
+//idea: LordHavoc, others
+//darkplaces implementation: Black
+//field definitions:
+.entity clientcamera; // override camera entity
+//description:
+//allows another entity to be the camera for a client, for example a remote camera, this is similar to sending svc_setview manually except that it also changes the network culling appropriately.
+
+//DP_SV_CLIENTCOLORS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float clientcolors; // colors of the client (format: pants + shirt * 16)
+//description:
+//allows qc to read and modify the client colors associated with a client entity (not particularly useful on other entities), and automatically sends out any appropriate network updates if changed
+
+//DP_SV_CLIENTNAME
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//description:
+//allows qc to modify the client's .netname, and automatically sends out any appropriate network updates if changed
+
+//DP_SV_CUSTOMIZEENTITYFORCLIENT
+//idea: LordHavoc
+//darkplaces implementation: [515] and LordHavoc
+//field definitions:
+.float() customizeentityforclient; // self = this entity, other = client entity
+//description:
+//allows qc to modify an entity before it is sent to each client, the function returns TRUE if it should send, FALSE if it should not, and is fully capable of editing the entity's fields, this allows cloaked players to appear less transparent to their teammates, navigation markers to only show to their team, etc
+//tips on writing customize functions:
+//it is a good idea to return FALSE early in the function if possible to reduce cpu usage, because this function may be called many thousands of times per frame if there are many customized entities on a 64+ player server.
+//you are free to change anything in self, but please do not change any other entities (the results may be very inconsistent).
+//example ideas for use of this extension:
+//making icons over teammates' heads which are only visible to teammates. for exasmple: float() playericon_customizeentityforclient = {return self.owner.team == other.team;};
+//making cloaked players more visible to their teammates than their enemies. for example: float() player_customizeentityforclient = {if (self.items & IT_CLOAKING) {if (self.team == other.team) self.alpha = 0.6;else self.alpha = 0.1;} return TRUE;};
+//making explosion models that face the viewer (does not work well with chase_active). for example: float() explosion_customizeentityforclient = {self.angles = vectoangles(other.origin + other.view_ofs - self.origin);self.angles_x = 0 - self.angles_x;};
+//implementation notes:
+//entity customization is done before per-client culling (visibility for instance) because the entity may be doing setorigin to display itself in different locations on different clients, may be altering its .modelindex, .effects and other fields important to culling, so customized entities increase cpu usage (non-customized entities can use all the early culling they want however, as they are not changing on a per client basis).
+
+//DP_SV_DISCARDABLEDEMO
+//idea: parasti
+//darkplaces implementation: parasti
+//field definitions:
+.float discardabledemo;
+//description:
+//when this field is set to a non-zero value on a player entity, a possibly recorded server-side demo for the player is discarded
+//Note that this extension only works if:
+// auto demos are enabled (the cvar sv_autodemo_perclient is set)
+// discarding demos is enabled (the cvar sv_autodemo_perclient_discardable is set)
+
+//DP_SV_DRAWONLYTOCLIENT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.entity drawonlytoclient;
+//description:
+//the entity is only visible to the specified client.
+
+//DP_SV_DROPCLIENT
+//idea: FrikaC
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(entity clent) dropclient = #453;
+//description:
+//causes the server to immediately drop the client, more reliable than stuffcmd(clent, "disconnect\n"); which could be intentionally ignored by the client engine
+
+//DP_SV_EFFECT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404;
+//SVC definitions:
+//float svc_effect = #52; // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
+//float svc_effect2 = #53; // [vector] org [short] modelindex [byte] startframe [byte] framecount [byte] framerate
+//description:
+//clientside playback of simple custom sprite effects (explosion sprites, etc).
+
+//DP_SV_ENTITYCONTENTSTRANSITION
+//idea: Dresk
+//darkplaces implementation: Dresk
+//field definitions:
+.void(float nOriginalContents, float nNewContents) contentstransition;
+//description:
+//This field function, when provided, is triggered on an entity when the contents (ie. liquid / water / etc) is changed.
+//The first parameter provides the entities original contents, prior to the transition. The second parameter provides the new contents.
+//NOTE: If this field function is provided on an entity, the standard watersplash sound IS SUPPRESSED to allow for authors to create their own transition sounds.
+
+//DP_SV_MOVETYPESTEP_LANDEVENT
+//idea: Dresk
+//darkplaces implementation: Dresk
+//field definitions:
+.void(vector vImpactVelocity) movetypesteplandevent;
+//description:
+//This field function, when provided, is triggered on a MOVETYPE_STEP entity when it experiences "land event".
+// The standard engine behavior for this event is to play the sv_sound_land CVar sound.
+//The parameter provides the velocity of the entity at the time of the impact. The z value may therefore be used to calculate how "hard" the entity struck the surface.
+//NOTE: If this field function is provided on a MOVETYPE_STEP entity, the standard sv_sound_land sound IS SUPPRESSED to allow for authors to create their own feedback.
+
+//DP_SV_POINTSOUND
+//idea: Dresk
+//darkplaces implementation: Dresk
+//builtin definitions:
+void(vector origin, string sample, float volume, float attenuation) pointsound = #483;
+//description:
+//Similar to the standard QC sound function, this function takes an origin instead of an entity and omits the channel parameter.
+// This allows sounds to be played at arbitrary origins without spawning entities.
+
+//DP_SV_ONENTITYNOSPAWNFUNCTION
+//idea: Dresk
+//darkplaces implementation: Dresk
+//engine-called QC prototypes:
+//void() SV_OnEntityNoSpawnFunction;
+//description:
+// This function is called whenever an entity on the server has no spawn function, and therefore has no defined QC behavior.
+// You may as such dictate the behavior as to what happens to the entity.
+// To mimic the engine's default behavior, simply call remove(self).
+
+//DP_SV_ONENTITYPREPOSTSPAWNFUNCTION
+//idea: divVerent
+//darkplaces implementation: divVerent
+//engine-called QC prototypes:
+//void() SV_OnEntityPreSpawnFunction;
+//void() SV_OnEntityPostSpawnFunction;
+//description:
+// These functions are called BEFORE or AFTER an entity is spawned the regular way.
+// You may as such dictate the behavior as to what happens to the entity.
+// SV_OnEntityPreSpawnFunction is called before even looking for the spawn function, so you can even change its classname in there. If it remove()s the entity, the spawn function will not be looked for.
+// SV_OnEntityPostSpawnFunction is called ONLY after its spawn function or SV_OnEntityNoSpawnFunction was called, and skipped if the entity got removed by either.
+
+//DP_SV_MODELFLAGS_AS_EFFECTS
+//idea: LordHavoc, Dresk
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float modelflags;
+//constant definitions:
+float EF_NOMODELFLAGS = 8388608; // ignore any effects in a model file and substitute your own
+float MF_ROCKET = 1; // leave a trail
+float MF_GRENADE = 2; // leave a trail
+float MF_GIB = 4; // leave a trail
+float MF_ROTATE = 8; // rotate (bonus items)
+float MF_TRACER = 16; // green split trail
+float MF_ZOMGIB = 32; // small blood trail
+float MF_TRACER2 = 64; // orange split trail
+float MF_TRACER3 = 128; // purple trail
+//description:
+//this extension allows model flags to be specified on entities so you can add a rocket trail and glow to any entity, etc.
+//setting any of these will override the flags the model already has, to disable the model's flags without supplying any of your own you must use EF_NOMODELFLAGS.
+//
+//silly example modification #1 to W_FireRocket in weapons.qc:
+//missile.effects = EF_NOMODELFLAGS; // rocket without a glow/fire trail
+//silly example modification #2 to W_FireRocket in weapons.qc:
+//missile.modelflags = MF_GIB; // leave a blood trail instead of glow/fire trail
+//
+//note: you can not combine multiple kinds of trail, only one of them will be active, you can combine MF_ROTATE and the other MF_ flags however, and using EF_NOMODELFLAGS along with these does no harm.
+//
+//note to engine coders: they are internally encoded in the protocol as extra EF_ flags (shift the values left 24 bits and send them in the protocol that way), so no protocol change was required (however 32bit effects is a protocol extension itself), within the engine they are referred to as EF_ for the 24bit shifted values.
+
+//DP_SV_NETADDRESS
+//idea: Dresk
+//darkplaces implementation: Dresk
+//field definitions:
+.string netaddress;
+//description:
+// provides the netaddress of the associated entity (ie. 127.0.0.1) and "null/botclient" if the netconnection of the entity is invalid
+
+//DP_SV_NODRAWTOCLIENT
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.entity nodrawtoclient;
+//description:
+//the entity is not visible to the specified client.
+
+//DP_SV_PING
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float ping;
+//description:
+//continuously updated field indicating client's ping (based on average of last 16 packet time differences).
+
+//DP_SV_PING_PACKETLOSS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float ping_packetloss;
+.float ping_movementloss;
+//description:
+//continuously updated field indicating client's packet loss, and movement loss (i.e. packet loss affecting player movement).
+
+//DP_SV_POINTPARTICLES
+//idea: Spike
+//darkplaces implementation: LordHavoc
+//function definitions:
+float(string effectname) particleeffectnum = #335; // same as in CSQC
+void(entity ent, float effectnum, vector start, vector end) trailparticles = #336; // same as in CSQC
+void(float effectnum, vector org, vector vel, float howmany) pointparticles = #337; // same as in CSQC
+//SVC definitions:
+//float svc_trailparticles = 60; // [short] entnum [short] effectnum [vector] start [vector] end
+//float svc_pointparticles = 61; // [short] effectnum [vector] start [vector] velocity [short] count
+//float svc_pointparticles1 = 62; // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1
+//description:
+//provides the ability to spawn non-standard particle effects, typically these are defined in a particle effect information file such as effectinfo.txt in darkplaces.
+//this is a port of particle effect features from clientside QC (EXT_CSQC) to server QC, as these effects are potentially useful to all games even if they do not make use of EXT_CSQC.
+//warning: server must have same order of effects in effectinfo.txt as client does or the numbers would not match up, except for standard quake effects which are always the same numbers.
+
+//DP_SV_PUNCHVECTOR
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.vector punchvector;
+//description:
+//offsets client view in worldspace, similar to view_ofs but all 3 components are used and are sent with at least 8 bits of fraction, this allows the view to be kicked around by damage or hard landings or whatever else, note that unlike punchangle this is not faded over time, it is up to the mod to fade it (see also DP_SV_PLAYERPHYSICS).
+
+//DP_SV_PLAYERPHYSICS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.vector movement;
+//cvar definitions:
+//"sv_playerphysicsqc" (0/1, default 1, allows user to disable qc player physics)
+//engine-called QC prototypes:
+//void() SV_PlayerPhysics;
+//description:
+//.movement vector contains the movement input from the player, allowing QC to do as it wishs with the input, and SV_PlayerPhysics will completely replace the player physics if present (works for all MOVETYPE's), see darkplaces mod source for example of this function (in playermovement.qc, adds HalfLife ladders support, as well as acceleration/deceleration while airborn (rather than the quake sudden-stop while airborn), and simplifies the physics a bit)
+
+//DP_PHYSICS_ODE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//globals:
+//new movetypes:
+const float MOVETYPE_PHYSICS = 32; // need to be set before any physics_* builtins applied
+//new solid types (deprecated):
+const float SOLID_PHYSICS_BOX = 32;
+const float SOLID_PHYSICS_SPHERE = 33;
+const float SOLID_PHYSICS_CAPSULE = 34;
+const float SOLID_PHYSICS_TRIMESH = 35;
+const float SOLID_PHYSICS_CYLINDER = 36;
+//geometry types:
+const float GEOMTYPE_NONE = -1; // entity will be entirely skipped by ODE
+const float GEOMTYPE_SOLID = 0; // geometry type will be set based on .solid field
+const float GEOMTYPE_BOX = 1; // entity bound box
+const float GEOMTYPE_SPHERE = 2; // sphere with radius picked from x axis of entity bound box
+const float GEOMTYPE_CAPSULE = 3; // with leading axis automatically determined from longest one, radius is picked as minimal of the rest 2 axes
+const float GEOMTYPE_TRIMESH = 4; // triangle mesh
+const float GEOMTYPE_CYLINDER = 5; // like capsule but not capped
+ // note that ODE's builtin cylinder support is experimental, somewhat bugged and unfinished (no cylinder-cylinder collision)
+ // to use properly working cylinder should build ODE with LIBCCD extension
+const float GEOMTYPE_CAPSULE_X = 6; // capsule with fixed leading axis
+const float GEOMTYPE_CAPSULE_Y = 7;
+const float GEOMTYPE_CAPSULE_Z = 8;
+const float GEOMTYPE_CYLINDER_X = 9; // cylinder with fixed leading axis
+const float GEOMTYPE_CYLINDER_Y = 10;
+const float GEOMTYPE_CYLINDER_Z = 11;
+//joint types:
+const float JOINTTYPE_NONE = 0;
+const float JOINTTYPE_POINT = 1;
+const float JOINTTYPE_HINGE = 2;
+const float JOINTTYPE_SLIDER = 3;
+const float JOINTTYPE_UNIVERSAL = 4;
+const float JOINTTYPE_HINGE2 = 5;
+const float JOINTTYPE_FIXED = -1;
+//force types:
+const float FORCETYPE_NONE = 0;
+const float FORCETYPE_FORCE = 1; // applied at center of mass
+const float FORCETYPE_FORCEATPOS = 2;
+const float FORCETYPE_TORQUE = 3;
+// common joint properties:
+// .entity aiment; // connected objects
+// .entity enemy; // connected objects, forces
+// .vector movedir;
+// for a spring:
+// movedir_x = spring constant (force multiplier, must be > 0)
+// movedir_y = spring dampening constant to prevent oscillation (must be > 0)
+// movedir_z = spring stop position (+/-)
+// for a motor:
+// movedir_x = desired motor velocity
+// movedir_y = -1 * max motor force to use
+// movedir_z = stop position (+/-), set to 0 for no stop
+// note that ODE does not support both in one anyway
+// for a force:
+// force vector to apply
+//field definitions:
+.float geomtype; // see GEOMTYPE_*, a more correct way to set collision shape, allows to set SOLID_CORPSE and trimesh collisions
+.float maxcontacts; // maximum number of contacts to make for this object, lesser = faster (but setting it too low will could make object pass though walls), default is 16, maximum is 32
+.float mass; // ODE mass, standart value is 1
+.vector massofs; // offsets a mass center out of object center, if not set a center of model bounds is used
+.float friction; // a friction of object, get multiplied by second objects's friction on contact
+.float bouncefactor;
+.float bouncestop;
+.float jointtype; // type of joint
+.float forcetype; // type of force
+.float erp; // error restitution parameter, makes ODE solver attempt to fix errors in contacts,
+ // bringing together 2 joints or fixing object being stuch in other object,
+ // a value of 0.1 will fix slightly, a value of 1.0 attempts to fix whole error in one frame
+ // use with care as high values makes system unstable and likely to explode
+//builtin definitions:
+void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object
+void(entity e, vector force, vector force_pos) physics_addforce = #541; // deprecated, apply a force from certain origin, length of force vector is power of force
+void(entity e, vector torque) physics_addtorque = #542; // deprecated, add relative torque
+//description: provides Open Dynamics Engine support, requires extenal dll to be present or engine compiled with statical link option
+//be sure to checkextension for it to know if library is loaded and ready, also to enable physics set "physics_ode" cvar to 1
+//note: this extension is highly experimental and may be unstable
+
+//DP_SV_PRINT
+//idea: id Software (QuakeWorld Server)
+//darkplaces implementation: Black, LordHavoc
+void(string s, ...) print = #339; // same number as in EXT_CSQC
+//description:
+//this is identical to dprint except that it always prints regardless of the developer cvar.
+
+//DP_SV_PRECACHEANYTIME
+//idea: id Software (Quake2)
+//darkplaces implementation: LordHavoc
+//description:
+//this extension allows precache_model and precache_sound (and any variants) to be used during the game (with automatic messages to clients to precache the new model/sound indices), also setmodel/sound/ambientsound can be called without precaching first (they will cause an automatic precache).
+
+//DP_SV_QCSTATUS
+//idea: divVerent
+//darkplaces implementation: divVerent
+//1. A global variable
+string worldstatus;
+//Its content is set as "qcstatus" field in the rules.
+//It may be at most 255 characters, and must not contain newlines or backslashes.
+//2. A per-client field
+.string clientstatus;
+//It is sent instead of the "frags" in status responses.
+//It should always be set in a way so that stof(player.clientstatus) is a meaningful score value. Other info may be appended. If used this way, the cvar sv_status_use_qcstatus may be set to 1, and then this value will replace the frags in "status".
+//Currently, qstat does not support this and will not show player info if used and set to anything other than ftos(some integer).
+
+//DP_SV_ROTATINGBMODEL
+//idea: id Software
+//darkplaces implementation: LordHavoc
+//description:
+//this extension merely indicates that MOVETYPE_PUSH supports avelocity, allowing rotating brush models to be created, they rotate around their origin (needs rotation supporting qbsp/light utilities because id ones expected bmodel entity origins to be '0 0 0', recommend setting "origin" key in the entity fields in the map before compiling, there may be other methods depending on your qbsp, most are more complicated however).
+//tip: level designers can create a func_wall with an origin, and avelocity (for example "avelocity" "0 90 0"), and "nextthink" "99999999" to make a rotating bmodel without any qc modifications, such entities will be solid in stock quake but will not rotate)
+
+//DP_SV_SETCOLOR
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(entity ent, float colors) setcolor = #401;
+//engine called QC functions (optional):
+//void(float color) SV_ChangeTeam;
+//description:
+//setcolor sets the color on a client and updates internal color information accordingly (equivalent to stuffing a "color" command but immediate)
+//SV_ChangeTeam is called by the engine whenever a "color" command is recieved, it may decide to do anything it pleases with the color passed by the client, including rejecting it (by doing nothing), or calling setcolor to apply it, preventing team changes is one use for this.
+//the color format is pants + shirt * 16 (0-255 potentially)
+
+//DP_SV_SLOWMO
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//cvars:
+//"slowmo" (0+, default 1)
+//description:
+//sets the time scale of the server, mainly intended for use in singleplayer by the player, however potentially useful for mods, so here's an extension for it.
+//range is 0 to infinite, recommended values to try are 0.1 (very slow, 10% speed), 1 (normal speed), 5 (500% speed).
+
+//DP_SV_WRITEPICTURE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+void(float to, string s, float sz) WritePicture = #501;
+//description:
+//writes a picture to the data stream so CSQC can read it using ReadPicture, which has the definition
+// string(void) ReadPicture = #501;
+//The picture data is sent as at most sz bytes, by compressing to low quality
+//JPEG. The data being sent will be equivalent to:
+// WriteString(to, s);
+// WriteShort(to, imagesize);
+// for(i = 0; i < imagesize; ++i)
+// WriteByte(to, [the i-th byte of the compressed JPEG image]);
+
+//DP_SV_WRITEUNTERMINATEDSTRING
+//idea: FrikaC
+//darkplaces implementation: Sajt
+//builtin definitions:
+void(float to, string s) WriteUnterminatedString = #456;
+//description:
+//like WriteString, but does not write a terminating 0 after the string. This means you can include things like a player's netname in the middle of a string sent over the network. Just be sure to end it up with either a call to WriteString (which includes the trailing 0) or WriteByte(0) to terminate it yourself.
+//A historical note: this extension was suggested by FrikaC years ago, more recently Shadowalker has been badmouthing LordHavoc and Spike for stealing 'his' extension writestring2 which does exactly the same thing but uses a different builtin number and name and extension string, this argument hinges on the idea that it was his idea in the first place, which is incorrect as FrikaC first suggested it and used a rough equivalent of it in his FrikBot mod years ago involving WriteByte calls on each character.
+
+//DP_TE_BLOOD
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org, vector velocity, float howmany) te_blood = #405;
+//temp entity definitions:
+float TE_BLOOD = 50;
+//protocol:
+//vector origin
+//byte xvelocity (-128 to +127)
+//byte yvelocity (-128 to +127)
+//byte zvelocity (-128 to +127)
+//byte count (0 to 255, how much blood)
+//description:
+//creates a blood effect.
+
+//DP_TE_BLOODSHOWER
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406;
+//temp entity definitions:
+//float TE_BLOODSHOWER = 52;
+//protocol:
+//vector mins (minimum corner of the cube)
+//vector maxs (maximum corner of the cube)
+//coord explosionspeed (velocity of blood particles flying out of the center)
+//short count (number of blood particles)
+//description:
+//creates an exploding shower of blood, for making gibbings more convincing.
+
+//DP_TE_CUSTOMFLASH
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org, float radius, float lifetime, vector color) te_customflash = #417;
+//temp entity definitions:
+//float TE_CUSTOMFLASH = 73;
+//protocol:
+//vector origin
+//byte radius ((MSG_ReadByte() + 1) * 8, meaning 8-2048 unit radius)
+//byte lifetime ((MSG_ReadByte() + 1) / 256.0, meaning approximately 0-1 second lifetime)
+//byte red (0.0 to 1.0 converted to 0-255)
+//byte green (0.0 to 1.0 converted to 0-255)
+//byte blue (0.0 to 1.0 converted to 0-255)
+//description:
+//creates a customized light flash.
+
+//DP_TE_EXPLOSIONRGB
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org, vector color) te_explosionrgb = #407;
+//temp entity definitions:
+//float TE_EXPLOSIONRGB = 53;
+//protocol:
+//vector origin
+//byte red (0.0 to 1.0 converted to 0 to 255)
+//byte green (0.0 to 1.0 converted to 0 to 255)
+//byte blue (0.0 to 1.0 converted to 0 to 255)
+//description:
+//creates a colored explosion effect.
+
+//DP_TE_FLAMEJET
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org, vector vel, float howmany) te_flamejet = #457;
+//temp entity definitions:
+//float TE_FLAMEJET = 74;
+//protocol:
+//vector origin
+//vector velocity
+//byte count (0 to 255, how many flame particles)
+//description:
+//creates a single puff of flame particles. (not very useful really)
+
+//DP_TE_PARTICLECUBE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408;
+//temp entity definitions:
+//float TE_PARTICLECUBE = 54;
+//protocol:
+//vector mins (minimum corner of the cube)
+//vector maxs (maximum corner of the cube)
+//vector velocity
+//short count
+//byte color (palette color)
+//byte gravity (TRUE or FALSE, FIXME should this be a scaler instead?)
+//coord randomvel (how much to jitter the velocity)
+//description:
+//creates a cloud of particles, useful for forcefields but quite customizable.
+
+//DP_TE_PARTICLERAIN
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409;
+//temp entity definitions:
+//float TE_PARTICLERAIN = 55;
+//protocol:
+//vector mins (minimum corner of the cube)
+//vector maxs (maximum corner of the cube)
+//vector velocity (velocity of particles)
+//short count (number of particles)
+//byte color (8bit palette color)
+//description:
+//creates a shower of rain, the rain will appear either at the top (if falling down) or bottom (if falling up) of the cube.
+
+//DP_TE_PARTICLESNOW
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410;
+//temp entity definitions:
+//float TE_PARTICLERAIN = 56;
+//protocol:
+//vector mins (minimum corner of the cube)
+//vector maxs (maximum corner of the cube)
+//vector velocity (velocity of particles)
+//short count (number of particles)
+//byte color (8bit palette color)
+//description:
+//creates a shower of snow, the snow will appear either at the top (if falling down) or bottom (if falling up) of the cube, low velocities are advisable for convincing snow.
+
+//DP_TE_PLASMABURN
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org) te_plasmaburn = #433;
+//temp entity definitions:
+//float TE_PLASMABURN = 75;
+//protocol:
+//vector origin
+//description:
+//creates a small light flash (radius 200, time 0.2) and marks the walls.
+
+//DP_TE_QUADEFFECTS1
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org) te_gunshotquad = #412;
+void(vector org) te_spikequad = #413;
+void(vector org) te_superspikequad = #414;
+void(vector org) te_explosionquad = #415;
+//temp entity definitions:
+//float TE_GUNSHOTQUAD = 57; // [vector] origin
+//float TE_SPIKEQUAD = 58; // [vector] origin
+//float TE_SUPERSPIKEQUAD = 59; // [vector] origin
+//float TE_EXPLOSIONQUAD = 70; // [vector] origin
+//protocol:
+//vector origin
+//description:
+//all of these just take a location, and are equivalent in function (but not appearance :) to the original TE_GUNSHOT, etc.
+
+//DP_TE_SMALLFLASH
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org) te_smallflash = #416;
+//temp entity definitions:
+//float TE_SMALLFLASH = 72;
+//protocol:
+//vector origin
+//description:
+//creates a small light flash (radius 200, time 0.2).
+
+//DP_TE_SPARK
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org, vector vel, float howmany) te_spark = #411;
+//temp entity definitions:
+//float TE_SPARK = 51;
+//protocol:
+//vector origin
+//byte xvelocity (-128 to 127)
+//byte yvelocity (-128 to 127)
+//byte zvelocity (-128 to 127)
+//byte count (number of sparks)
+//description:
+//creates a shower of sparks and a smoke puff.
+
+//DP_TE_STANDARDEFFECTBUILTINS
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+void(vector org) te_gunshot = #418;
+void(vector org) te_spike = #419;
+void(vector org) te_superspike = #420;
+void(vector org) te_explosion = #421;
+void(vector org) te_tarexplosion = #422;
+void(vector org) te_wizspike = #423;
+void(vector org) te_knightspike = #424;
+void(vector org) te_lavasplash = #425;
+void(vector org) te_teleport = #426;
+void(vector org, float color, float colorlength) te_explosion2 = #427;
+void(entity own, vector start, vector end) te_lightning1 = #428;
+void(entity own, vector start, vector end) te_lightning2 = #429;
+void(entity own, vector start, vector end) te_lightning3 = #430;
+void(entity own, vector start, vector end) te_beam = #431;
+//description:
+//to make life easier on mod coders.
+
+//DP_TRACE_HITCONTENTSMASK_SURFACEINFO
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//globals:
+.float dphitcontentsmask; // if non-zero on the entity passed to traceline/tracebox/tracetoss this will override the normal collidable contents rules and instead hit these contents values (for example AI can use tracelines that hit DONOTENTER if it wants to, by simply changing this field on the entity passed to traceline), this affects normal movement as well as trace calls
+float trace_dpstartcontents; // DPCONTENTS_ value at start position of trace
+float trace_dphitcontents; // DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit)
+float trace_dphitq3surfaceflags; // Q3SURFACEFLAG_ value of impacted surface
+string trace_dphittexturename; // texture name of impacted surface
+//constants:
+float DPCONTENTS_SOLID = 1; // hit a bmodel, not a bounding box
+float DPCONTENTS_WATER = 2;
+float DPCONTENTS_SLIME = 4;
+float DPCONTENTS_LAVA = 8;
+float DPCONTENTS_SKY = 16;
+float DPCONTENTS_BODY = 32; // hit a bounding box, not a bmodel
+float DPCONTENTS_CORPSE = 64; // hit a SOLID_CORPSE entity
+float DPCONTENTS_NODROP = 128; // an area where backpacks should not spawn
+float DPCONTENTS_PLAYERCLIP = 256; // blocks player movement
+float DPCONTENTS_MONSTERCLIP = 512; // blocks monster movement
+float DPCONTENTS_DONOTENTER = 1024; // AI hint brush
+float DPCONTENTS_LIQUIDSMASK = 14; // WATER | SLIME | LAVA
+float DPCONTENTS_BOTCLIP = 2048; // AI hint brush
+float DPCONTENTS_OPAQUE = 4096; // only fully opaque brushes get this (may be useful for line of sight checks)
+float Q3SURFACEFLAG_NODAMAGE = 1;
+float Q3SURFACEFLAG_SLICK = 2; // low friction surface
+float Q3SURFACEFLAG_SKY = 4; // sky surface (also has NOIMPACT and NOMARKS set)
+float Q3SURFACEFLAG_LADDER = 8; // climbable surface
+float Q3SURFACEFLAG_NOIMPACT = 16; // projectiles should remove themselves on impact (this is set on sky)
+float Q3SURFACEFLAG_NOMARKS = 32; // projectiles should not leave marks, such as decals (this is set on sky)
+float Q3SURFACEFLAG_FLESH = 64; // projectiles should do a fleshy effect (blood?) on impact
+float Q3SURFACEFLAG_NODRAW = 128; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_HINT = 256; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_SKIP = 512; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_NOLIGHTMAP = 1024; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_POINTLIGHT = 2048; // compiler hint (not important to qc)
+float Q3SURFACEFLAG_METALSTEPS = 4096; // walking on this surface should make metal step sounds
+float Q3SURFACEFLAG_NOSTEPS = 8192; // walking on this surface should not make footstep sounds
+float Q3SURFACEFLAG_NONSOLID = 16384; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_LIGHTFILTER = 32768; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_ALPHASHADOW = 65536; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_NODLIGHT = 131072; // compiler hint (not important to qc)
+//float Q3SURFACEFLAG_DUST = 262144; // translucent 'light beam' effect (not important to qc)
+//description:
+//adds additional information after a traceline/tracebox/tracetoss call.
+//also (very important) sets trace_* globals before calling .touch functions,
+//this allows them to inspect the nature of the collision (for example
+//determining if a projectile hit sky), clears trace_* variables for the other
+//object in a touch event (that is to say, a projectile moving will see the
+//trace results in its .touch function, but the player it hit will see very
+//little information in the trace_ variables as it was not moving at the time)
+
+//DP_VIEWZOOM
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float viewzoom;
+//description:
+//scales fov and sensitivity of player, valid range is 0 to 1 (intended for sniper rifle zooming, and such)
+
+//EXT_BITSHIFT
+//idea: Spike
+//darkplaces implementation: [515]
+//builtin definitions:
+float(float number, float quantity) bitshift = #218;
+//description:
+//multiplies number by a power of 2 corresponding to quantity (0 = *1, 1 = *2, 2 = *4, 3 = *8, -1 = /2, -2 = /4x, etc), and rounds down (due to integer math) like other bit operations do (& and | and the like).
+//note: it is faster to use multiply if you are shifting by a constant, avoiding the quakec function call cost, however that does not do a floor for you.
+
+//FRIK_FILE
+//idea: FrikaC
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+float(string s) stof = #81; // get numerical value from a string
+float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
+void(float fhandle) fclose = #111; // closes a file
+string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
+void(float fhandle, string s, ...) fputs = #113; // writes a line of text to the end of the file
+float(string s) strlen = #114; // returns how many characters are in a string
+string(string s1, string s2, ...) strcat = #115; // concatenates two or more strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
+string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring - see FTE_STRINGS for enhanced version
+vector(string s) stov = #117; // returns vector value from a string
+string(string s, ...) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
+void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
+//constants:
+float FILE_READ = 0;
+float FILE_APPEND = 1;
+float FILE_WRITE = 2;
+//cvars:
+//pr_zone_min_strings : default 64 (64k), min 64 (64k), max 8192 (8mb)
+//description:
+//provides text file access functions and string manipulation functions, note that you may want to set pr_zone_min_strings in the worldspawn function if 64k is not enough string zone space.
+//
+//NOTE: strzone functionality is partially superseded by
+//DP_QC_UNLIMITEDTEMPSTRINGS when longterm storage is not needed
+//NOTE: substring is upgraded by FTE_STRINGS extension with negative start/length handling identical to php 5.2.0
+
+//FTE_CSQC_SKELETONOBJECTS
+//idea: Spike, LordHavoc
+//darkplaces implementation: LordHavoc
+//builtin definitions:
+// all skeleton numbers are 1-based (0 being no skeleton)
+// all bone numbers are 1-based (0 being invalid)
+float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model.
+float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
+float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist
+string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist
+float(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
+float(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity
+vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
+vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
+void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
+void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
+void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
+float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found
+float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
+//fields:
+.float skeletonindex; // active skeleton overriding standard animation on model
+.float frame; // primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
+.float frame2; // secondary framegroup animation (strength = lerpfrac)
+.float frame3; // tertiary framegroup animation (strength = lerpfrac3)
+.float frame4; // quaternary framegroup animation (strength = lerpfrac4)
+.float lerpfrac; // strength of framegroup blend
+.float lerpfrac3; // strength of framegroup blend
+.float lerpfrac4; // strength of framegroup blend
+.float frame1time; // start time of framegroup animation
+.float frame2time; // start time of framegroup animation
+.float frame3time; // start time of framegroup animation
+.float frame4time; // start time of framegroup animation
+//description:
+//this extension provides a way to do complex skeletal animation on an entity.
+//
+//see also DP_SKELETONOBJECTS (this extension implemented on server as well as client)
+//
+//notes:
+//each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render).
+//each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files).
+//if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton.
+//proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose.
+//
+//features include:
+//multiple animations blended together.
+//animating a model with animations from another model with a compatible skeleton.
+//restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head.
+//custom bone controllers - for example making eyes track a target location.
+//
+//
+//
+//example code follows...
+//
+//this helper function lets you identify (by parentage) what group a bone
+//belongs to - for example "torso", "leftarm", would return 1 ("torso") for
+//all children of the bone named "torso", unless they are children of
+//"leftarm" (which is a child of "torso") which would return 2 instead...
+float(float skel, float bonenum, string g1, string g2, string g3, string g4, string g5, string g6) example_skel_findbonegroup =
+{
+ local string bonename;
+ while (bonenum >= 0)
+ {
+ bonename = skel_get_bonename(skel, bonenum);
+ if (bonename == g1) return 1;
+ if (bonename == g2) return 2;
+ if (bonename == g3) return 3;
+ if (bonename == g4) return 4;
+ if (bonename == g5) return 5;
+ if (bonename == g6) return 6;
+ bonenum = skel_get_boneparent(skel, bonenum);
+ }
+ return 0;
+};
+// create a skeletonindex for our player using current modelindex
+void() example_skel_player_setup =
+{
+ self.skeletonindex = skel_create(self.modelindex);
+};
+// setup bones of skeleton based on an animation
+// note: animmodelindex can be a different model than self.modelindex
+void(float animmodelindex, float framegroup, float framegroupstarttime) example_skel_player_update_begin =
+{
+ // start with our standard animation
+ self.frame = framegroup;
+ self.frame2 = 0;
+ self.frame3 = 0;
+ self.frame4 = 0;
+ self.frame1time = framegroupstarttime;
+ self.frame2time = 0;
+ self.frame3time = 0;
+ self.frame4time = 0;
+ self.lerpfrac = 0;
+ self.lerpfrac3 = 0;
+ self.lerpfrac4 = 0;
+ skel_build(self.skeletonindex, self, animmodelindex, 0, 0, 100000);
+};
+// apply a different framegroup animation to bones with a specified parent
+void(float animmodelindex, float framegroup, float framegroupstarttime, float blendalpha, string groupbonename, string excludegroupname1, string excludegroupname2) example_skel_player_update_applyoverride =
+{
+ local float bonenum;
+ local float numbones;
+ self.frame = framegroup;
+ self.frame2 = 0;
+ self.frame3 = 0;
+ self.frame4 = 0;
+ self.frame1time = framegroupstarttime;
+ self.frame2time = 0;
+ self.frame3time = 0;
+ self.frame4time = 0;
+ self.lerpfrac = 0;
+ self.lerpfrac3 = 0;
+ self.lerpfrac4 = 0;
+ bonenum = 0;
+ numbones = skel_get_numbones(self.skeletonindex);
+ while (bonenum < numbones)
+ {
+ if (example_skel_findbonegroup(self.skeletonindex, bonenum, groupbonename, excludegroupname1, excludegroupname2, "", "", "") == 1)
+ skel_build(self.skeletonindex, self, animmodelindex, 1 - blendalpha, bonenum, bonenum + 1);
+ bonenum = bonenum + 1;
+ }
+};
+// make eyes point at a target location, be sure v_forward, v_right, v_up are set correctly before calling
+void(vector eyetarget, string bonename) example_skel_player_update_eyetarget =
+{
+ local float bonenum;
+ local vector ang;
+ local vector oldforward, oldright, oldup;
+ local vector relforward, relright, relup, relorg;
+ local vector boneforward, boneright, boneup, boneorg;
+ local vector parentforward, parentright, parentup, parentorg;
+ local vector u, v;
+ local vector modeleyetarget;
+ bonenum = skel_find_bone(self.skeletonindex, bonename) - 1;
+ if (bonenum < 0)
+ return;
+ oldforward = v_forward;
+ oldright = v_right;
+ oldup = v_up;
+ v = eyetarget - self.origin;
+ modeleyetarget_x = v * v_forward;
+ modeleyetarget_y = 0-v * v_right;
+ modeleyetarget_z = v * v_up;
+ // this is an eyeball, make it point at the target location
+ // first get all the data we can...
+ relorg = skel_get_bonerel(self.skeletonindex, bonenum);
+ relforward = v_forward;
+ relright = v_right;
+ relup = v_up;
+ boneorg = skel_get_boneabs(self.skeletonindex, bonenum);
+ boneforward = v_forward;
+ boneright = v_right;
+ boneup = v_up;
+ parentorg = skel_get_boneabs(self.skeletonindex, skel_get_boneparent(self.skeletonindex, bonenum));
+ parentforward = v_forward;
+ parentright = v_right;
+ parentup = v_up;
+ // get the vector from the eyeball to the target
+ u = modeleyetarget - boneorg;
+ // now transform it inversely by the parent matrix to produce new rel vectors
+ v_x = u * parentforward;
+ v_y = u * parentright;
+ v_z = u * parentup;
+ ang = vectoangles2(v, relup);
+ ang_x = 0 - ang_x;
+ makevectors(ang);
+ // set the relative bone matrix
+ skel_set_bone(self.skeletonindex, bonenum, relorg);
+ // restore caller's v_ vectors
+ v_forward = oldforward;
+ v_right = oldright;
+ v_up = oldup;
+};
+// delete skeleton when we're done with it
+// note: skeleton remains valid until next frame when it is really deleted
+void() example_skel_player_delete =
+{
+ skel_delete(self.skeletonindex);
+ self.skeletonindex = 0;
+};
+//
+// END OF EXAMPLES FOR FTE_CSQC_SKELETONOBJECTS
+//
+
+//KRIMZON_SV_PARSECLIENTCOMMAND
+//idea: KrimZon
+//darkplaces implementation: KrimZon, LordHavoc
+//engine-called QC prototypes:
+//void(string s) SV_ParseClientCommand;
+//builtin definitions:
+void(entity e, string s) clientcommand = #440;
+float(string s) tokenize = #441;
+string(float n) argv = #442;
+//description:
+//provides QC the ability to completely control server interpretation of client commands ("say" and "color" for example, clientcommand is necessary for this and substring (FRIK_FILE) is useful) as well as adding new commands (tokenize, argv, and stof (FRIK_FILE) are useful for this)), whenever a clc_stringcmd is received the QC function is called, and it is up to the QC to decide what (if anything) to do with it
+
+//NEH_CMD_PLAY2
+//idea: Nehahra
+//darkplaces implementation: LordHavoc
+//description:
+//shows that the engine supports the "play2" console command (plays a sound without spatialization).
+
+//NEH_RESTOREGAME
+//idea: Nehahra
+//darkplaces implementation: LordHavoc
+//engine-called QC prototypes:
+//void() RestoreGame;
+//description:
+//when a savegame is loaded, this function is called
+
+//NEXUIZ_PLAYERMODEL
+//idea: Nexuiz
+//darkplaces implementation: Black
+//console commands:
+//playermodel <name> - FIXME: EXAMPLE NEEDED
+//playerskin <name> - FIXME: EXAMPLE NEEDED
+//field definitions:
+.string playermodel; // name of player model sent by client
+.string playerskin; // name of player skin sent by client
+//description:
+//these client properties are used by Nexuiz.
+
+//NXQ_GFX_LETTERBOX
+//idea: nxQuake
+//darkplaces implementation: LordHavoc
+//description:
+//shows that the engine supports the "r_letterbox" console variable, set to values in the range 0-100 this restricts the view vertically (and turns off sbar and crosshair), value is a 0-100 percentage of how much to constrict the view, <=0 = normal view height, 25 = 75% of normal view height, 50 = 50%, 75 = 25%, >=100 = no view
+
+//PRYDON_CLIENTCURSOR
+//idea: FrikaC
+//darkplaces implementation: LordHavoc
+//effects bit:
+float EF_SELECTABLE = 16384; // allows cursor to highlight entity (brighten)
+//field definitions:
+.float cursor_active; // true if cl_prydoncursor mode is on
+.vector cursor_screen; // screen position of cursor as -1 to +1 in _x and _y (_z unused)
+.vector cursor_trace_start; // position of camera
+.vector cursor_trace_endpos; // position of cursor in world (as traced from camera)
+.entity cursor_trace_ent; // entity the cursor is pointing at (server forces this to world if the entity is currently free at time of receipt)
+//cvar definitions:
+//cl_prydoncursor (0/1+, default 0, 1 and above use cursors named gfx/prydoncursor%03i.lmp - or .tga and such if DP_GFX_EXTERNALTEXTURES is implemented)
+//description:
+//shows that the engine supports the cl_prydoncursor cvar, this puts a clientside mouse pointer on the screen and feeds input to the server for the QuakeC to use as it sees fit.
+//the mouse pointer triggers button4 if cursor is at left edge of screen, button5 if at right edge of screen, button6 if at top edge of screen, button7 if at bottom edge of screen.
+//the clientside trace skips transparent entities (except those marked EF_SELECTABLE).
+//the selected entity highlights only if EF_SELECTABLE is set, a typical selection method would be doubling the brightness of the entity by some means (such as colormod[] *= 2).
+//intended to be used by Prydon Gate.
+
+//TENEBRAE_GFX_DLIGHTS
+//idea: Tenebrae
+//darkplaces implementation: LordHavoc
+//fields:
+.float light_lev; // radius (does not affect brightness), typical value 350
+.vector color; // color (does not affect radius), typical value '1 1 1' (bright white), can be up to '255 255 255' (nuclear blast)
+.float style; // light style (like normal light entities, flickering torches or switchable, etc)
+.float pflags; // flags (see PFLAGS_ constants)
+.vector angles; // orientation of the light
+.float skin; // cubemap filter number, can be 1-255 (0 is assumed to be none, and tenebrae only allows 16-255), this selects a projective light filter, a value of 1 loads cubemaps/1posx.tga and cubemaps/1negx.tga and posy, negy, posz, and negz, similar to skybox but some sides need to be rotated or flipped
+//constants:
+float PFLAGS_NOSHADOW = 1; // light does not cast shadows
+float PFLAGS_CORONA = 2; // light has a corona flare
+float PFLAGS_FULLDYNAMIC = 128; // light enable (without this set no light is produced!)
+//description:
+//more powerful dynamic light settings
+//warning: it is best not to use cubemaps on a light entity that has a model, as using a skin number that a model does not have will cause issues in glquake, and produce warnings in darkplaces (use developer 1 to see them)
+//changes compared to tenebrae (because they're too 'leet' for standards):
+//note: networking should send entities with PFLAGS_FULLDYNAMIC set even if they have no model (lights in general do not have a model, nor should they)
+//EF_FULLDYNAMIC effects flag replaced by PFLAGS_FULLDYNAMIC flag (EF_FULLDYNAMIC conflicts with EF_NODRAW)
+
+//TW_SV_STEPCONTROL
+//idea: Transfusion
+//darkplaces implementation: LordHavoc
+//cvars:
+//sv_jumpstep (0/1, default 1)
+//sv_stepheight (default 18)
+//description:
+//sv_jumpstep allows stepping up onto stairs while airborn, sv_stepheight controls how high a single step can be.
+
+//FTE_QC_CHECKPVS
+//idea: Urre
+//darkplaces implementation: divVerent
+//builtin definitions:
+float checkpvs(vector viewpos, entity viewee) = #240;
+//description:
+//returns true if viewee can be seen from viewpos according to PVS data
+
+//FTE_STRINGS
+//idea: many
+//darkplaces implementation: KrimZon
+//builtin definitions:
+float(string str, string sub, float startpos) strstrofs = #221; // returns the offset into a string of the matching text, or -1 if not found, case sensitive
+float(string str, float ofs) str2chr = #222; // returns the character at the specified offset as an integer, or 0 if an invalid index, or byte value - 256 if the engine supports UTF8 and the byte is part of an extended character
+string(float c, ...) chr2str = #223; // returns a string representing the character given, if the engine supports UTF8 this may be a multi-byte sequence (length may be more than 1) for characters over 127.
+string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; // reformat a string with special color characters in the font, DO NOT USE THIS ON UTF8 ENGINES (if you are lucky they will emit ^4 and such color codes instead), the parameter values are 0=same/1=lower/2=upper for ccase, 0=same/1=white/2=red/5=alternate/6=alternate-alternate for redalpha, 0=same/1=white/2=red/3=redspecial/4=whitespecial/5=alternate/6=alternate-alternate for rednum.
+string(float chars, string s, ...) strpad = #225; // pad string with spaces to a specified length, < 0 = left padding, > 0 = right padding
+string(string info, string key, string value, ...) infoadd = #226; // sets or adds a key/value pair to an infostring - note: forbidden characters are \ and "
+string(string info, string key) infoget = #227; // gets a key/value pair in an infostring, returns value or null if not found
+float(string s1, string s2) strcmp = #228; // compare two strings
+float(string s1, string s2, float len) strncmp = #228; // compare two strings up to the specified number of characters, if their length differs and is within the specified limit the result will be negative, otherwise it is the difference in value of their first non-matching character.
+float(string s1, string s2) strcasecmp = #229; // compare two strings with case-insensitive matching, characters a-z are considered equivalent to the matching A-Z character, no other differences, and this does not consider special characters equal even if they look similar
+float(string s1, string s2, float len) strncasecmp = #230; // same as strcasecmp but with a length limit, see strncmp
+//string(string s, float start, float length) substring = #116; // see note below
+//description:
+//various string manipulation functions
+//note: substring also exists in FRIK_FILE but this extension adds negative start and length as valid cases (see note above), substring is consistent with the php 5.2.0 substr function (not 5.2.3 behavior)
+//substring returns a section of a string as a tempstring, if given negative
+// start the start is measured back from the end of the string, if given a
+// negative length the length is the offset back from the end of the string to
+// stop at, rather than being relative to start, if start is negative and
+// larger than length it is treated as 0.
+// examples of substring:
+// substring("blah", -3, 3) returns "lah"
+// substring("blah", 3, 3) returns "h"
+// substring("blah", -10, 3) returns "bla"
+// substring("blah", -10, -3) returns "b"
+
+//DP_CON_BESTWEAPON
+//idea: many
+//darkplaces implementation: divVerent
+//description:
+//allows QC to register weapon properties for use by the bestweapon command, for mods that change required ammo count or type for the weapons
+//it is done using console commands sent via stuffcmd:
+// register_bestweapon quake
+// register_bestweapon clear
+// register_bestweapon <shortname> <impulse> <itemcode> <activeweaponcode> <ammostat> <ammomin>
+//for example, this is what Quake uses:
+// register_bestweapon 1 1 4096 4096 6 0 // STAT_SHELLS is 6
+// register_bestweapon 2 2 1 1 6 1
+// register_bestweapon 3 3 2 2 6 1
+// register_bestweapon 4 4 4 4 7 1 // STAT_NAILS is 7
+// register_bestweapon 5 5 8 8 7 1
+// register_bestweapon 6 6 16 16 8 1 // STAT_ROCKETS is 8
+// register_bestweapon 7 7 32 32 8 1
+// register_bestweapon 8 8 64 64 9 1 // STAT_CELLS is 9
+//after each map client initialization, this is reset back to Quake settings. So you should send these data in ClientConnect.
+//also, this extension introduces a new "cycleweapon" command to the user.
+
+//DP_QC_STRINGBUFFERS
+//idea: ??
+//darkplaces implementation: LordHavoc
+//functions to manage string buffer objects - that is, arbitrary length string arrays that are handled by the engine
+float() buf_create = #460;
+void(float bufhandle) buf_del = #461;
+float(float bufhandle) buf_getsize = #462;
+void(float bufhandle_from, float bufhandle_to) buf_copy = #463;
+void(float bufhandle, float sortpower, float backward) buf_sort = #464;
+string(float bufhandle, string glue) buf_implode = #465;
+string(float bufhandle, float string_index) bufstr_get = #466;
+void(float bufhandle, float string_index, string str) bufstr_set = #467;
+float(float bufhandle, string str, float order) bufstr_add = #468;
+void(float bufhandle, float string_index) bufstr_free = #469;
+
+//DP_QC_STRINGBUFFERS_CVARLIST
+//idea: divVerent
+//darkplaces implementation: divVerent
+//functions to list cvars and store their names into a stringbuffer
+//cvars that start with pattern but not with antipattern will be stored into the buffer
+void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
+
+//DP_QC_STRINGBUFFERS_EXT_WIP
+//idea: VorteX
+//darkplaces implementation: VorteX
+//constant definitions:
+const float MATCH_AUTO = 0;
+const float MATCH_WHOLE = 1;
+const float MATCH_LEFT = 2;
+const float MATCH_RIGHT = 3;
+const float MATCH_MIDDLE = 4;
+const float MATCH_PATTERN = 5;
+//builtin definitions:
+float(string filename, float bufhandle) buf_loadfile = #535; // append each line of file as new buffer string, return 1 if succesful
+float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile = #536; // writes buffer strings as lines, returns 1 if succesful
+float(float bufhandle, string match, float matchrule, float startpos, float step) bufstr_find = #537; // returns string index
+float(string s, string pattern, float matchrule) matchpattern = #538; // returns 0/1
+float(string s, string pattern, float matchrule, float pos) matchpatternofs = #538;
+//description:
+//provides a set of functions to manipulate with string buffers
+//pattern wildcards: * - any character (or no characters), ? - any 1 character
+//Warning: This extension is work-in-progress, it may be changed/revamped/removed at any time, dont use it if you dont want any trouble
+//wip note: UTF8 is not supported yet
+
+//DP_QC_STRREPLACE
+//idea: Sajt
+//darkplaces implementation: Sajt
+//builtin definitions:
+string(string search, string replace, string subject) strreplace = #484;
+string(string search, string replace, string subject) strireplace = #485;
+//description:
+//strreplace replaces all occurrences of 'search' with 'replace' in the string 'subject', and returns the result as a tempstring.
+//strireplace does the same but uses case-insensitive matching of the 'search' term
+
+//DP_SV_SHUTDOWN
+//idea: divVerent
+//darkplaces implementation: divVerent
+//A function that gets called just before progs exit. To save persistent data from.
+//It is not called on a crash or error.
+//void SV_Shutdown();
+
+//EXT_CSQC
+// #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
+void(float index, float type, ...) addstat = #232;
+
+//ZQ_PAUSE
+//idea: ZQuake
+//darkplaces implementation: GreEn`mArine
+//builtin definitions:
+void(float pause) setpause = #531;
+//function definitions:
+//void(float elapsedtime) SV_PausedTic;
+//description:
+//during pause the world is not updated (time does not advance), SV_PausedTic is the only function you can be sure will be called at regular intervals during the pause, elapsedtime is the current system time in seconds since the pause started (not affected by slowmo or anything else).
+//
+//calling setpause(0) will end a pause immediately.
+//
+//Note: it is worth considering that network-related functions may be called during the pause (including customizeentityforclient for example), and it is also important to consider the continued use of the KRIMZON_SV_PARSECLIENTCOMMAND extension while paused (chatting players, etc), players may also join/leave during the pause. In other words, the only things that are not called are think and other time-related functions.
+
+//DP_COVERAGE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//function definitions:
+void coverage() = #642; // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
+
+
+// EXPERIMENTAL (not finalized) EXTENSIONS:
+
+//DP_CRYPTO
+//idea: divVerent
+//darkplaces implementation: divVerent
+//field definitions: (SVQC)
+.string crypto_keyfp; // fingerprint of CA key the player used to authenticate
+.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player
+.string crypto_idfp; // fingerprint of ID used by the player entity, or string_null if not identified
+.float crypto_idfp_signed; // set if the player's ID has been signed
+.string crypto_encryptmethod; // the string "AES128" if encrypting, and string_null if plaintext
+.string crypto_signmethod; // the string "HMAC-SHA256" if signing, and string_null if plaintext
+// there is no field crypto_myidfp, as that info contains no additional information the QC may have a use for
+//builtin definitions: (SVQC)
+float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
+//description:
+//use -1 as buffer handle to justs end delim as postdata
--- /dev/null
+///////////////////////////
+// key constants
+
+//
+// these are the key numbers that should be passed to Key_Event
+//
+float K_TAB = 9;
+float K_ENTER = 13;
+float K_ESCAPE = 27;
+float K_SPACE = 32;
+
+// normal keys should be passed as lowercased ascii
+
+float K_BACKSPACE = 127;
+float K_UPARROW = 128;
+float K_DOWNARROW = 129;
+float K_LEFTARROW = 130;
+float K_RIGHTARROW = 131;
+
+float K_ALT = 132;
+float K_CTRL = 133;
+float K_SHIFT = 134;
+
+float K_F1 = 135;
+float K_F2 = 136;
+float K_F3 = 137;
+float K_F4 = 138;
+float K_F5 = 139;
+float K_F6 = 140;
+float K_F7 = 141;
+float K_F8 = 142;
+float K_F9 = 143;
+float K_F10 = 144;
+float K_F11 = 145;
+float K_F12 = 146;
+
+float K_INS = 147;
+float K_DEL = 148;
+float K_PGDN = 149;
+float K_PGUP = 150;
+float K_HOME = 151;
+float K_END = 152;
+
+float K_NUMLOCK = 154;
+float K_CAPSLOCK = 155;
+float K_SCROLLOCK = 156;
+
+float K_KP_0 = 157;
+float K_KP_INS = 157; // same as K_KP_0
+float K_KP_1 = 158;
+float K_KP_END = 158; // same as K_KP_1
+float K_KP_2 = 159;
+float K_KP_DOWNARROW = 159; // same as K_KP_2
+float K_KP_3 = 160;
+float K_KP_PGDN = 160; // same as K_KP_3
+float K_KP_4 = 161;
+float K_KP_LEFTARROW = 161; // same as K_KP_4
+float K_KP_5 = 162;
+float K_KP_6 = 163;
+float K_KP_RIGHTARROW = 163; // same as K_KP_6
+float K_KP_7 = 164;
+float K_KP_HOME = 164; // same as K_KP_7
+float K_KP_8 = 165;
+float K_KP_UPARROW = 165; // same as K_KP_8
+float K_KP_9 = 166;
+float K_KP_PGUP = 166; // same as K_KP_9
+float K_KP_PERIOD = 167;
+float K_KP_DEL = 167; // same as K_KP_PERIOD
+float K_KP_DIVIDE = 168;
+float K_KP_SLASH = 168; // same as K_KP_DIVIDE
+float K_KP_MULTIPLY = 169;
+float K_KP_MINUS = 170;
+float K_KP_PLUS = 171;
+float K_KP_ENTER = 172;
+float K_KP_EQUALS = 173;
+
+// mouse buttons generate virtual keys
+float K_PAUSE = 153;
+
+//
+// joystick buttons
+//
+float K_JOY1 = 768;
+float K_JOY2 = 769;
+float K_JOY3 = 770;
+float K_JOY4 = 771;
+
+//
+//
+// aux keys are for multi-buttoned joysticks to generate so they can use
+// the normal binding process
+//
+float K_AUX1 = 772;
+float K_AUX2 = 773;
+float K_AUX3 = 774;
+float K_AUX4 = 775;
+float K_AUX5 = 776;
+float K_AUX6 = 777;
+float K_AUX7 = 778;
+float K_AUX8 = 779;
+float K_AUX9 = 780;
+float K_AUX10 = 781;
+float K_AUX11 = 782;
+float K_AUX12 = 783;
+float K_AUX13 = 784;
+float K_AUX14 = 785;
+float K_AUX15 = 786;
+float K_AUX16 = 787;
+float K_AUX17 = 788;
+float K_AUX18 = 789;
+float K_AUX19 = 790;
+float K_AUX20 = 791;
+float K_AUX21 = 792;
+float K_AUX22 = 793;
+float K_AUX23 = 794;
+float K_AUX24 = 795;
+float K_AUX25 = 796;
+float K_AUX26 = 797;
+float K_AUX27 = 798;
+float K_AUX28 = 799;
+float K_AUX29 = 800;
+float K_AUX30 = 801;
+float K_AUX31 = 802;
+float K_AUX32 = 803;
+
+//
+// mouse buttons generate virtual keys
+//
+float K_MOUSE1 = 512;
+float K_MOUSE2 = 513;
+float K_MOUSE3 = 514;
+float K_MWHEELUP = 515;
+float K_MWHEELDOWN = 516;
+float K_MOUSE4 = 517;
+float K_MOUSE5 = 518;
+float K_MOUSE6 = 519;
+float K_MOUSE7 = 520;
+float K_MOUSE8 = 521;
+float K_MOUSE9 = 522;
+float K_MOUSE10 = 523;
+float K_MOUSE11 = 524;
+float K_MOUSE12 = 525;
+float K_MOUSE13 = 526;
+float K_MOUSE14 = 527;
+float K_MOUSE15 = 528;
+float K_MOUSE16 = 529;
--- /dev/null
+//////////////////////////////////////////////////////////
+// sys globals
+
+entity self;
+
+/////////////////////////////////////////////////////////
+void end_sys_globals;
+/////////////////////////////////////////////////////////
+// sys fields
+
+/////////////////////////////////////////////////////////
+void end_sys_fields;
+/////////////////////////////////////////////////////////
+// sys functions
+
+void() m_init;
+void(float keynr, float ascii) m_keydown;
+void(float width, float height) m_draw;
+void(float mode) m_toggle;
+void() m_shutdown;
+// optional: float(float) m_gethostcachecategory;
+
+/////////////////////////////////////////////////////////
+// sys constants
+///////////////////////////
+// key dest constants
+
+float KEY_UNKNOWN = -1;
+float KEY_GAME = 0;
+float KEY_MENU = 2;
+float KEY_MENU_GRABBED = 3;
+
+///////////////////////////
+// file constants
+
+float FILE_READ = 0;
+float FILE_APPEND = 1;
+float FILE_WRITE = 2;
+
+///////////////////////////
+// logical constants (just for completeness)
+
+float TRUE = 1;
+float FALSE = 0;
+
+///////////////////////////
+// boolean constants
+
+float true = 1;
+float false = 0;
+
+///////////////////////////
+// msg constants
+
+float MSG_BROADCAST = 0; // unreliable to all
+float MSG_ONE = 1; // reliable to one (msg_entity)
+float MSG_ALL = 2; // reliable to all
+float MSG_INIT = 3; // write to the init string
+
+/////////////////////////////
+// mouse target constants
+
+float MT_MENU = 1;
+float MT_CLIENT = 2;
+
+/////////////////////////
+// client state constants
+
+float CS_DEDICATED = 0;
+float CS_DISCONNECTED = 1;
+float CS_CONNECTED = 2;
+
+///////////////////////////
+// blend flags
+
+float DRAWFLAG_NORMAL = 0;
+float DRAWFLAG_ADDITIVE = 1;
+float DRAWFLAG_MODULATE = 2;
+float DRAWFLAG_2XMODULATE = 3;
+
+///////////////////////////
+// null entity (actually it is the same like the world entity)
+
+entity null_entity;
+
+///////////////////////////
+// error constants
+
+// file handling
+float ERR_CANNOTOPEN = -1; // fopen
+float ERR_NOTENOUGHFILEHANDLES = -2; // fopen
+float ERR_INVALIDMODE = -3; // fopen
+float ERR_BADFILENAME = -4; // fopen
+
+// drawing functions
+
+float ERR_NULLSTRING = -1;
+float ERR_BADDRAWFLAG = -2;
+float ERR_BADSCALE = -3;
+float ERR_BADSIZE = -3; // same as ERR_BADSCALE
+float ERR_NOTCACHED = -4;
+
+// server list stuff
+float SLIST_HOSTCACHEVIEWCOUNT = 0;
+float SLIST_HOSTCACHETOTALCOUNT = 1;
+float SLIST_MASTERQUERYCOUNT = 2;
+float SLIST_MASTERREPLYCOUNT = 3;
+float SLIST_SERVERQUERYCOUNT = 4;
+float SLIST_SERVERREPLYCOUNT = 5;
+float SLIST_SORTFIELD = 6;
+float SLIST_SORTDESCENDING = 7;
+float SLIST_LEGACY_LINE1 = 1024;
+float SLIST_LEGACY_LINE2 = 1025;
+float SLIST_TEST_CONTAINS = 0;
+float SLIST_TEST_NOTCONTAIN = 1;
+float SLIST_TEST_LESSEQUAL = 2;
+float SLIST_TEST_LESS = 3;
+float SLIST_TEST_EQUAL = 4;
+float SLIST_TEST_GREATER = 5;
+float SLIST_TEST_GREATEREQUAL = 6;
+float SLIST_TEST_NOTEQUAL = 7;
+float SLIST_TEST_STARTSWITH = 8;
+float SLIST_TEST_NOTSTARTSWITH = 9;
+float SLIST_MASK_AND = 0;
+float SLIST_MASK_OR = 512;
+
+// font stuff
+float FONT_DEFAULT = 0;
+float FONT_CONSOLE = 1;
+float FONT_SBAR = 2;
+float FONT_NOTIFY = 3;
+float FONT_CHAT = 4;
+float FONT_CENTERPRINT = 5;
+float FONT_INFOBAR = 6;
+float FONT_MENU = 7;
+float FONT_USER = 8; // add to this the index, like FONT_USER+3 = user3. At least 8 of them are supported.
+float drawfont;
+
+/* not supported at the moment
+///////////////////////////
+// os constants
+
+float OS_WINDOWS = 0;
+float OS_LINUX = 1;
+float OS_MAC = 2;
+*/
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////
+// common cmd
+//////////////////////////////////////////////////
+// AK FIXME: Create perhaps a special builtin file for the common cmds
+
+void checkextension(string ext) = #1;
+
+// error cmds
+void error(string err,...) = #2;
+void objerror(string err,...) = #3;
+
+// print
+
+void print(string text,...) = #4;
+void bprint(string text,...) = #5;
+void sprint(float clientnum, string text,...) = #6;
+void centerprint(string text,...) = #7;
+
+// vector stuff
+
+vector normalize(vector v) = #8;
+float vlen(vector v) = #9;
+float vectoyaw(vector v) = #10;
+vector vectoangles(vector v) = #11;
+
+float random(void) = #12;
+
+void cmd(string command, ...) = #13;
+
+// cvar cmds
+
+float cvar(string name) = #14;
+const string str_cvar(string name) = #71;
+void cvar_set(string name, string value) = #15;
+
+void dprint(string text,...) = #16;
+
+// conversion functions
+
+string ftos(float f) = #17;
+float fabs(float f) = #18;
+string vtos(vector v) = #19;
+string etos(entity e) = #20;
+
+float stof(string val,...) = #21;
+
+entity spawn(void) = #22;
+void remove(entity e) = #23;
+
+entity find(entity start, .string field, string match) = #24;
+entity findfloat(entity start, .float field, float match) = #25;
+entity findentity(entity start, .entity field, entity match) = #25;
+
+entity findchainstring(.string field, string match) = #26;
+entity findchainfloat(.float field, float match) = #27;
+entity findchainentity(.entity field, entity match) = #27;
+
+string precache_file(string file) = #28;
+string precache_sound(string sample) = #29;
+
+void crash(void) = #72;
+void coredump(void) = #30;
+void stackdump(void) = #73;
+void traceon(void) = #31;
+void traceoff(void) = #32;
+
+void eprint(entity e) = #33;
+float rint(float f) = #34;
+float floor(float f) = #35;
+float ceil(float f) = #36;
+entity nextent(entity e) = #37;
+float sin(float f) = #38;
+float cos(float f) = #39;
+float sqrt(float f) = #40;
+vector randomvec(void) = #41;
+
+float registercvar(string name, string value, float flags) = #42; // returns 1 if success
+
+float min(float f,...) = #43;
+float max(float f,...) = #44;
+
+float bound(float min,float value, float max) = #45;
+float pow(float a, float b) = #46;
+
+void copyentity(entity src, entity dst) = #47;
+
+float fopen(string filename, float mode) = #48;
+void fclose(float fhandle) = #49;
+string fgets(float fhandle) = #50;
+void fputs(float fhandle, string s) = #51;
+
+float strlen(string s) = #52;
+string strcat(string s1,string s2,...) = #53;
+string substring(string s, float start, float length) = #54;
+
+vector stov(string s) = #55;
+
+string strzone(string s) = #56;
+void strunzone(string s) = #57;
+
+float tokenize(string s) = #58;
+string argv(float n) = #59;
+
+float isserver(void) = #60;
+float clientcount(void) = #61;
+float clientstate(void) = #62;
+void clientcommand(float client, string s) = #63;
+void changelevel(string map) = #64;
+void localsound(string sample) = #65;
+vector getmousepos(void) = #66;
+float gettime(void) = #67;
+void loadfromdata(string data) = #68;
+void loadfromfile(string file) = #69;
+
+float mod(float val, float m) = #70;
+
+float search_begin(string pattern, float caseinsensitive, float quiet) = #74;
+void search_end(float handle) = #75;
+float search_getsize(float handle) = #76;
+string search_getfilename(float handle, float num) = #77;
+
+string chr(float ascii) = #78;
+
+/////////////////////////////////////////////////
+// Write* Functions
+/////////////////////////////////////////////////
+void WriteByte(float data, float dest, float desto) = #401;
+void WriteChar(float data, float dest, float desto) = #402;
+void WriteShort(float data, float dest, float desto) = #403;
+void WriteLong(float data, float dest, float desto) = #404;
+void WriteAngle(float data, float dest, float desto) = #405;
+void WriteCoord(float data, float dest, float desto) = #406;
+void WriteString(string data, float dest, float desto)= #407;
+void WriteEntity(entity data, float dest, float desto) = #408;
+
+//////////////////////////////////////////////////
+// Draw funtions
+//////////////////////////////////////////////////
+
+float iscachedpic(string name) = #451;
+string precache_pic(string name, ...) = #452;
+void freepic(string name) = #453;
+
+float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454;
+
+float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455;
+
+float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) = #467;
+
+vector drawcolorcodedstring2(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #467;
+
+float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456;
+
+float drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457;
+
+void drawsetcliparea(float x, float y, float width, float height) = #458;
+
+void drawresetcliparea(void) = #459;
+
+vector drawgetimagesize(string pic) = #460;
+
+////////////////////////////////////////////////
+// Menu functions
+////////////////////////////////////////////////
+
+void setkeydest(float dest) = #601;
+float getkeydest(void) = #602;
+
+void setmousetarget(float trg) = #603;
+float getmousetarget(void) = #604;
+
+float isfunction(string function_name) = #607;
+void callfunction(...) = #605;
+void writetofile(float fhandle, entity ent) = #606;
+vector getresolution(float number) = #608;
+string keynumtostring(float keynum) = #609;
+
+float gethostcachevalue(float type) = #611;
+string gethostcachestring(float type, float hostnr) = #612;
+
+//DP_CSQC_BINDMAPS
+//idea: daemon, motorsep
+//darkplaces implementation: divVerent
+//builtin definitions:
+string(float key, float bindmap) getkeybind_bindmap = #342;
+float(float key, string bind, float bindmap) setkeybind_bindmap = #630;
+vector(void) getbindmaps = #631;
+float(vector bm) setbindmaps = #632;
+string(string command, float bindmap) findkeysforcommand = #610;
+float(string key) stringtokeynum = #341;
+//<also allowed builtin number to match EXT_CSQC> string(float keynum) keynumtostring = #340;
+//description: key bind setting/getting including support for switchable
+//bindmaps.
+
+//DP_CRYPTO
+//idea: divVerent
+//darkplaces implementation: divVerent
+//field definitions: (MENUQC)
+string(string serveraddress) crypto_getkeyfp = #633; // retrieves the cached host key's CA fingerprint of a server given by IP address
+string(string serveraddress) crypto_getidfp = #634; // retrieves the cached host key fingerprint of a server given by IP address
+float(string serveraddress) crypto_getidstatus = #643; // retrieves the cached host key's key status. See below for CRYPTO_IDSTATUS_ defines.
+string(string serveraddress) crypto_getencryptlevel = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each
+string(float i) crypto_getmykeyfp = #636; // retrieves the CA key fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
+string(float i) crypto_getmyidfp = #637; // retrieves the ID fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
+float CRYPTO_IDSTATUS_OUTOFRANGE = -1;
+float CRYPTO_IDSTATUS_EMPTY = 0;
+float CRYPTO_IDSTATUS_UNSIGNED = 1;
+float CRYPTO_IDSTATUS_SIGNED = 2;
+float(float i) crypto_getmyidstatus = #641; // retrieves the ID's status of a given CA slot, or 0 if slot is unused but more to come, or -1 if end of list
+float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
+//description:
+//use -1 as buffer handle to justs end delim as postdata
+
+//DP_GECKO_SUPPORT
+//idea: Res2k, BlackHC
+//darkplaces implementation: Res2k, BlackHC
+//constant definitions:
+float GECKO_BUTTON_DOWN = 0;
+float GECKO_BUTTON_UP = 1;
+// either use down and up or just press but not all of them!
+float GECKO_BUTTON_PRESS = 2;
+// use this for mouse events if needed?
+float GECKO_BUTTON_DOUBLECLICK = 3;
+//builtin definitions:
+float gecko_create( string name ) = #487;
+void gecko_destroy( string name ) = #488;
+void gecko_navigate( string name, string URI ) = #489;
+float gecko_keyevent( string name, float key, float eventtype ) = #490;
+void gecko_mousemove( string name, float x, float y ) = #491;
+void gecko_resize( string name, float w, float h ) = #492;
+vector gecko_get_texture_extent( string name ) = #493;
+//engine-called QC prototypes:
+//string(string name, string query) Qecko_Query;
+//description:
+//provides an interface to the offscreengecko library and allows for internet browsing in games
+
+//FTE_STRINGS
+//idea: many
+//darkplaces implementation: KrimZon
+//description:
+//various string manipulation functions
+float(string str, string sub, float startpos) strstrofs = #221;
+float(string str, float ofs) str2chr = #222;
+string(float c, ...) chr2str = #223;
+string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
+string(float chars, string s, ...) strpad = #225;
+string(string info, string key, string value, ...) infoadd = #226;
+string(string info, string key) infoget = #227;
+float(string s1, string s2) strcmp = #228;
+float(string s1, string s2, float len) strncmp = #228;
+float(string s1, string s2) strcasecmp = #229;
+float(string s1, string s2, float len) strncasecmp = #230;
+
+//DP_PRECACHE_PIC_FLAGS
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC
+float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused
+float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense
+//notes: these constants are given as optional second argument to precache_pic()
+
+//DP_QC_CRC16
+//idea: div0
+//darkplaces implementation: div0
+//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
+//When caseinsensitive is set, the CRC is calculated of the lower cased string.
+float(float caseinsensitive, string s, ...) crc16 = #494;
+
+//DP_QC_CVAR_TYPE
+float(string name) cvar_type = #495;
+float CVAR_TYPEFLAG_EXISTS = 1;
+float CVAR_TYPEFLAG_SAVED = 2;
+float CVAR_TYPEFLAG_PRIVATE = 4;
+float CVAR_TYPEFLAG_ENGINE = 8;
+float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
+float CVAR_TYPEFLAG_READONLY = 32;
+
+//DP_QC_STRINGBUFFERS
+//idea: ??
+//darkplaces implementation: LordHavoc
+//functions to manage string buffer objects - that is, arbitrary length string arrays that are handled by the engine
+float() buf_create = #440;
+void(float bufhandle) buf_del = #441;
+float(float bufhandle) buf_getsize = #442;
+void(float bufhandle_from, float bufhandle_to) buf_copy = #443;
+void(float bufhandle, float sortpower, float backward) buf_sort = #444;
+string(float bufhandle, string glue) buf_implode = #445;
+string(float bufhandle, float string_index) bufstr_get = #446;
+void(float bufhandle, float string_index, string str) bufstr_set = #447;
+float(float bufhandle, string str, float order) bufstr_add = #448;
+void(float bufhandle, float string_index) bufstr_free = #449;
+void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
+
+//DP_QC_STRING_CASE_FUNCTIONS
+//idea: Dresk
+//darkplaces implementation: LordHavoc / Dresk
+//builtin definitions:
+string(string s) strtolower = #480; // returns the passed in string in pure lowercase form
+string(string s) strtoupper = #481; // returns the passed in string in pure uppercase form
+//description:
+//provides simple string uppercase and lowercase functions
+
+//DP_QC_CVAR_DESCRIPTION
+//idea: divVerent
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string name) cvar_description = #518;
+//description:
+//returns the description of a cvar
+
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
+
+//DP_QC_URI_ESCAPE
+//idea: div0
+//darkplaces implementation: div0
+//URI::Escape's functionality
+string(string in) uri_escape = #510;
+string(string in) uri_unescape = #511;
+
+//DP_QC_URI_GET
+//idea: divVerent
+//darkplaces implementation: divVerent
+//loads text from an URL into a string
+//returns 1 on success of initiation, 0 if there are too many concurrent
+//connections already or if the URL is invalid
+//the following callback will receive the data and MUST exist!
+// void(float id, float status, string data) URI_Get_Callback;
+//status is either
+// negative for an internal error,
+// 0 for success, or
+// the HTTP response code on server error (e.g. 404)
+//if 1 is returned by uri_get, the callback will be called in the future
+float(string url, float id) uri_get = #513;
+//DP_QC_URI_POST
+//idea: divVerent
+//darkplaces implementation: divVerent
+//loads text from an URL into a string after POSTing via HTTP
+//works like uri_get, but uri_post sends data with Content-Type: content_type to the server
+//and uri_post sends the string buffer buf, joined using the delimiter delim
+float(string url, float id, string content_type, string data) uri_post = #513;
+float(string url, float id, string content_type, string delim, float buf) uri_postbuf = #513;
+
+//DP_QC_ENTITYDATA
+//idea: KrimZon
+//darkplaces implementation: KrimZon
+//builtin definitions:
+float() numentityfields = #496;
+string(float fieldnum) entityfieldname = #497;
+float(float fieldnum) entityfieldtype = #498;
+string(float fieldnum, entity ent) getentityfieldstring = #499;
+float(float fieldnum, entity ent, string s) putentityfieldstring = #500;
+//constants:
+//Returned by entityfieldtype
+float FIELD_STRING = 1;
+float FIELD_FLOAT = 2;
+float FIELD_VECTOR = 3;
+float FIELD_ENTITY = 4;
+float FIELD_FUNCTION = 6;
+//description:
+//Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame.
+//WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers.
+//numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z.
+//entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever.
+//entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers.
+//getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
+//putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
+
+//DP_COVERAGE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//function definitions:
+void coverage() = #642; // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
+
+// assorted undocumented extensions
+string(string, float) netaddress_resolve = #625;
+string(string search, string replace, string subject) strreplace = #484;
+string(float uselocaltime, string format, ...) strftime = #478;
+float(string s) tokenize_console = #514;
+float(float i) argv_start_index = #515;
+float(float i) argv_end_index = #516;
+string(float, float) getgamedirinfo = #626;
+#define GETGAMEDIRINFO_NAME 0
+#define GETGAMEDIRINFO_DESCRIPTION 1
+float log(float f) = #532;
+string(string format, ...) sprintf = #627;
+string(string s) strdecolorize = #477;
+entity findflags(entity start, .float field, float match) = #87;
+entity findchainflags(.float field, float match) = #88;
+float(string s, string separator1, ...) tokenizebyseparator = #479;
+float etof(entity ent) = #79;
+entity ftoe(float num) = #80;
+float validstring(string str) = #81;
+float altstr_count(string str) = #82;
+string altstr_prepare(string str) = #83;
+string altstr_get(string str, float num) = #84;
+string altstr_set(string str, float num, string set) = #85;
+string altstr_ins(string str, float num, string set) = #86;
+float isdemo() = #349;
+float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #469;
+//vector getresolution(float number, ...) = #608; // optional argument "isfullscreen"
+void parseentitydata(entity ent, string data) = #613;
+void resethostcachemasks(void) = #615;
+void sethostcachemaskstring(float mask, float fld, string str, float op) = #616;
+void sethostcachemasknumber(float mask, float fld, float num, float op) = #617;
+void resorthostcache(void) = #618;
+float SLSF_DESCENDING = 1;
+float SLSF_FAVORITES = 2;
+float SLSF_CATEGORIES = 4;
+void sethostcachesort(float fld, float slsf) = #619;
+void refreshhostcache(...) = #620; // optional boolean argument "clear_list"
+float gethostcachenumber(float fld, float hostnr) = #621;
+float gethostcacheindexforkey(string key) = #622;
+void addwantedhostcachekey(string key) = #623;
+string getextresponse(void) = #624;
+const string cvar_string(string name) = #71;
+const string cvar_defstring(string name) = #89;
+float stringwidth(string text, float handleColors, vector size) = #468;
--- /dev/null
+/*
+==============================================================================
+
+ SOURCE FOR GLOBALVARS_T C STRUCTURE
+ MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+
+==============================================================================
+*/
+
+//
+// system globals
+//
+entity self;
+entity other;
+entity world;
+float time;
+float frametime;
+
+float force_retouch; // force all entities to touch triggers
+ // next frame. this is needed because
+ // non-moving things don't normally scan
+ // for triggers, and when a trigger is
+ // created (like a teleport trigger), it
+ // needs to catch everything.
+ // decremented each frame, so set to 2
+ // to guarantee everything is touched
+string mapname;
+
+float deathmatch;
+float coop;
+float teamplay;
+
+float serverflags; // propagated from level to level, used to
+ // keep track of completed episodes
+
+float total_secrets;
+float total_monsters;
+
+float found_secrets; // number of secrets found
+float killed_monsters; // number of monsters killed
+
+
+// spawnparms are used to encode information about clients across server
+// level changes
+float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
+
+//
+// global variables set by built in functions
+//
+vector v_forward, v_up, v_right; // set by makevectors()
+
+// set by traceline / tracebox
+float trace_allsolid;
+float trace_startsolid;
+float trace_fraction;
+vector trace_endpos;
+vector trace_plane_normal;
+float trace_plane_dist;
+entity trace_ent;
+float trace_inopen;
+float trace_inwater;
+
+entity msg_entity; // destination of single entity writes
+
+//
+// required prog functions
+//
+void() main; // only for testing
+
+void() StartFrame;
+
+void() PlayerPreThink;
+void() PlayerPostThink;
+
+void() ClientKill;
+void() ClientConnect;
+void() PutClientInServer; // call after setting the parm1... parms
+void() ClientDisconnect;
+
+void() SetNewParms; // called when a client first connects to
+ // a server. sets parms so they can be
+ // saved off for restarts
+
+void() SetChangeParms; // call to set parms for self so they can
+ // be saved for a level transition
+
+
+//================================================
+void end_sys_globals; // flag for structure dumping
+//================================================
+
+/*
+==============================================================================
+
+ SOURCE FOR ENTVARS_T C STRUCTURE
+ MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+
+==============================================================================
+*/
+
+//
+// system fields (*** = do not set in prog code, maintained by C code)
+//
+.float modelindex; // *** model index in the precached list
+.vector absmin, absmax; // *** origin + mins / maxs
+
+.float ltime; // local time for entity
+.float movetype;
+.float solid;
+
+.vector origin; // ***
+.vector oldorigin; // ***
+.vector velocity;
+.vector angles;
+.vector avelocity;
+
+.vector punchangle; // temp angle adjust from damage or recoil
+
+.string classname; // spawn function
+.string model;
+.float frame;
+.float skin;
+.float effects;
+
+.vector mins, maxs; // bounding box extents reletive to origin
+.vector size; // maxs - mins
+
+.void() touch;
+.void() use;
+.void() think;
+.void() blocked; // for doors or plats, called when can't push other
+
+.float nextthink;
+.entity groundentity;
+
+// stats
+.float health;
+.float frags;
+.float weapon; // one of the IT_SHOTGUN, etc flags
+.string weaponmodel;
+.float weaponframe;
+.float currentammo;
+.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
+
+.float items; // bit flags
+
+.float takedamage;
+.entity chain;
+.float deadflag;
+
+.vector view_ofs; // add to origin to get eye point
+
+
+.float button0; // fire
+.float button1; // use
+.float button2; // jump
+
+.float impulse; // weapon changes
+
+.float fixangle;
+.vector v_angle; // view / targeting angle for players
+.float idealpitch; // calculated pitch angle for lookup up slopes
+
+
+.string netname;
+
+.entity enemy;
+
+.float flags;
+
+.float colormap;
+.float team;
+
+.float max_health; // players maximum health is stored here
+
+.float teleport_time; // don't back up
+
+.float armortype; // save this fraction of incoming damage
+.float armorvalue;
+
+.float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes
+.float watertype; // a contents value
+
+.float ideal_yaw;
+.float yaw_speed;
+
+.entity aiment;
+
+.entity goalentity; // a movetarget or an enemy
+
+.float spawnflags;
+
+.string target;
+.string targetname;
+
+// damage is accumulated through a frame. and sent as one single
+// message, so the super shotgun doesn't generate huge messages
+.float dmg_take;
+.float dmg_save;
+.entity dmg_inflictor;
+
+.entity owner; // who launched a missile
+.vector movedir; // mostly for doors, but also used for waterjump
+
+.string message; // trigger messages
+
+.float sounds; // either a cd track number or sound number
+
+.string noise, noise1, noise2, noise3; // contains names of wavs to play
+
+//================================================
+void end_sys_fields; // flag for structure dumping
+//================================================
+
+/*
+==============================================================================
+
+ CONSTANT DEFINITIONS
+
+==============================================================================
+*/
+
+
+//
+// constants
+//
+
+float FALSE = 0;
+float TRUE = 1;
+
+// edict.flags
+float FL_FLY = 1;
+float FL_SWIM = 2;
+float FL_CLIENT = 8; // set for all client edicts
+float FL_INWATER = 16; // for enter / leave water splash
+float FL_MONSTER = 32;
+float FL_GODMODE = 64; // player cheat
+float FL_NOTARGET = 128; // player cheat
+float FL_ITEM = 256; // extra wide size for bonus items
+float FL_ONGROUND = 512; // standing on something
+float FL_PARTIALGROUND = 1024; // not all corners are valid
+float FL_WATERJUMP = 2048; // player jumping out of water
+float FL_JUMPRELEASED = 4096; // for jump debouncing
+
+// edict.movetype values
+float MOVETYPE_NONE = 0; // never moves
+//float MOVETYPE_ANGLENOCLIP = 1;
+//float MOVETYPE_ANGLECLIP = 2;
+float MOVETYPE_WALK = 3; // players only
+float MOVETYPE_STEP = 4; // discrete, not real time unless fall
+float MOVETYPE_FLY = 5;
+float MOVETYPE_TOSS = 6; // gravity
+float MOVETYPE_PUSH = 7; // no clip to world, push and crush
+float MOVETYPE_NOCLIP = 8;
+float MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters
+float MOVETYPE_BOUNCE = 10;
+float MOVETYPE_BOUNCEMISSILE = 11; // bounce with extra size
+
+// edict.solid values
+float SOLID_NOT = 0; // no interaction with other objects
+float SOLID_TRIGGER = 1; // touch on edge, but not blocking
+float SOLID_BBOX = 2; // touch on edge, block
+float SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
+float SOLID_BSP = 4; // bsp clip, touch on edge, block
+
+// range values
+float RANGE_MELEE = 0;
+float RANGE_NEAR = 1;
+float RANGE_MID = 2;
+float RANGE_FAR = 3;
+
+// deadflag values
+
+float DEAD_NO = 0;
+float DEAD_DYING = 1;
+float DEAD_DEAD = 2;
+float DEAD_RESPAWNABLE = 3;
+float DEAD_RESPAWNING = 4; // dead, waiting for buttons to be released
+
+// takedamage values
+
+float DAMAGE_NO = 0;
+float DAMAGE_YES = 1;
+float DAMAGE_AIM = 2;
+
+// items
+float IT_AXE = 4096;
+float IT_SHOTGUN = 1;
+float IT_SUPER_SHOTGUN = 2;
+float IT_NAILGUN = 4;
+float IT_SUPER_NAILGUN = 8;
+float IT_GRENADE_LAUNCHER = 16;
+float IT_ROCKET_LAUNCHER = 32;
+float IT_LIGHTNING = 64;
+float IT_EXTRA_WEAPON = 128;
+
+float IT_SHELLS = 256;
+float IT_NAILS = 512;
+float IT_ROCKETS = 1024;
+float IT_CELLS = 2048;
+
+float IT_ARMOR1 = 8192;
+float IT_ARMOR2 = 16384;
+float IT_ARMOR3 = 32768;
+float IT_SUPERHEALTH = 65536;
+
+float IT_KEY1 = 131072;
+float IT_KEY2 = 262144;
+
+float IT_INVISIBILITY = 524288;
+float IT_INVULNERABILITY = 1048576;
+float IT_SUIT = 2097152;
+float IT_QUAD = 4194304;
+
+// point content values
+
+float CONTENT_EMPTY = -1;
+float CONTENT_SOLID = -2;
+float CONTENT_WATER = -3;
+float CONTENT_SLIME = -4;
+float CONTENT_LAVA = -5;
+float CONTENT_SKY = -6;
+
+float STATE_TOP = 0;
+float STATE_BOTTOM = 1;
+float STATE_UP = 2;
+float STATE_DOWN = 3;
+
+vector VEC_ORIGIN = '0 0 0';
+vector VEC_HULL_MIN = '-16 -16 -24';
+vector VEC_HULL_MAX = '16 16 32';
+
+vector VEC_HULL2_MIN = '-32 -32 -24';
+vector VEC_HULL2_MAX = '32 32 64';
+
+// protocol bytes
+float SVC_TEMPENTITY = 23;
+float SVC_KILLEDMONSTER = 27;
+float SVC_FOUNDSECRET = 28;
+float SVC_INTERMISSION = 30;
+float SVC_FINALE = 31;
+float SVC_CDTRACK = 32;
+float SVC_SELLSCREEN = 33;
+
+
+float TE_SPIKE = 0;
+float TE_SUPERSPIKE = 1;
+float TE_GUNSHOT = 2;
+float TE_EXPLOSION = 3;
+float TE_TAREXPLOSION = 4;
+float TE_LIGHTNING1 = 5;
+float TE_LIGHTNING2 = 6;
+float TE_WIZSPIKE = 7;
+float TE_KNIGHTSPIKE = 8;
+float TE_LIGHTNING3 = 9;
+float TE_LAVASPLASH = 10;
+float TE_TELEPORT = 11;
+
+// sound channels
+// channel 0 never willingly overrides
+// other channels (1-7) allways override a playing sound on that channel
+float CHAN_AUTO = 0;
+float CHAN_WEAPON = 1;
+float CHAN_VOICE = 2;
+float CHAN_ITEM = 3;
+float CHAN_BODY = 4;
+
+float ATTN_NONE = 0;
+float ATTN_NORM = 1;
+float ATTN_IDLE = 2;
+float ATTN_STATIC = 3;
+
+// update types
+
+float UPDATE_GENERAL = 0;
+float UPDATE_STATIC = 1;
+float UPDATE_BINARY = 2;
+float UPDATE_TEMP = 3;
+
+// entity effects
+
+float EF_BRIGHTFIELD = 1;
+float EF_MUZZLEFLASH = 2;
+float EF_BRIGHTLIGHT = 4;
+float EF_DIMLIGHT = 8;
+
+
+// messages
+float MSG_BROADCAST = 0; // unreliable to all
+float MSG_ONE = 1; // reliable to one (msg_entity)
+float MSG_ALL = 2; // reliable to all
+float MSG_INIT = 3; // write to the init string
+
+//===========================================================================
+
+//
+// builtin functions
+//
+
+void(vector ang) makevectors = #1; // sets v_forward, etc globals
+void(entity e, vector o) setorigin = #2;
+void(entity e, string m) setmodel = #3; // set movetype and solid first
+void(entity e, vector min, vector max) setsize = #4;
+// #5 was removed
+void() break_to_debugger = #6;
+float() random = #7; // returns 0 - 1
+void(entity e, float chan, string samp, float vol, float atten) sound = #8;
+vector(vector v) normalize = #9;
+void(string e, ...) error = #10;
+void(string e, ...) objerror = #11;
+float(vector v) vlen = #12;
+float(vector v) vectoyaw = #13;
+entity() spawn = #14;
+void(entity e) remove = #15;
+
+// sets trace_* globals
+// nomonsters can be:
+// An entity will also be ignored for testing if forent == test,
+// forent->owner == test, or test->owner == forent
+// a forent of world is ignored
+void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
+
+entity() checkclient = #17; // returns a client to look for
+entity(entity start, .string fld, string match) find = #18;
+string(string s) precache_sound = #19;
+string(string s) precache_model = #20;
+void(entity client, string s, ...)stuffcmd = #21;
+entity(vector org, float rad) findradius = #22;
+void(string s, ...) bprint = #23;
+void(entity client, string s, ...) sprint = #24;
+void(string s, ...) dprint = #25;
+string(float f) ftos = #26;
+string(vector v) vtos = #27;
+void() coredump = #28; // prints all edicts
+void() traceon = #29; // turns statment trace on
+void() traceoff = #30;
+void(entity e) eprint = #31; // prints an entire edict
+float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE
+// #33 was removed
+float() droptofloor= #34; // TRUE if landed on floor
+void(float style, string value) lightstyle = #35;
+float(float v) rint = #36; // round to nearest int
+float(float v) floor = #37; // largest integer <= v
+float(float v) ceil = #38; // smallest integer >= v
+// #39 was removed
+float(entity e) checkbottom = #40; // true if self is on ground
+float(vector v) pointcontents = #41; // returns a CONTENT_*
+// #42 was removed
+float(float f) fabs = #43;
+vector(entity e, float speed) aim = #44; // returns the shooting vector
+float(string s) cvar = #45; // return cvar.value
+void(string s, ...) localcmd = #46; // put string into local que
+entity(entity e) nextent = #47; // for looping through all ents
+void(vector o, vector d, float color, float count) particle = #48;// start a particle effect
+void() ChangeYaw = #49; // turn towards self.ideal_yaw
+ // at self.yaw_speed
+// #50 was removed
+vector(vector v) vectoangles = #51;
+
+//
+// direct client message generation
+//
+void(float to, float f) WriteByte = #52;
+void(float to, float f) WriteChar = #53;
+void(float to, float f) WriteShort = #54;
+void(float to, float f) WriteLong = #55;
+void(float to, float f) WriteCoord = #56;
+void(float to, float f) WriteAngle = #57;
+void(float to, string s, ...) WriteString = #58;
+void(float to, entity s) WriteEntity = #59;
+
+//
+// broadcast client message generation
+//
+
+// void(float f) bWriteByte = #59;
+// void(float f) bWriteChar = #60;
+// void(float f) bWriteShort = #61;
+// void(float f) bWriteLong = #62;
+// void(float f) bWriteCoord = #63;
+// void(float f) bWriteAngle = #64;
+// void(string s) bWriteString = #65;
+// void(entity e) bWriteEntity = #66;
+
+void(float step) movetogoal = #67;
+
+string(string s) precache_file = #68; // no effect except for -copy
+void(entity e) makestatic = #69;
+void(string s) changelevel = #70;
+
+//#71 was removed
+
+void(string var, string val) cvar_set = #72; // sets cvar.value
+
+void(entity client, string s, ...) centerprint = #73; // sprint, but in middle
+
+void(vector pos, string samp, float vol, float atten) ambientsound = #74;
+
+string(string s) precache_model2 = #75; // registered version only
+string(string s) precache_sound2 = #76; // registered version only
+string(string s) precache_file2 = #77; // registered version only
+
+void(entity e) setspawnparms = #78; // set parm1... to the
+ // values at level start
+ // for coop respawn
+
+//============================================================================
--- /dev/null
+#ifndef CLIENT_ALL_H
+#define CLIENT_ALL_H
+
+#include "../dpdefs/menudefs.qh"
+#include "../dpdefs/keycodes.qh"
+
+#endif
-#ifdef INTERFACE
-CLASS(Animation) EXTENDS(Object)
+#ifndef ANIM_ANIMATION_H
+#define ANIM_ANIMATION_H
+#include "../oo/base.qh"
+void setterDummy(entity, float);
+CLASS(Animation, Object)
METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float))
METHOD(Animation, setTimeStartEnd, void(entity, float, float))
METHOD(Animation, setTimeStartDuration, void(entity, float, float))
ATTRIB(Animation, stopped, float, false)
ATTRIB(Animation, finished, float, false)
ENDCLASS(Animation)
-void setterDummy(entity, float);
#endif
#ifdef IMPLEMENTATION
#include "../menu.qh"
-#ifdef INTERFACE
-CLASS(AnimHost) EXTENDS(Object)
+#ifndef ANIM_ANIMHOST_H
+#define ANIM_ANIMHOST_H
+#include "../oo/base.qh"
+CLASS(AnimHost, Object)
METHOD(AnimHost, addAnim, void(entity, entity))
METHOD(AnimHost, removeAnim, void(entity, entity))
METHOD(AnimHost, removeAllAnim, void(entity))
-#ifdef INTERFACE
-CLASS(Easing) EXTENDS(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)
-ENDCLASS(Easing)
+#ifndef ANIM_EASING_H
+#define ANIM_EASING_H
+#include "animation.qc"
entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
float easingLinear(float, float, float, float);
float easingQuadIn(float, float, float, float);
float easingQuadOut(float, float, float, float);
float easingQuadInOut(float, float, float, float);
+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)
+ENDCLASS(Easing)
#endif
#ifdef IMPLEMENTATION
entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
{
entity me;
- me = spawnEasing();
+ me = NEW(Easing);
me.configureAnimation(me, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
me.setMath(me, func);
return me;
-#ifdef INTERFACE
-CLASS(Keyframe) EXTENDS(Animation)
+#ifndef ANIM_KEYFRAME_H
+#define ANIM_KEYFRAME_H
+#include "animation.qc"
+CLASS(Keyframe, Animation)
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))
entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
{
entity me;
- me = spawnKeyframe();
+ me = NEW(Keyframe);
me.configureAnimation(me, obj, objSetter, time, animDuration, animStart, animEnd);
return me;
}
--- /dev/null
+#include "anim/animation.qc"
+#include "anim/animhost.qc"
+#include "anim/easing.qc"
+#include "anim/keyframe.qc"
+
+#include "item.qc"
+#include "item/borderimage.qc"
+#include "item/button.qc"
+#include "item/checkbox.qc"
+#include "item/container.qc"
+#include "item/dialog.qc"
+#include "item/image.qc"
+#include "item/inputbox.qc"
+#include "item/inputcontainer.qc"
+#include "item/label.qc"
+#include "item/listbox.qc"
+#include "item/modalcontroller.qc"
+#include "item/nexposee.qc"
+#include "item/radiobutton.qc"
+#include "item/slider.qc"
+#include "item/tab.qc"
+#include "item/textslider.qc"
+
+#include "xonotic/bigbutton.qc"
+#include "xonotic/bigcommandbutton.qc"
+#include "xonotic/button.qc"
+#include "xonotic/campaign.qc"
+#include "xonotic/charmap.qc"
+#include "xonotic/checkbox.qc"
+#include "xonotic/checkbox_slider_invalid.qc"
+#include "xonotic/checkbox_string.qc"
+#include "xonotic/colorbutton.qc"
+#include "xonotic/colorpicker.qc"
+#include "xonotic/colorpicker_string.qc"
+#include "xonotic/commandbutton.qc"
+#include "xonotic/credits.qc"
+#include "xonotic/crosshairpicker.qc"
+#include "xonotic/crosshairpreview.qc"
+#include "xonotic/cvarlist.qc"
+#include "xonotic/demolist.qc"
+#include "xonotic/dialog.qc"
+#include "xonotic/dialog_credits.qc"
+#include "xonotic/dialog_firstrun.qc"
+#include "xonotic/dialog_hudpanel_ammo.qc"
+#include "xonotic/dialog_hudpanel_buffs.qc"
+#include "xonotic/dialog_hudpanel_centerprint.qc"
+#include "xonotic/dialog_hudpanel_chat.qc"
+#include "xonotic/dialog_hudpanel_engineinfo.qc"
+#include "xonotic/dialog_hudpanel_healtharmor.qc"
+#include "xonotic/dialog_hudpanel_infomessages.qc"
+#include "xonotic/dialog_hudpanel_modicons.qc"
+#include "xonotic/dialog_hudpanel_notification.qc"
+#include "xonotic/dialog_hudpanel_physics.qc"
+#include "xonotic/dialog_hudpanel_powerups.qc"
+#include "xonotic/dialog_hudpanel_pressedkeys.qc"
+#include "xonotic/dialog_hudpanel_racetimer.qc"
+#include "xonotic/dialog_hudpanel_radar.qc"
+#include "xonotic/dialog_hudpanel_score.qc"
+#include "xonotic/dialog_hudpanel_timer.qc"
+#include "xonotic/dialog_hudpanel_vote.qc"
+#include "xonotic/dialog_hudpanel_weapons.qc"
+#include "xonotic/dialog_hudsetup_exit.qc"
+#include "xonotic/dialog_monstertools.qc"
+#include "xonotic/dialog_multiplayer.qc"
+#include "xonotic/dialog_multiplayer_create.qc"
+#include "xonotic/dialog_multiplayer_create_mapinfo.qc"
+#include "xonotic/dialog_multiplayer_create_mutators.qc"
+#include "xonotic/dialog_multiplayer_join.qc"
+#include "xonotic/dialog_multiplayer_join_serverinfo.qc"
+#include "xonotic/dialog_multiplayer_media.qc"
+#include "xonotic/dialog_multiplayer_media_demo.qc"
+#include "xonotic/dialog_multiplayer_media_demo_startconfirm.qc"
+#include "xonotic/dialog_multiplayer_media_demo_timeconfirm.qc"
+#include "xonotic/dialog_multiplayer_media_musicplayer.qc"
+#include "xonotic/dialog_multiplayer_media_screenshot.qc"
+#include "xonotic/dialog_multiplayer_media_screenshot_viewer.qc"
+#include "xonotic/dialog_multiplayer_profile.qc"
+#include "xonotic/dialog_quit.qc"
+#include "xonotic/dialog_sandboxtools.qc"
+#include "xonotic/dialog_settings.qc"
+#include "xonotic/dialog_settings_audio.qc"
+#include "xonotic/dialog_settings_effects.qc"
+#include "xonotic/dialog_settings_game.qc"
+#include "xonotic/dialog_settings_game_crosshair.qc"
+#include "xonotic/dialog_settings_game_hudconfirm.qc"
+#include "xonotic/dialog_settings_game_hud.qc"
+#include "xonotic/dialog_settings_game_messages.qc"
+#include "xonotic/dialog_settings_game_model.qc"
+#include "xonotic/dialog_settings_game_view.qc"
+#include "xonotic/dialog_settings_game_weapons.qc"
+#include "xonotic/dialog_settings_input.qc"
+#include "xonotic/dialog_settings_input_userbind.qc"
+#include "xonotic/dialog_settings_misc.qc"
+#include "xonotic/dialog_settings_misc_cvars.qc"
+#include "xonotic/dialog_settings_misc_reset.qc"
+#include "xonotic/dialog_settings_user.qc"
+#include "xonotic/dialog_settings_user_languagewarning.qc"
+#include "xonotic/dialog_settings_video.qc"
+#include "xonotic/dialog_singleplayer.qc"
+#include "xonotic/dialog_singleplayer_winner.qc"
+#include "xonotic/dialog_teamselect.qc"
+#include "xonotic/gametypelist.qc"
+#include "xonotic/image.qc"
+#include "xonotic/inputbox.qc"
+#include "xonotic/keybinder.qc"
+#include "xonotic/languagelist.qc"
+#include "xonotic/listbox.qc"
+#include "xonotic/mainwindow.qc"
+#include "xonotic/maplist.qc"
+#include "xonotic/nexposee.qc"
+#include "xonotic/picker.qc"
+#include "xonotic/playerlist.qc"
+#include "xonotic/playermodel.qc"
+#include "xonotic/playlist.qc"
+#include "xonotic/radiobutton.qc"
+#include "xonotic/rootdialog.qc"
+#include "xonotic/screenshotimage.qc"
+#include "xonotic/screenshotlist.qc"
+#include "xonotic/serverlist.qc"
+#include "xonotic/skinlist.qc"
+#include "xonotic/slider.qc"
+#include "xonotic/slider_decibels.qc"
+#include "xonotic/slider_particles.qc"
+#include "xonotic/slider_picmip.qc"
+#include "xonotic/slider_resolution.qc"
+#include "xonotic/slider_sbfadetime.qc"
+#include "xonotic/soundlist.qc"
+#include "xonotic/statslist.qc"
+#include "xonotic/tabcontroller.qc"
+#include "xonotic/tab.qc"
+#include "xonotic/textlabel.qc"
+#include "xonotic/textslider.qc"
+#include "xonotic/weaponarenacheckbox.qc"
+#include "xonotic/weaponslist.qc"
+++ /dev/null
-#include "anim/animhost.qc"
-#include "anim/animation.qc"
-#include "anim/easing.qc"
-#include "anim/keyframe.qc"
-#include "item.qc"
-#include "item/container.qc"
-#include "item/inputcontainer.qc"
-#include "item/nexposee.qc"
-#include "item/modalcontroller.qc"
-#include "item/image.qc"
-#include "item/label.qc"
-#include "item/button.qc"
-#include "item/checkbox.qc"
-#include "item/radiobutton.qc"
-#include "item/borderimage.qc"
-#include "item/slider.qc"
-#include "item/dialog.qc"
-#include "item/tab.qc"
-#include "item/textslider.qc"
-#include "item/listbox.qc"
-#include "item/inputbox.qc"
-#include "xonotic/dialog.qc"
-#include "xonotic/tab.qc"
-#include "xonotic/mainwindow.qc"
-#include "xonotic/button.qc"
-#include "xonotic/bigbutton.qc"
-#include "xonotic/commandbutton.qc"
-#include "xonotic/bigcommandbutton.qc"
-#include "xonotic/textlabel.qc"
-#include "xonotic/dialog_firstrun.qc"
-#include "xonotic/dialog_teamselect.qc"
-#include "xonotic/dialog_sandboxtools.qc"
-#include "xonotic/dialog_monstertools.qc"
-#include "xonotic/dialog_settings.qc"
-#include "xonotic/dialog_settings_video.qc"
-#include "xonotic/dialog_settings_effects.qc"
-#include "xonotic/dialog_settings_audio.qc"
-#include "xonotic/dialog_settings_game.qc"
-#include "xonotic/dialog_settings_user.qc"
-#include "xonotic/dialog_settings_user_languagewarning.qc"
-#include "xonotic/dialog_settings_misc.qc"
-#include "xonotic/dialog_multiplayer.qc"
-#include "xonotic/dialog_multiplayer_profile.qc"
-#include "xonotic/tabcontroller.qc"
-#include "xonotic/slider.qc"
-#include "xonotic/slider_resolution.qc"
-#include "xonotic/checkbox.qc"
-#include "xonotic/checkbox_string.qc"
-#include "xonotic/weaponarenacheckbox.qc"
-#include "xonotic/radiobutton.qc"
-#include "xonotic/nexposee.qc"
-#include "xonotic/rootdialog.qc"
-#include "xonotic/textslider.qc"
-#include "xonotic/colorbutton.qc"
-#include "xonotic/dialog_multiplayer_join.qc"
-#include "xonotic/dialog_multiplayer_join_serverinfo.qc"
-#include "xonotic/playerlist.qc"
-#include "xonotic/listbox.qc"
-#include "xonotic/serverlist.qc"
-#include "xonotic/inputbox.qc"
-#include "xonotic/dialog_quit.qc"
-#include "xonotic/dialog_multiplayer_create.qc"
-#include "xonotic/dialog_multiplayer_create_mutators.qc"
-#include "xonotic/dialog_multiplayer_create_mapinfo.qc"
-#include "xonotic/gametypelist.qc"
-#include "xonotic/maplist.qc"
-#include "xonotic/skinlist.qc"
-#include "xonotic/languagelist.qc"
-#include "xonotic/image.qc"
-#include "xonotic/crosshairbutton.qc"
-#include "xonotic/playermodel.qc"
-#include "xonotic/checkbox_slider_invalid.qc"
-#include "xonotic/charmap.qc"
-#include "xonotic/keybinder.qc"
-#include "xonotic/dialog_settings_input.qc"
-#include "xonotic/dialog_settings_input_userbind.qc"
-#include "xonotic/slider_decibels.qc"
-#include "xonotic/dialog_singleplayer.qc"
-#include "xonotic/campaign.qc"
-#include "xonotic/dialog_singleplayer_winner.qc"
-#include "xonotic/dialog_credits.qc"
-#include "xonotic/credits.qc"
-#include "xonotic/dialog_settings_game_crosshair.qc"
-#include "xonotic/dialog_settings_game_hud.qc"
-#include "xonotic/dialog_settings_game_hudconfirm.qc"
-#include "xonotic/dialog_settings_game_model.qc"
-#include "xonotic/dialog_settings_game_messages.qc"
-#include "xonotic/dialog_settings_game_view.qc"
-#include "xonotic/dialog_settings_game_weapons.qc"
-#include "xonotic/weaponslist.qc"
-#include "xonotic/dialog_multiplayer_media.qc"
-#include "xonotic/dialog_multiplayer_media_demo.qc"
-#include "xonotic/dialog_multiplayer_media_demo_startconfirm.qc"
-#include "xonotic/dialog_multiplayer_media_demo_timeconfirm.qc"
-#include "xonotic/demolist.qc"
-#include "xonotic/screenshotimage.qc"
-#include "xonotic/dialog_multiplayer_media_screenshot.qc"
-#include "xonotic/dialog_multiplayer_media_screenshot_viewer.qc"
-#include "xonotic/screenshotlist.qc"
-#include "xonotic/statslist.qc"
-#include "xonotic/dialog_multiplayer_media_musicplayer.qc"
-#include "xonotic/soundlist.qc"
-#include "xonotic/playlist.qc"
-#include "xonotic/colorpicker.qc"
-#include "xonotic/colorpicker_string.qc"
-#include "xonotic/cvarlist.qc"
-#include "xonotic/dialog_settings_misc_cvars.qc"
-#include "xonotic/dialog_hudsetup_exit.qc"
-#include "xonotic/dialog_hudpanel_notification.qc"
-#include "xonotic/dialog_hudpanel_ammo.qc"
-#include "xonotic/dialog_hudpanel_healtharmor.qc"
-#include "xonotic/dialog_hudpanel_powerups.qc"
-#include "xonotic/dialog_hudpanel_racetimer.qc"
-#include "xonotic/dialog_hudpanel_pressedkeys.qc"
-#include "xonotic/dialog_hudpanel_radar.qc"
-#include "xonotic/dialog_hudpanel_score.qc"
-#include "xonotic/dialog_hudpanel_timer.qc"
-#include "xonotic/dialog_hudpanel_vote.qc"
-#include "xonotic/dialog_hudpanel_modicons.qc"
-#include "xonotic/dialog_hudpanel_chat.qc"
-#include "xonotic/dialog_hudpanel_engineinfo.qc"
-#include "xonotic/dialog_hudpanel_infomessages.qc"
-#include "xonotic/dialog_hudpanel_weapons.qc"
-#include "xonotic/dialog_hudpanel_physics.qc"
-#include "xonotic/dialog_hudpanel_centerprint.qc"
-#include "xonotic/dialog_hudpanel_buffs.qc"
-#include "xonotic/slider_picmip.qc"
-#include "xonotic/slider_particles.qc"
-#include "xonotic/slider_sbfadetime.qc"
-#include "xonotic/dialog_settings_misc_reset.qc"
--- /dev/null
+#include "../menu.qh"
+
+#include "../../common/command/all.qc"
+
+#include "menu_cmd.qc"
--- /dev/null
+#ifndef MENU_COMMANDS_ALL_H
+#define MENU_COMMANDS_ALL_H
+
+#include "../../common/command/commands.qh"
+
+#include "menu_cmd.qh"
+
+#endif
#include "menu_cmd.qh"
+#include "../menu.qh"
+#include "../oo/classes.qc"
+
#include "../../common/command/generic.qh"
+.entity firstChild, nextSibling;
+
string _dumptree_space;
void _dumptree_open(entity pass, entity me)
{
}
}
+float updateConwidths(float width, float height, float pixelheight);
+
void GameCommand(string theCommand)
{
float argc;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "draw.qh"
+#include "../common/util.qh"
+#include "../common/constants.qh"
string draw_mousepointer;
vector draw_mousepointer_offset;
-#ifdef INTERFACE
-CLASS(Item) EXTENDS(Object)
+#ifndef ITEM_H
+#define ITEM_H
+#include "skin.qh"
+#include "oo/base.qh"
+CLASS(Item, Object)
METHOD(Item, draw, void(entity))
METHOD(Item, keyDown, float(entity, float, float, float))
METHOD(Item, keyUp, float(entity, float, float, float))
-#ifdef INTERFACE
-CLASS(BorderImage) EXTENDS(Label)
+#ifndef ITEM_BORDERIMAGE_H
+#define ITEM_BORDERIMAGE_H
+#include "label.qc"
+CLASS(BorderImage, Label)
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))
-#ifdef INTERFACE
-CLASS(Button) EXTENDS(Label)
+#ifndef ITEM_BUTTON_H
+#define ITEM_BUTTON_H
+#include "label.qc"
+CLASS(Button, Label)
METHOD(Button, configureButton, void(entity, string, float, string))
METHOD(Button, draw, void(entity))
METHOD(Button, showNotify, void(entity))
-#ifdef INTERFACE
+#ifndef ITEM_CHECKBOX_H
+#define ITEM_CHECKBOX_H
+#include "button.qc"
void CheckBox_Click(entity me, entity other);
-CLASS(CheckBox) EXTENDS(Button)
+CLASS(CheckBox, Button)
METHOD(CheckBox, configureCheckBox, void(entity, string, float, string))
METHOD(CheckBox, draw, void(entity))
METHOD(CheckBox, playClickSound, void(entity))
-#ifdef INTERFACE
-CLASS(Container) EXTENDS(Item)
+#ifndef ITEM_CONTAINER_H
+#define ITEM_CONTAINER_H
+#include "../item.qc"
+CLASS(Container, Item)
METHOD(Container, draw, void(entity))
METHOD(Container, keyUp, float(entity, float, float, float))
METHOD(Container, keyDown, float(entity, float, float, float))
METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector))
METHOD(Container, addItem, void(entity, entity, vector, vector, float))
METHOD(Container, addItemCentered, void(entity, entity, vector, float))
+ METHOD(Container, addItemRightCentered, void(entity, entity, vector, float))
METHOD(Container, moveItemAfter, void(entity, entity, entity))
METHOD(Container, removeItem, void(entity, entity))
METHOD(Container, setFocus, void(entity, entity))
float d;
for(e = me.firstChild; e; e = e.nextSibling)
{
- o = e.originField;
- s = e.sizeField;
- me.enterLieSubitem(me, o, s, e.fontScaleField, e.Container_alpha);
+ o = e.(originField);
+ s = e.(sizeField);
+ me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
me.leaveSubitem(me);
}
{
e.resized = 0;
d = 1;
- o = e.originField;
- s = e.sizeField;
- me.enterLieSubitem(me, o, s, e.fontScaleField, e.Container_alpha);
+ o = e.(originField);
+ s = e.(sizeField);
+ me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
me.leaveSubitem(me);
}
me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
}
+void Container_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
+{
+ me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
+}
+
void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
{
if(other.parent)
//
// a subclass may help with using this as a tab
-#ifdef INTERFACE
-CLASS(Dialog) EXTENDS(InputContainer)
+#ifndef ITEM_DIALOG_H
+#define ITEM_DIALOG_H
+#include "inputcontainer.qc"
+CLASS(Dialog, InputContainer)
METHOD(Dialog, configureDialog, void(entity)) // no runtime configuration, all parameters are given in the code!
METHOD(Dialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
METHOD(Dialog, keyDown, float(entity, float, float, float))
{
float absWidth, absHeight;
- me.frame = spawnBorderImage();
- me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
- me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
- me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
- me.frame.alpha = me.alpha;
- me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+ if(me.isTabRoot)
+ {
+ me.frame = NEW(BorderImage);
+ me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
+ me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
+ me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
+ me.frame.alpha = me.alpha;
+ me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+ }
if (!me.titleFontSize)
me.titleHeight = 0; // no title bar
me.fill(me);
- if(me.closable && me.borderLines > 0)
+ if(me.isTabRoot && me.closable && me.borderLines > 0)
{
entity closebutton;
- closebutton = me.closeButton = me.frame.closeButton = spawnButton();
+ closebutton = me.closeButton = me.frame.closeButton = NEW(Button);
closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
closebutton.onClick = Dialog_Close; closebutton.onClickEntity = me;
closebutton.srcMulti = 0;
-#ifdef INTERFACE
-CLASS(Image) EXTENDS(Item)
+#ifndef ITEM_IMAGE_H
+#define ITEM_IMAGE_H
+#include "../item.qc"
+CLASS(Image, Item)
METHOD(Image, configureImage, void(entity, string))
METHOD(Image, draw, void(entity))
METHOD(Image, toString, string(entity))
-#ifdef INTERFACE
-CLASS(InputBox) EXTENDS(Label)
+#ifndef ITEM_INPUTBOX_H
+#define ITEM_INPUTBOX_H
+#include "label.qc"
+CLASS(InputBox, Label)
METHOD(InputBox, configureInputBox, void(entity, string, float, float, string))
METHOD(InputBox, draw, void(entity))
METHOD(InputBox, setText, void(entity, string))
-#ifdef INTERFACE
-CLASS(InputContainer) EXTENDS(Container)
+#ifndef ITEM_INPUTCONTAINER_H
+#define ITEM_INPUTCONTAINER_H
+#include "container.qc"
+CLASS(InputContainer, Container)
METHOD(InputContainer, keyDown, float(entity, float, float, float))
METHOD(InputContainer, mouseMove, float(entity, vector))
METHOD(InputContainer, mousePress, float(entity, vector))
-#ifdef INTERFACE
-CLASS(Label) EXTENDS(Item)
+#ifndef ITEM_LABEL_H
+#define ITEM_LABEL_H
+#include "../item.qc"
+CLASS(Label, Item)
METHOD(Label, configureLabel, void(entity, string, float, float))
METHOD(Label, draw, void(entity))
METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector))
-#ifdef INTERFACE
-CLASS(ListBox) EXTENDS(Item)
+#ifndef ITEM_LISTBOX_H
+#define ITEM_LISTBOX_H
+#include "../item.qc"
+CLASS(ListBox, Item)
METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(ListBox, configureListBox, void(entity, float, float))
METHOD(ListBox, draw, void(entity))
METHOD(ListBox, keyDown, float(entity, float, float, float))
+ METHOD(ListBox, mouseMove, float(entity, vector))
METHOD(ListBox, mousePress, float(entity, vector))
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, allowFocusSound, float, 1)
- ATTRIB(ListBox, selectedItem, float, 0)
+ 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, lastClickedItem, float, -1)
ATTRIB(ListBox, lastClickedTime, float, 0)
- METHOD(ListBox, drawListBoxItem, void(entity, float, vector, float)) // item number, width/height, selected
+ 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(ListBox, doubleClickListBoxItem, void(entity, float, vector)) // item number, relative clickpos
METHOD(ListBox, setSelected, void(entity, float))
return 0;
return 1;
}
+float ListBox_mouseMove(entity me, vector pos)
+{
+ if(pos_x < 0) return 0;
+ if(pos_y < 0) return 0;
+ if(pos_x >= 1) return 0;
+ if(pos_y >= 1) return 0;
+ if(pos_x < 1 - me.controlWidth)
+ {
+ float x;
+ x = me.focusedItem;
+ me.focusedItem = me.getItemAtPos(me, me.scrollPos + pos.y);
+ if(x != me.focusedItem)
+ me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
+ }
+ return 1;
+}
float ListBox_mouseDrag(entity me, vector pos)
{
float hit;
// by a mouse click on an item of the list
// for example showing a dialog on right click
me.pressed = 0;
+ me.focusedItem = -1;
}
void ListBox_updateControlTopBottom(entity me)
{
draw_SetClip();
oldshift = draw_shift;
oldscale = draw_scale;
+
float y;
i = me.getItemAtPos(me, me.scrollPos);
y = me.getItemStart(me, i) - me.scrollPos;
vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
absSize = boxToGlobalSize(relSize, me.size);
draw_scale = boxToGlobalSize(relSize, oldscale);
- me.drawListBoxItem(me, i, absSize, (me.selectedItem == i));
+ me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
y += relSize.y;
}
draw_ClearClip();
// template method
}
-void ListBox_drawListBoxItem(entity me, float i, vector absSize, float selected)
+void ListBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
- draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (selected ? '0 1 0' : '1 1 1'), 1, 0);
+ draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (isSelected ? '0 1 0' : '1 1 1'), 1, 0);
}
#endif
-#ifdef INTERFACE
-CLASS(ModalController) EXTENDS(Container)
+#ifndef ITEM_MODALCONTROLLER_H
+#define ITEM_MODALCONTROLLER_H
+#include "container.qc"
+CLASS(ModalController, Container)
METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(ModalController, draw, void(entity))
METHOD(ModalController, showChild, void(entity, entity, vector, vector, float))
-#ifdef INTERFACE
-CLASS(Nexposee) EXTENDS(Container)
+#ifndef ITEM_NEXPOSEE_H
+#define ITEM_NEXPOSEE_H
+#include "container.qc"
+CLASS(Nexposee, Container)
METHOD(Nexposee, draw, void(entity))
METHOD(Nexposee, keyDown, float(entity, float, float, float))
METHOD(Nexposee, keyUp, float(entity, float, float, float))
ENDCLASS(Nexposee)
void ExposeeCloseButton_Click(entity button, entity other); // un-exposees the current state
-#endif
// animation states:
// 0 = thumbnails seen
// 2 = zoomed in
// 3 = zooming out
// animation factor: 0 = minimum theSize, 1 = maximum theSize
-
-#ifdef IMPLEMENTATION
-
.vector Nexposee_initialSize;
.vector Nexposee_initialFontScale;
.vector Nexposee_initialOrigin;
.vector Nexposee_align;
.float Nexposee_animationFactor;
+#endif
+
+#ifdef IMPLEMENTATION
void Nexposee_close(entity me)
{
// user must override this
-#ifdef INTERFACE
+#ifndef ITEM_RADIOBUTTON_H
+#define ITEM_RADIOBUTTON_H
+#include "checkbox.qc"
void RadioButton_Click(entity me, entity other);
-CLASS(RadioButton) EXTENDS(CheckBox)
+CLASS(RadioButton, CheckBox)
METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float))
ATTRIB(RadioButton, checked, float, 0)
ATTRIB(RadioButton, group, float, 0)
// Note:
// to use this, you FIRST call configureSliderVisuals, then configureSliderValues
-#ifdef INTERFACE
-CLASS(Slider) EXTENDS(Label)
+#ifndef ITEM_SLIDER_H
+#define ITEM_SLIDER_H
+#include "label.qc"
+CLASS(Slider, Label)
METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string))
METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float))
-#ifdef INTERFACE
-CLASS(Tab) EXTENDS(Dialog)
+#ifndef ITEM_TAB_H
+#define ITEM_TAB_H
+#include "dialog.qc"
+CLASS(Tab, Dialog)
ATTRIB(Tab, isTabRoot, float, 0)
ATTRIB(Tab, closable, float, 0)
ATTRIB(Tab, rootDialog, float, 0)
// Note:
// to use this, you FIRST call configureSliderVisuals, then multiple times addValue, then configureTextSlider
-#ifdef INTERFACE
-CLASS(TextSlider) EXTENDS(Slider)
+#ifndef ITEM_TEXTSLIDER_H
+#define ITEM_TEXTSLIDER_H
+#include "slider.qc"
+CLASS(TextSlider, Slider)
METHOD(TextSlider, valueToText, string(entity, float))
METHOD(TextSlider, valueToIdentifier, string(entity, float))
METHOD(TextSlider, setValueFromIdentifier, void(entity, string))
METHOD(TextSlider, configureTextSliderValues, void(entity, string))
ATTRIBARRAY(TextSlider, valueStrings, string, 256)
ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
- ATTRIB(TextSlider, nValues, float, 0)
+ ATTRIB(TextSlider, nValues, int, 0)
ENDCLASS(TextSlider)
#endif
#ifdef IMPLEMENTATION
-string TextSlider_valueToIdentifier(entity me, float val)
+string TextSlider_valueToIdentifier(entity me, int val)
{
if(val >= me.nValues)
return "custom";
return "custom";
return me.(valueIdentifiers[val]);
}
-string TextSlider_valueToText(entity me, float val)
+string TextSlider_valueToText(entity me, int val)
{
if(val >= me.nValues)
return _("Custom");
}
void TextSlider_setValueFromIdentifier(entity me, string id)
{
- float i;
+ int i;
for(i = 0; i < me.nValues; ++i)
if(me.valueToIdentifier(me, i) == id)
{
me.(valueIdentifiers[me.nValues]) = theIdentifier;
me.nValues += 1;
}
-void TextSlider_insertValue(entity me, float pos, string theString, string theIdentifier)
+void TextSlider_insertValue(entity me, int pos, string theString, string theIdentifier)
{
- float i;
+ int i;
for (i = me.nValues; i > pos; --i)
{
me.(valueStrings[i]) = me.(valueStrings[i-1]);
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
+#include "menu.qh"
+#include "oo/classes.qc"
+#include "xonotic/util.qh"
+
+#include "../common/items/all.qh"
+#include "../common/weapons/all.qh"
+#include "../common/mapinfo.qh"
///////////////////////////////////////////////
// Menu Source File
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
RegisterSLCategories();
draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);
loadTooltips();
- anim = spawnAnimHost();
- main = spawnMainWindow(); main.configureMainWindow(main);
+ anim = NEW(AnimHost);
+ main = NEW(MainWindow); main.configureMainWindow(main);
unloadTooltips();
main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
menuMousePos = focus.origin + 0.5 * focus.size;
menuMousePos.x *= 1 / conwidth;
menuMousePos.y *= 1 / conheight;
- if(wnd.focused) // why does this never happen?
+ entity par = wnd.parent;
+ if(par.focused)
+ par.setFocus(par, wnd);
+ if(wnd.focused)
m_focus_item_chain(wnd, focus);
}
}
#define localcmd cmd
-#define NULL (null_entity)
-#define world NULL
-
// constants
const int GAME_ISSERVER = 1;
void m_sync();
+void draw_reset_cropped();
+
// sounds
const string MENU_SOUND_CLEAR = "sound/menu/clear.wav";
#ifndef BASE_H
#define BASE_H
-.string classname;
-entity Object_vtbl;
-.string vtblname;
-.entity vtblbase;
-// THIS LINE INTENTIONALLY LEFT BLANK
-entity spawnVtbl(entity e, entity b)
-{
- entity v;
- v = spawn();
- copyentity(e, v);
- v.vtblname = v.classname;
- v.classname = "vtbl";
- if(b)
- v.vtblbase = b;
- else
- v.vtblbase = v;
- return v;
-}
-entity spawnObject()
-{
- entity e;
- e = spawn();
- e.classname = "Object";
- if(!Object_vtbl)
- Object_vtbl = spawnVtbl(e, null_entity);
- return e;
-}
+#include "../../common/oo.qh"
+
+#include "../../common/util.qh"
+#include "../../dpdefs/keycodes.qh"
+
+#define world NULL
+
#endif
--- /dev/null
+#ifndef CLASSES_H
+#define CLASSES_H
+#include "base.qh"
+
+#include "../classes.inc"
+#define IMPLEMENTATION
+#include "../classes.inc"
+
+#endif
+++ /dev/null
-#ifndef IMPLEMENTATION_H
-#define IMPLEMENTATION_H
-
-#ifndef INTERFACE
-#define INTERFACE
-#endif
-
-#ifndef IMPLEMENTATION
-#define IMPLEMENTATION
-#endif
-
-#ifdef CLASS
-#undef CLASS
-#undef EXTENDS
-#undef METHOD
-#undef ATTRIB
-#undef ATTRIBARRAY
-#undef ENDCLASS
-#undef SUPER
-#endif
-
-// for the constructor
-#define CLASS(cname) entity spawn##cname() { entity me;
-#define EXTENDS(base) me = spawn##base (); entity basevtbl; basevtbl = base##_vtbl;
-#define METHOD(cname,name,prototype) me.name = cname##_##name;
-#define ATTRIB(cname,name,type,val) me.name = val;
-#define ATTRIBARRAY(cname,name,type,cnt)
-#define ENDCLASS(cname) me.instanceOf##cname = 1; me.classname = #cname; if(!cname##_vtbl) cname##_vtbl = spawnVtbl(me, basevtbl); return me; }
-
-// for the implementation
-#define SUPER(cname) (cname##_vtbl.vtblbase)
-#endif
+++ /dev/null
-#ifndef INTERFACE_H
-#define INTERFACE_H
-
-#ifndef INTERFACE
-#define INTERFACE
-#endif
-
-#ifdef IMPLEMENTATION
-#undef IMPLEMENTATION
-#endif
-
-#ifdef CLASS
-#undef CLASS
-#undef EXTENDS
-#undef METHOD
-#undef ATTRIB
-#undef ATTRIBARRAY
-#undef ENDCLASS
-#undef SUPER
-#endif
-
-#define CLASS(cname) entity spawn##cname(); entity cname##_vtbl;
-#define EXTENDS(base)
-#define METHOD(cname,name,prototype) prototype cname##_##name; .prototype name;
-#define ATTRIB(cname,name,type,val) .type name;
-#define ATTRIBARRAY(cname,name,type,cnt) .type name[cnt];
-#define ENDCLASS(cname) .float instanceOf##cname;
-#define SUPER(cname)
-#endif
../dpdefs/menudefs.qh
../dpdefs/keycodes.qh
-oo/interface.qh
- classes.qc
-oo/implementation.qh
- classes.qc
+oo/classes.qc
draw.qc
menu.qc
-command/menu_cmd.qc
+command/all.qc
xonotic/util.qc
../common/urllib.qc
../common/util.qc
-../common/command/generic.qc
-../common/command/markup.qc
-../common/command/rpn.qc
+../common/items/all.qc
-../common/monsters/monsters.qc
+../common/monsters/all.qc
-../common/weapons/weapons.qc // TODO
+../common/weapons/all.qc // TODO
../warpzonelib/mathlib.qc
SKINFLOAT(ROWS_CREDITS, 20);
SKINFLOAT(WIDTH_CREDITS, 0.5);
- // item: crosshair button
- SKINSTRING(GFX_CROSSHAIRBUTTON, "crosshairbutton");
-
// item: cvar list
SKINFLOAT(ALPHA_CVARLIST_SAVED, 1);
SKINFLOAT(ALPHA_CVARLIST_TEMPORARY, 0.7);
SKINVECTOR(COLOR_CLEARBUTTON_F, '1 1 1');
SKINVECTOR(COLOR_CLEARBUTTON_C, '1 1 1');
+ // item: gametype list
+ SKINFLOAT(BOOL_GAMETYPELIST_ICON_BLUR, 1);
+
// item: key grabber
SKINVECTOR(COLOR_KEYGRABBER_TITLES, '1 1 1');
SKINFLOAT(ALPHA_KEYGRABBER_TITLES, 1);
SKINFLOAT(ALPHA_LISTBOX_WAITING, 0.5);
SKINVECTOR(COLOR_LISTBOX_BACKGROUND, '0 0 0');
SKINFLOAT(ALPHA_LISTBOX_BACKGROUND, 0.5);
+ SKINVECTOR(COLOR_LISTBOX_FOCUSED, '0 0 1');
+ SKINFLOAT(ALPHA_LISTBOX_FOCUSED, 0.7);
+ SKINFLOAT(FADEALPHA_LISTBOX_FOCUSED, 0.3);
// item: map list
SKINVECTOR(COLOR_MAPLIST_TITLE, '1 1 1');
SKINVECTOR(COLOR_MODELTITLE, '1 1 1');
SKINFLOAT(ALPHA_MODELTITLE, 1);
- // item: player name editor
+ // item: special character picker
SKINVECTOR(COLOR_CHARMAP_CHAR, '1 1 1');
SKINFLOAT(ALPHA_CHARMAP_CHAR, 1);
- SKINVECTOR(COLOR_CHARMAP_FOCUS, '0 0 1');
- SKINFLOAT(ALPHA_CHARMAP_FOCUS, 0.5);
+
+ // item: crosshair picker
+ SKINVECTOR(COLOR_CROSSHAIRPICKER_CROSSHAIR, '1 1 1');
+ SKINFLOAT(ALPHA_CROSSHAIRPICKER_CROSSHAIR, 1);
// item: radio button
SKINSTRING(GFX_RADIOBUTTON, "radiobutton");
SKINVECTOR(COLOR_SERVERLIST_FAVORITE, '1 1 1');
SKINFLOAT(ALPHA_SERVERLIST_IMPOSSIBLE, 0.7);
SKINVECTOR(COLOR_SERVERLIST_IMPOSSIBLE, '0.3 0.3 0.3');
- SKINSTRING(GFX_SERVERLIST_ICON, "icon");
SKINFLOAT(ALPHA_SERVERLIST_ICON_NONPURE, 0.5);
// item: server info
#undef SKINFLOAT
#undef SKINVECTOR
-#define SKINBEGIN void Skin_ApplySetting(string key, string value) { switch(key) {
-#define SKINVECTOR(name,def) case #name: SKIN##name = stov(value); break
-#define SKINFLOAT(name,def) case #name: SKIN##name = stof(value); break
+#define SKINBEGIN void Skin_ApplySetting(string key, string _value) { switch(key) {
+#define SKINVECTOR(name,def) case #name: SKIN##name = stov(_value); break
+#define SKINFLOAT(name,def) case #name: SKIN##name = stof(_value); break
//#define SKINSTRING(name,def) case #name: break
-#define SKINSTRING(name,def) case #name: SKIN##name = strzone(value); 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: dprint("Invalid key in skin file: ", key, "\n"); } }
#include "skin-customizables.inc"
-#ifdef INTERFACE
-CLASS(XonoticBigButton) EXTENDS(XonoticButton)
+#ifndef BIGBUTTON_H
+#define BIGBUTTON_H
+#include "button.qc"
+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)
entity makeXonoticBigButton(string theText, vector theColor)
{
entity me;
- me = spawnXonoticBigButton();
+ me = NEW(XonoticBigButton);
me.configureXonoticBigButton(me, theText, theColor);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticBigCommandButton) EXTENDS(XonoticCommandButton)
+#ifndef BIGCOMMANDBUTTON_H
+#define BIGCOMMANDBUTTON_H
+#include "commandbutton.qc"
+CLASS(XonoticBigCommandButton, XonoticCommandButton)
METHOD(XonoticBigCommandButton, configureXonoticBigCommandButton, void(entity, string, vector, string, float))
ATTRIB(XonoticBigCommandButton, image, string, SKINGFX_BUTTON_BIG)
ATTRIB(XonoticBigCommandButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
entity makeXonoticBigCommandButton(string theText, vector theColor, string theCommand, float theFlags)
{
entity me;
- me = spawnXonoticBigCommandButton();
+ me = NEW(XonoticBigCommandButton);
me.configureXonoticBigCommandButton(me, theText, theColor, theCommand, theFlags);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticButton) EXTENDS(Button)
+#ifndef BUTTON_H
+#define BUTTON_H
+#include "../item/button.qc"
+CLASS(XonoticButton, Button)
METHOD(XonoticButton, configureXonoticButton, void(entity, string, vector))
ATTRIB(XonoticButton, fontSize, float, SKINFONTSIZE_NORMAL)
ATTRIB(XonoticButton, image, string, SKINGFX_BUTTON)
entity makeXonoticButton(string theText, vector theColor)
{
entity me;
- me = spawnXonoticButton();
+ me = NEW(XonoticButton);
me.configureXonoticButton(me, theText, theColor);
return me;
}
#include "../../common/campaign_common.qh"
-#ifdef INTERFACE
-CLASS(XonoticCampaignList) EXTENDS(XonoticListBox)
+#ifndef CAMPAIGN_H
+#define CAMPAIGN_H
+#include "listbox.qc"
+CLASS(XonoticCampaignList, XonoticListBox)
METHOD(XonoticCampaignList, configureXonoticCampaignList, void(entity))
ATTRIB(XonoticCampaignList, rowsPerItem, float, 10)
METHOD(XonoticCampaignList, draw, void(entity))
- METHOD(XonoticCampaignList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticCampaignList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticCampaignList, doubleClickListBoxItem, void(entity, float, vector))
METHOD(XonoticCampaignList, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(XonoticCampaignList, setSelected, void(entity, float))
void rewrapCampaign(float w, float l0, float emptyheight, vector theFontSize)
{
- float i, j;
- float n, l;
+ int i, j;
+ int n;
+ float l;
string r, s;
for(i = 0; i < campaign_entries; ++i)
{
entity makeXonoticCampaignList()
{
entity me;
- me = spawnXonoticCampaignList();
+ me = NEW(XonoticCampaignList);
me.configureXonoticCampaignList(me);
return me;
}
{
CampaignList_LoadMap(me, me);
}
-void XonoticCampaignList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticCampaignList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
vector theColor;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
if(draw_PictureSize(strcat("/maps/", campaign_mapname[i])) == '0 0 0')
draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
-#ifdef INTERFACE
-CLASS(XonoticCharmap) EXTENDS(Item)
+#ifndef CHARMAP_H
+#define CHARMAP_H
+#include "picker.qc"
+CLASS(XonoticCharmap, XonoticPicker)
METHOD(XonoticCharmap, configureXonoticCharmap, void(entity, entity))
- METHOD(XonoticCharmap, mousePress, float(entity, vector))
- METHOD(XonoticCharmap, mouseRelease, float(entity, vector))
- METHOD(XonoticCharmap, mouseMove, float(entity, vector))
- METHOD(XonoticCharmap, mouseDrag, float(entity, vector))
- METHOD(XonoticCharmap, keyDown, float(entity, float, float, float))
METHOD(XonoticCharmap, focusLeave, void(entity))
METHOD(XonoticCharmap, resizeNotify, void(entity, vector, vector, vector, vector))
- METHOD(XonoticCharmap, draw, void(entity))
- ATTRIB(XonoticCharmap, focusable, float, 1)
-
- METHOD(XonoticCharmap, moveFocus, void(entity, vector, vector))
- METHOD(XonoticCharmap, enterChar, void(entity))
+ METHOD(XonoticCharmap, keyDown, float(entity, float, float, float))
ATTRIB(XonoticCharmap, inputBox, entity, NULL)
ATTRIB(XonoticCharmap, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticCharmap, realCellSize, vector, '0 0 0')
- ATTRIB(XonoticCharmap, focusedCell, vector, '-1 -1 0')
- ATTRIB(XonoticCharmap, previouslyFocusedCell, vector, '-1 -1 0')
+
+ 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))
+ METHOD(XonoticCharmap, charOffset, vector)
ENDCLASS(XonoticCharmap)
entity makeXonoticCharmap(entity controlledInputBox);
#endif
#ifdef IMPLEMENTATION
-const float CHARMAP_COLS = 14;
-const float CHARMAP_ROWS = 10;
-
string CHARMAP =
"★◆■▮▰▬◣◤◥◢◀▲▶▼"
"🌍🌎🌏🚀🌌👽🔫⌖❇❈←↑→↓"
"\xEE\x83\x8F\xEE\x83\x90\xEE\x83\x91\xEE\x83\x92\xEE\x83\x93\xEE\x83\x94\xEE\x83\x95"
"\xEE\x83\x96\xEE\x83\x97\xEE\x83\x98\xEE\x83\x99\xEE\x83\x9A\xEE\x81\x9B\xEE\x81\x9D";
-string charmap_cellToChar(vector cell)
+string charmap_cellToChar(entity me, vector cell)
{
- string character = substring(CHARMAP, cell.y * CHARMAP_COLS + cell.x, 1);
+ string character = substring(CHARMAP, cell.y * me.columns + cell.x, 1);
- if (character != " ")
+ if(character != " ")
return character;
else
return "";
entity makeXonoticCharmap(entity controlledInputBox)
{
entity me;
- me = spawnXonoticCharmap();
+ me = NEW(XonoticCharmap);
me.configureXonoticCharmap(me, controlledInputBox);
return me;
}
void XonoticCharmap_configureXonoticCharmap(entity me, entity controlledInputBox)
{
me.inputBox = controlledInputBox;
- me.realCellSize = eX / CHARMAP_COLS + eY / CHARMAP_ROWS;
+ me.configureXonoticPicker(me);
}
void XonoticCharmap_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
if(me.realFontSize.x > maxFontWidth || me.realFontSize.y > maxFontHeight)
me.realFontSize = eX * maxFontWidth + eY * maxFontHeight;
-}
-
-float XonoticCharmap_mouseMove(entity me, vector coords)
-{
- me.focusedCell_x = floor(coords.x * CHARMAP_COLS);
- me.focusedCell_y = floor(coords.y * CHARMAP_ROWS);
- if(me.focusedCell.x < 0 || me.focusedCell.y < 0 ||
- me.focusedCell.x >= CHARMAP_COLS || me.focusedCell.y >= CHARMAP_ROWS)
- {
- me.focusedCell = '-1 -1 0';
- return 0;
- }
-
- return 1;
+ me.charOffset = eX * me.realCellSize.x / 2 + eY * ((me.realCellSize.y - me.realFontSize.y) / 2);
}
-float XonoticCharmap_mouseDrag(entity me, vector coords)
-{
- return me.mouseMove(me, coords);
-}
-
-float XonoticCharmap_mousePress(entity me, vector coords)
-{
- me.mouseMove(me, coords);
-
- if(me.focusedCell.x >= 0)
- {
- me.pressed = 1;
- me.previouslyFocusedCell = me.focusedCell;
- }
-
- return 1;
-}
-
-float XonoticCharmap_mouseRelease(entity me, vector coords)
+float XonoticCharmap_keyDown(entity me, float key, float ascii, float shift)
{
- if(!me.pressed)
- return 0;
-
- me.mouseMove(me, coords);
-
- if(me.focusedCell == me.previouslyFocusedCell)
- me.enterChar(me);
-
- me.pressed = 0;
- return 1;
+ if(SUPER(XonoticCharmap).keyDown(me, key, ascii, shift))
+ return 1;
+ return me.inputBox.keyDown(me.inputBox, key, ascii, shift);
}
-float XonoticCharmap_keyDown(entity me, float key, float ascii, float shift)
+void XonoticCharmap_cellSelect(entity me, vector cell)
{
- switch(key)
- {
- case K_LEFTARROW:
- case K_KP_LEFTARROW:
- me.moveFocus(me, me.focusedCell, '-1 0 0');
- return 1;
- case K_RIGHTARROW:
- case K_KP_RIGHTARROW:
- me.moveFocus(me, me.focusedCell, '1 0 0');
- return 1;
- case K_UPARROW:
- case K_KP_UPARROW:
- me.moveFocus(me, me.focusedCell, '0 -1 0');
- return 1;
- case K_DOWNARROW:
- case K_KP_DOWNARROW:
- me.moveFocus(me, me.focusedCell, '0 1 0');
- return 1;
- case K_HOME:
- case K_KP_HOME:
- me.focusedCell = '0 0 0';
- return 1;
- case K_END:
- case K_KP_END:
- me.focusedCell_x = CHARMAP_COLS - 1;
- me.focusedCell_y = CHARMAP_ROWS - 1;
- return 1;
- case K_ENTER:
- case K_KP_ENTER:
- case K_INS:
- case K_KP_INS:
- me.enterChar(me);
- return 1;
- default:
- return me.inputBox.keyDown(me.inputBox, key, ascii, shift);
- }
+ string character = charmap_cellToChar(me, cell);
+ if(character != "")
+ me.inputBox.enterText(me.inputBox, character);
}
-void XonoticCharmap_moveFocus(entity me, vector initialCell, vector step)
+bool XonoticCharmap_cellIsValid(entity me, vector cell)
{
- me.focusedCell_x = mod(me.focusedCell.x + step.x + CHARMAP_COLS, CHARMAP_COLS);
- me.focusedCell_y = mod(me.focusedCell.y + step.y + CHARMAP_ROWS, CHARMAP_ROWS);
-
- if(me.focusedCell != initialCell) // Recursion break
- if(charmap_cellToChar(me.focusedCell) == "")
- me.moveFocus(me, initialCell, step);
+ if(charmap_cellToChar(me, cell) == "")
+ return false;
+ return true;
}
-void XonoticCharmap_enterChar(entity me)
+void XonoticCharmap_cellDraw(entity me, vector cell, vector cellPos)
{
- string character = charmap_cellToChar(me.focusedCell);
- if(character != "")
- me.inputBox.enterText(me.inputBox, character);
+ draw_CenterText(cellPos + me.charOffset, charmap_cellToChar(me, cell), me.realFontSize, SKINCOLOR_CHARMAP_CHAR, SKINALPHA_CHARMAP_CHAR, 0);
}
void XonoticCharmap_focusLeave(entity me)
{
me.inputBox.saveCvars(me.inputBox);
}
-
-void XonoticCharmap_draw(entity me)
-{
- string character;
- vector cell, cellPos, charPos;
- cell = '0 0 0';
- cellPos = '0 0 0';
- charPos = '0 0 0';
-
- float CHAR_OFFSET_X = me.realCellSize.x / 2;
- float CHAR_OFFSET_Y = (me.realCellSize.y - me.realFontSize.y) / 2;
-
- for(cell_y = 0; cell.y < CHARMAP_ROWS; ++cell.y)
- {
- charPos_y = cell.y / CHARMAP_ROWS + CHAR_OFFSET_Y;
- for(cell_x = 0; cell.x < CHARMAP_COLS; ++cell.x)
- {
- character = charmap_cellToChar(cell);
-
- if(character == "")
- continue;
-
- // Draw focused cell
- if(cell == me.focusedCell && me.focused)
- {
- if(!me.pressed || me.focusedCell == me.previouslyFocusedCell)
- {
- cellPos_x = mod(me.focusedCell.x, CHARMAP_COLS) / CHARMAP_COLS;
- cellPos_y = mod(me.focusedCell.y, CHARMAP_ROWS) / CHARMAP_ROWS;
- draw_Fill(cellPos, me.realCellSize, SKINCOLOR_CHARMAP_FOCUS, SKINALPHA_CHARMAP_FOCUS);
- }
- }
-
- // Draw character
- charPos_x = cell.x / CHARMAP_COLS + CHAR_OFFSET_X;
- draw_CenterText(charPos, character, me.realFontSize, SKINCOLOR_CHARMAP_CHAR, SKINALPHA_CHARMAP_CHAR, 0);
- }
- }
-}
#endif
-#ifdef INTERFACE
-CLASS(XonoticCheckBox) EXTENDS(CheckBox)
+#ifndef CHECKBOX_H
+#define CHECKBOX_H
+#include "../item/checkbox.qc"
+CLASS(XonoticCheckBox, CheckBox)
METHOD(XonoticCheckBox, configureXonoticCheckBox, void(entity, float, float, string, string))
METHOD(XonoticCheckBox, setChecked, void(entity, float))
ATTRIB(XonoticCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
entity makeXonoticCheckBoxEx(float theYesValue, float theNoValue, string theCvar, string theText)
{
entity me;
- me = spawnXonoticCheckBox();
+ me = NEW(XonoticCheckBox);
me.configureXonoticCheckBox(me, theYesValue, theNoValue, theCvar, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticSliderCheckBox) EXTENDS(CheckBox)
+#ifndef CHECKBOX_SLIDER_INVALID_H
+#define CHECKBOX_SLIDER_INVALID_H
+#include "../item/checkbox.qc"
+CLASS(XonoticSliderCheckBox, CheckBox)
METHOD(XonoticSliderCheckBox, configureXonoticSliderCheckBox, void(entity, float, float, entity, string))
METHOD(XonoticSliderCheckBox, setChecked, void(entity, float))
METHOD(XonoticSliderCheckBox, draw, void(entity))
entity makeXonoticSliderCheckBox(float theOffValue, float isInverted, entity theControlledSlider, string theText)
{
entity me;
- me = spawnXonoticSliderCheckBox();
+ me = NEW(XonoticSliderCheckBox);
me.configureXonoticSliderCheckBox(me, theOffValue, isInverted, theControlledSlider, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticCheckBoxString) EXTENDS(CheckBox)
+#ifndef CHECKBOX_STRING_H
+#define CHECKBOX_STRING_H
+#include "../item/checkbox.qc"
+CLASS(XonoticCheckBoxString, CheckBox)
METHOD(XonoticCheckBoxString, configureXonoticCheckBoxString, void(entity, string, string, string, string))
METHOD(XonoticCheckBoxString, setChecked, void(entity, float))
ATTRIB(XonoticCheckBoxString, fontSize, float, SKINFONTSIZE_NORMAL)
entity makeXonoticCheckBoxString(string theYesValue, string theNoValue, string theCvar, string theText)
{
entity me;
- me = spawnXonoticCheckBoxString();
+ me = NEW(XonoticCheckBoxString);
me.configureXonoticCheckBoxString(me, theYesValue, theNoValue, theCvar, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticColorButton) EXTENDS(RadioButton)
+#ifndef COLORBUTTON_H
+#define COLORBUTTON_H
+#include "../item/radiobutton.qc"
+CLASS(XonoticColorButton, RadioButton)
METHOD(XonoticColorButton, configureXonoticColorButton, void(entity, float, float, float))
METHOD(XonoticColorButton, setChecked, void(entity, float))
METHOD(XonoticColorButton, draw, void(entity))
entity makeXonoticColorButton(float theGroup, float theColor, float theValue)
{
entity me;
- me = spawnXonoticColorButton();
+ me = NEW(XonoticColorButton);
me.configureXonoticColorButton(me, theGroup, theColor, theValue);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticColorpicker) EXTENDS(Image)
+#ifndef COLORPICKER_H
+#define COLORPICKER_H
+#include "../item/image.qc"
+CLASS(XonoticColorpicker, Image)
METHOD(XonoticColorpicker, configureXonoticColorpicker, void(entity, entity))
METHOD(XonoticColorpicker, mousePress, float(entity, vector))
METHOD(XonoticColorpicker, mouseRelease, float(entity, vector))
entity makeXonoticColorpicker(entity theTextbox)
{
entity me;
- me = spawnXonoticColorpicker();
+ me = NEW(XonoticColorpicker);
me.configureXonoticColorpicker(me, theTextbox);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticColorpickerString) EXTENDS(Image)
+#ifndef COLORPICKER_STRING_H
+#define COLORPICKER_STRING_H
+#include "../item/image.qc"
+CLASS(XonoticColorpickerString, Image)
METHOD(XonoticColorpickerString, configureXonoticColorpickerString, void(entity, string, string))
METHOD(XonoticColorpickerString, mousePress, float(entity, vector))
METHOD(XonoticColorpickerString, mouseRelease, float(entity, vector))
METHOD(XonoticColorpickerString, mouseDrag, float(entity, vector))
ATTRIB(XonoticColorpickerString, cvarName, string, string_null)
- METHOD(XonoticColorPickerString, loadCvars, void(entity))
- METHOD(XonoticColorPickerString, saveCvars, void(entity))
+ 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)
entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar)
{
entity me;
- me = spawnXonoticColorpickerString();
+ me = NEW(XonoticColorpickerString);
me.configureXonoticColorpickerString(me, theCvar, theDefaultCvar);
return me;
}
}
}
-void XonoticColorPickerString_loadCvars(entity me)
+void XonoticColorpickerString_loadCvars(entity me)
{
if (!me.cvarName)
return;
me.prevcoords = color_hslimage(stov(cvar_string(me.cvarName)), me.imagemargin);
}
-void XonoticColorPickerString_saveCvars(entity me)
+void XonoticColorpickerString_saveCvars(entity me)
{
if (!me.cvarName)
return;
//# define COMMANDBUTTON_REVERT 4
#endif
-#ifdef INTERFACE
-CLASS(XonoticCommandButton) EXTENDS(XonoticButton)
+#ifndef COMMANDBUTTON_H
+#define COMMANDBUTTON_H
+#include "button.qc"
+CLASS(XonoticCommandButton, XonoticButton)
METHOD(XonoticCommandButton, configureXonoticCommandButton, void(entity, string, vector, string, float))
ATTRIB(XonoticCommandButton, onClickCommand, string, string_null)
ATTRIB(XonoticCommandButton, flags, float, 0)
entity makeXonoticCommandButton(string theText, vector theColor, string theCommand, float theFlags)
{
entity me;
- me = spawnXonoticCommandButton();
+ me = NEW(XonoticCommandButton);
me.configureXonoticCommandButton(me, theText, theColor, theCommand, theFlags);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticCreditsList) EXTENDS(XonoticListBox)
+#ifndef CREDITS_H
+#define CREDITS_H
+#include "listbox.qc"
+CLASS(XonoticCreditsList, XonoticListBox)
METHOD(XonoticCreditsList, configureXonoticCreditsList, void(entity))
ATTRIB(XonoticCreditsList, rowsPerItem, float, 1)
METHOD(XonoticCreditsList, draw, void(entity))
- METHOD(XonoticCreditsList, drawListBoxItem, void(entity, float, vector, float))
+ 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, bufferIndex, float, 0)
ATTRIB(XonoticCreditsList, scrolling, float, 0)
- ATTRIB(XonoticListBox, alphaBG, float, 0)
+ ATTRIB(XonoticCreditsList, alphaBG, float, 0)
ENDCLASS(XonoticCreditsList)
entity makeXonoticCreditsList();
#endif
entity makeXonoticCreditsList()
{
entity me;
- me = spawnXonoticCreditsList();
+ me = NEW(XonoticCreditsList);
me.configureXonoticCreditsList(me);
return me;
}
me.realFontSize_x = me.fontSize / (absSize.x * (1 - me.controlWidth));
me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
}
-void XonoticCreditsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticCreditsList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
// layout: Ping, Credits name, Map name, NP, TP, MP
string s;
+++ /dev/null
-#ifdef INTERFACE
-CLASS(XonoticCrosshairButton) EXTENDS(RadioButton)
- METHOD(XonoticCrosshairButton, configureXonoticCrosshairButton, void(entity, float, float))
- METHOD(XonoticCrosshairButton, setChecked, void(entity, float))
- METHOD(XonoticCrosshairButton, draw, void(entity))
- ATTRIB(XonoticCrosshairButton, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticCrosshairButton, image, string, SKINGFX_CROSSHAIRBUTTON)
-
- ATTRIB(XonoticCrosshairButton, useDownAsChecked, float, 1)
- ATTRIB(XonoticCrosshairButton, src3, string, string_null)
- ATTRIB(XonoticCrosshairButton, src4, string, string_null)
-
- ATTRIB(XonoticCrosshairButton, cvarName, string, string_null)
- ATTRIB(XonoticCrosshairButton, cvarValueFloat, float, 0)
- METHOD(XonoticCrosshairButton, loadCvars, void(entity))
- METHOD(XonoticCrosshairButton, saveCvars, void(entity))
-ENDCLASS(XonoticCrosshairButton)
-entity makeXonoticCrosshairButton(float, float);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCrosshairButton(float theGroup, float theCrosshair)
-{
- entity me;
- me = spawnXonoticCrosshairButton();
- me.configureXonoticCrosshairButton(me, theGroup, theCrosshair);
- return me;
-}
-void XonoticCrosshairButton_configureXonoticCrosshairButton(entity me, float theGroup, float theCrosshair)
-{
- me.cvarName = "crosshair";
- me.cvarValueFloat = theCrosshair;
- me.loadCvars(me);
- me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
- me.srcMulti = 1;
- if(me.cvarValueFloat == -1)
- me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
- else
- me.src3 = strzone(strcat("/gfx/crosshair", ftos(me.cvarValueFloat)));
- me.src4 = "/gfx/crosshairdot";
-}
-void XonoticCrosshairButton_setChecked(entity me, float val)
-{
- if(me.cvarValueFloat != -1) // preview shouldn't work as a button
- if(val != me.checked)
- {
- me.checked = val;
- me.saveCvars(me);
- }
-}
-void XonoticCrosshairButton_loadCvars(entity me)
-{
- if (!me.cvarName)
- return;
-
- me.checked = (cvar(me.cvarName) == me.cvarValueFloat);
-}
-void XonoticCrosshairButton_saveCvars(entity me)
-{
- if (!me.cvarName)
- return;
-
- if(me.checked)
- cvar_set(me.cvarName, ftos(me.cvarValueFloat));
- // TODO on an apply button, read _cl_color and execute the color command for it
-}
-void XonoticCrosshairButton_draw(entity me)
-{
- vector sz, rgb;
- float a;
-
-
- if(me.cvarValueFloat == -1)
- {
- rgb = stov(cvar_string("crosshair_color"));
- a = cvar("crosshair_alpha");
- }
- else if(me.checked || me.focused)
- {
- a = 1;
- rgb = '1 1 1';
- }
- else
- {
- a = me.disabledAlpha;
- rgb = '1 1 1';
- }
-
- if(me.cvarValueFloat == -1) // update the preview if this is the preview button
- {
- if(me.src3)
- strunzone(me.src3);
- me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
- me.focused = 1;
- me.checked = 0;
- }
-
- SUPER(XonoticCrosshairButton).draw(me);
-
- sz = draw_PictureSize(me.src3);
- sz = globalToBoxSize(sz, me.size);
- if(me.cvarValueFloat == -1)
- {
- sz = sz * cvar("crosshair_size"); // (6 * '1 1 0' + ...) * 0.08 here to make visible size changes happen also at bigger sizes
- /*
- if(sz_x > 0.95)
- sz = sz * (0.95 / sz_x);
- if(sz_y > 0.95)
- sz = sz * (0.95 / sz_y);
- */
- }
- else // show the crosshair picker at full size
- {
- sz = sz * (0.95 / sz.x);
- if(sz.y > 0.95)
- sz = sz * (0.95 / sz.y);
- }
-
- draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src3, sz, rgb, a);
- if(cvar("crosshair_dot"))
- {
- if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
- rgb = stov(cvar_string("crosshair_dot_color"));
-
- draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src4, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha"));
- }
-}
-#endif
--- /dev/null
+#ifndef CROSSHAIRPICKER_H
+#define CROSSHAIRPICKER_H
+#include "picker.qc"
+CLASS(XonoticCrosshairPicker, XonoticPicker)
+ METHOD(XonoticCrosshairPicker, configureXonoticCrosshairPicker, void(entity))
+
+ ATTRIB(XonoticCrosshairPicker, rows, float, 3)
+ ATTRIB(XonoticCrosshairPicker, columns, float, 12)
+
+ METHOD(XonoticCrosshairPicker, cellSelect, void(entity, vector))
+ METHOD(XonoticCrosshairPicker, cellIsValid, bool(entity, vector))
+ METHOD(XonoticCrosshairPicker, cellDraw, void(entity, vector, vector))
+ENDCLASS(XonoticCrosshairPicker)
+entity makeXonoticCrosshairPicker();
+#endif
+
+#ifdef IMPLEMENTATION
+
+string crosshairpicker_cellToCrosshair(entity me, vector cell)
+{
+ if(cell.x < 0 || cell.x >= me.columns || cell.y < 0 || cell.y >= me.rows)
+ return "";
+ return ftos(31 + cell.y * me.columns + cell.x);
+}
+
+vector crosshairpicker_crosshairToCell(entity me, string crosshair_str)
+{
+ float crosshair = stof(crosshair_str) - 31;
+ if(crosshair - floor(crosshair) > 0)
+ return '-1 -1 0';
+ return mod(crosshair, me.columns) * eX + floor(crosshair / me.columns) * eY;
+}
+
+entity makeXonoticCrosshairPicker()
+{
+ entity me;
+ me = NEW(XonoticCrosshairPicker);
+ me.configureXonoticCrosshairPicker(me);
+ return me;
+}
+
+void XonoticCrosshairPicker_configureXonoticCrosshairPicker(entity me)
+{
+ me.configureXonoticPicker(me);
+ SUPER(XonoticCrosshairPicker).cellSelect(me, crosshairpicker_crosshairToCell(me, cvar_string("crosshair")));
+}
+
+void XonoticCrosshairPicker_cellSelect(entity me, vector cell)
+{
+ cvar_set("crosshair", crosshairpicker_cellToCrosshair(me, me.focusedCell));
+ SUPER(XonoticCrosshairPicker).cellSelect(me, me.focusedCell);
+}
+
+bool XonoticCrosshairPicker_cellIsValid(entity me, vector cell)
+{
+ if(crosshairpicker_cellToCrosshair(me, cell) == "")
+ return false;
+ return true;
+}
+
+void XonoticCrosshairPicker_cellDraw(entity me, vector cell, vector cellPos)
+{
+ vector sz;
+ string cross = strcat("/gfx/crosshair", crosshairpicker_cellToCrosshair(me, cell));
+ sz = draw_PictureSize(cross);
+ sz = globalToBoxSize(sz, me.size);
+
+ float ar = sz.x / sz.y;
+ sz.x = me.realCellSize.x;
+ sz.y = sz.x / ar;
+ sz = sz * 0.95;
+
+ vector crosshairPos = cellPos + 0.5 * me.realCellSize;
+ draw_Picture(crosshairPos - 0.5 * sz, cross, sz, SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
+
+ if(cvar("crosshair_dot"))
+ draw_Picture(crosshairPos - 0.5 * sz * cvar("crosshair_dot_size"), "/gfx/crosshairdot", sz * cvar("crosshair_dot_size"), SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
+}
+#endif
--- /dev/null
+#ifndef CROSSHAIRPREVIEW_H
+#define CROSSHAIRPREVIEW_H
+#include "../item.qc"
+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)
+ENDCLASS(XonoticCrosshairPreview)
+entity makeXonoticCrosshairPreview();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCrosshairPreview()
+{
+ entity me;
+ me = NEW(XonoticCrosshairPreview);
+ me.configureXonoticCrosshairPreview(me);
+ return me;
+}
+
+void XonoticCrosshairPreview_configureXonoticCrosshairPreview(entity me)
+{
+ me.src = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+ me.src2 = "/gfx/crosshairdot";
+}
+
+void XonoticCrosshairPreview_draw(entity me)
+{
+ float save;
+ save = draw_alpha;
+ if(me.disabled)
+ draw_alpha *= me.disabledAlpha;
+
+ vector sz, rgb;
+ float a;
+ rgb = stov(cvar_string("crosshair_color"));
+ a = cvar("crosshair_alpha");
+ if(me.src)
+ strunzone(me.src);
+ me.src = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+
+ sz = draw_PictureSize(me.src);
+ sz = globalToBoxSize(sz, me.size);
+ sz = sz * cvar("crosshair_size");
+
+ draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src, sz, rgb, a);
+ if(cvar("crosshair_dot"))
+ {
+ if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
+ rgb = stov(cvar_string("crosshair_dot_color"));
+
+ draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src2, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha"));
+ }
+
+ draw_alpha = save;
+
+ SUPER(XonoticCrosshairPreview).draw(me);
+}
+#endif
-#ifdef INTERFACE
-CLASS(XonoticCvarList) EXTENDS(XonoticListBox)
+#ifndef CVARLIST_H
+#define CVARLIST_H
+#include "listbox.qc"
+CLASS(XonoticCvarList, XonoticListBox)
METHOD(XonoticCvarList, configureXonoticCvarList, void(entity))
ATTRIB(XonoticCvarList, rowsPerItem, float, 1)
- METHOD(XonoticCvarList, drawListBoxItem, void(entity, float, vector, float))
+ 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))
entity makeXonoticCvarList()
{
entity me;
- me = spawnXonoticCvarList();
+ me = NEW(XonoticCvarList);
me.configureXonoticCvarList(me);
return me;
}
me.setSelected(me, me.selectedItem);
}
-void XonoticCvarList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticCvarList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string k, v, d;
float t;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
k = bufstr_get(me.handle, i);
-#ifdef INTERFACE
-CLASS(XonoticDemoList) EXTENDS(XonoticListBox)
+#ifndef DEMOLIST_H
+#define DEMOLIST_H
+#include "listbox.qc"
+CLASS(XonoticDemoList, XonoticListBox)
METHOD(XonoticDemoList, configureXonoticDemoList, void(entity))
ATTRIB(XonoticDemoList, rowsPerItem, float, 1)
METHOD(XonoticDemoList, resizeNotify, void(entity, vector, vector, vector, vector))
- METHOD(XonoticDemoList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticDemoList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticDemoList, getDemos, void(entity))
METHOD(XonoticDemoList, startDemo, void(entity))
METHOD(XonoticDemoList, timeDemo, void(entity))
entity makeXonoticDemoList()
{
entity me;
- me = spawnXonoticDemoList();
+ me = NEW(XonoticDemoList);
me.configureXonoticDemoList(me);
return me;
}
me.columnNameSize = 1 - 2 * me.realFontSize.x;
}
-void XonoticDemoList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticDemoList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
s = me.demoName(me,i);
s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-#ifdef INTERFACE
-CLASS(XonoticDialog) EXTENDS(Dialog)
+#ifndef DIALOG_H
+#define DIALOG_H
+#include "../item/dialog.qc"
+CLASS(XonoticDialog, Dialog)
// still to be customized by user
/*
ATTRIB(XonoticDialog, closable, float, 1)
-#ifdef INTERFACE
-CLASS(XonoticCreditsDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_CREDITS_H
+#define DIALOG_CREDITS_H
+#include "dialog.qc"
+CLASS(XonoticCreditsDialog, XonoticDialog)
METHOD(XonoticCreditsDialog, fill, void(entity))
METHOD(XonoticCreditsDialog, focusEnter, void(entity))
ATTRIB(XonoticCreditsDialog, title, string, _("Credits"))
-#ifdef INTERFACE
-CLASS(XonoticFirstRunDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_FIRSTRUN_H
+#define DIALOG_FIRSTRUN_H
+#include "rootdialog.qc"
+CLASS(XonoticFirstRunDialog, XonoticRootDialog)
METHOD(XonoticFirstRunDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
ATTRIB(XonoticFirstRunDialog, title, string, _("Welcome"))
ATTRIB(XonoticFirstRunDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN)
-#ifdef INTERFACE
-CLASS(XonoticHUDAmmoDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_AMMO_H
+#define DIALOG_HUDPANEL_AMMO_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDAmmoDialog, XonoticRootDialog)
METHOD(XonoticHUDAmmoDialog, fill, void(entity))
ATTRIB(XonoticHUDAmmoDialog, title, string, _("Ammo Panel"))
ATTRIB(XonoticHUDAmmoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDBuffsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_BUFFS_H
+#define DIALOG_HUDPANEL_BUFFS_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDBuffsDialog, XonoticRootDialog)
METHOD(XonoticHUDBuffsDialog, fill, void(entity))
ATTRIB(XonoticHUDBuffsDialog, title, string, _("Buffs Panel"))
ATTRIB(XonoticHUDBuffsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDCenterprintDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_CENTERPRINT_H
+#define DIALOG_HUDPANEL_CENTERPRINT_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDCenterprintDialog, XonoticRootDialog)
METHOD(XonoticHUDCenterprintDialog, fill, void(entity))
ATTRIB(XonoticHUDCenterprintDialog, title, string, _("Centerprint Panel"))
ATTRIB(XonoticHUDCenterprintDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDChatDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_CHAT_H
+#define DIALOG_HUDPANEL_CHAT_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDChatDialog, XonoticRootDialog)
METHOD(XonoticHUDChatDialog, fill, void(entity))
ATTRIB(XonoticHUDChatDialog, title, string, _("Chat Panel"))
ATTRIB(XonoticHUDChatDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDEngineInfoDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_ENGINEINFO_H
+#define DIALOG_HUDPANEL_ENGINEINFO_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDEngineInfoDialog, XonoticRootDialog)
METHOD(XonoticHUDEngineInfoDialog, fill, void(entity))
ATTRIB(XonoticHUDEngineInfoDialog, title, string, _("Engine Info Panel"))
ATTRIB(XonoticHUDEngineInfoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDHealthArmorDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_HEALTHARMOR_H
+#define DIALOG_HUDPANEL_HEALTHARMOR_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDHealthArmorDialog, XonoticRootDialog)
METHOD(XonoticHUDHealthArmorDialog, fill, void(entity))
ATTRIB(XonoticHUDHealthArmorDialog, title, string, _("Health/Armor Panel"))
ATTRIB(XonoticHUDHealthArmorDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDInfoMessagesDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_INFOMESSAGES_H
+#define DIALOG_HUDPANEL_INFOMESSAGES_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDInfoMessagesDialog, XonoticRootDialog)
METHOD(XonoticHUDInfoMessagesDialog, fill, void(entity))
ATTRIB(XonoticHUDInfoMessagesDialog, title, string, _("Info Messages Panel"))
ATTRIB(XonoticHUDInfoMessagesDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDModIconsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_MODICONS_H
+#define DIALOG_HUDPANEL_MODICONS_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDModIconsDialog, XonoticRootDialog)
METHOD(XonoticHUDModIconsDialog, fill, void(entity))
ATTRIB(XonoticHUDModIconsDialog, title, string, _("Mod Icons Panel"))
ATTRIB(XonoticHUDModIconsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDNotificationDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_NOTIFICATION_H
+#define DIALOG_HUDPANEL_NOTIFICATION_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDNotificationDialog, XonoticRootDialog)
METHOD(XonoticHUDNotificationDialog, fill, void(entity))
ATTRIB(XonoticHUDNotificationDialog, title, string, _("Notification Panel"))
ATTRIB(XonoticHUDNotificationDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDPhysicsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_PHYSICS_H
+#define DIALOG_HUDPANEL_PHYSICS_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDPhysicsDialog, XonoticRootDialog)
METHOD(XonoticHUDPhysicsDialog, fill, void(entity))
ATTRIB(XonoticHUDPhysicsDialog, title, string, _("Physics Panel"))
ATTRIB(XonoticHUDPhysicsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDPowerupsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_POWERUPS_H
+#define DIALOG_HUDPANEL_POWERUPS_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDPowerupsDialog, XonoticRootDialog)
METHOD(XonoticHUDPowerupsDialog, fill, void(entity))
ATTRIB(XonoticHUDPowerupsDialog, title, string, _("Powerups Panel"))
ATTRIB(XonoticHUDPowerupsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDPressedKeysDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_PRESSEDKEYS_H
+#define DIALOG_HUDPANEL_PRESSEDKEYS_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDPressedKeysDialog, XonoticRootDialog)
METHOD(XonoticHUDPressedKeysDialog, fill, void(entity))
ATTRIB(XonoticHUDPressedKeysDialog, title, string, _("Pressed Keys Panel"))
ATTRIB(XonoticHUDPressedKeysDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDRaceTimerDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_RACETIMER_H
+#define DIALOG_HUDPANEL_RACETIMER_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDRaceTimerDialog, XonoticRootDialog)
METHOD(XonoticHUDRaceTimerDialog, fill, void(entity))
ATTRIB(XonoticHUDRaceTimerDialog, title, string, _("Race Timer Panel"))
ATTRIB(XonoticHUDRaceTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDRadarDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_RADAR_H
+#define DIALOG_HUDPANEL_RADAR_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDRadarDialog, XonoticRootDialog)
METHOD(XonoticHUDRadarDialog, fill, void(entity))
ATTRIB(XonoticHUDRadarDialog, title, string, _("Radar Panel"))
ATTRIB(XonoticHUDRadarDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDScoreDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_SCORE_H
+#define DIALOG_HUDPANEL_SCORE_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDScoreDialog, XonoticRootDialog)
METHOD(XonoticHUDScoreDialog, fill, void(entity))
ATTRIB(XonoticHUDScoreDialog, title, string, _("Score Panel"))
ATTRIB(XonoticHUDScoreDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDTimerDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_TIMER_H
+#define DIALOG_HUDPANEL_TIMER_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDTimerDialog, XonoticRootDialog)
METHOD(XonoticHUDTimerDialog, fill, void(entity))
ATTRIB(XonoticHUDTimerDialog, title, string, _("Timer Panel"))
ATTRIB(XonoticHUDTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDVoteDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_VOTE_H
+#define DIALOG_HUDPANEL_VOTE_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDVoteDialog, XonoticRootDialog)
METHOD(XonoticHUDVoteDialog, fill, void(entity))
ATTRIB(XonoticHUDVoteDialog, title, string, _("Vote Panel"))
ATTRIB(XonoticHUDVoteDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDWeaponsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDPANEL_WEAPONS_H
+#define DIALOG_HUDPANEL_WEAPONS_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDWeaponsDialog, XonoticRootDialog)
METHOD(XonoticHUDWeaponsDialog, fill, void(entity))
ATTRIB(XonoticHUDWeaponsDialog, title, string, _("Weapons Panel"))
ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticHUDExitDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_HUDSETUP_EXIT_H
+#define DIALOG_HUDSETUP_EXIT_H
+#include "rootdialog.qc"
+CLASS(XonoticHUDExitDialog, XonoticRootDialog)
METHOD(XonoticHUDExitDialog, fill, void(entity))
ATTRIB(XonoticHUDExitDialog, title, string, _("Panel HUD Setup"))
ATTRIB(XonoticHUDExitDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-#ifdef INTERFACE
-CLASS(XonoticMonsterToolsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_MONSTERTOOLS_H
+#define DIALOG_MONSTERTOOLS_H
+#include "rootdialog.qc"
+CLASS(XonoticMonsterToolsDialog, XonoticRootDialog)
METHOD(XonoticMonsterToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
ATTRIB(XonoticMonsterToolsDialog, title, string, _("Monster Tools"))
ATTRIB(XonoticMonsterToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
-#ifdef INTERFACE
-CLASS(XonoticMultiplayerDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_H
+#define DIALOG_MULTIPLAYER_H
+#include "dialog.qc"
+CLASS(XonoticMultiplayerDialog, XonoticDialog)
METHOD(XonoticMultiplayerDialog, fill, void(entity))
ATTRIB(XonoticMultiplayerDialog, title, string, _("Multiplayer"))
ATTRIB(XonoticMultiplayerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER)
me.TR(me);
me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Servers"), makeXonoticServerListTab()));
me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Create"), makeXonoticServerCreateTab()));
- //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
- //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
- //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Players"), makeXonoticDemoBrowserTab()));
me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Media"), makeXonoticMediaTab()));
me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Profile"), makeXonoticProfileTab()));
-#ifdef INTERFACE
-CLASS(XonoticServerCreateTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_CREATE_H
+#define DIALOG_MULTIPLAYER_CREATE_H
+#include "tab.qc"
+CLASS(XonoticServerCreateTab, XonoticTab)
METHOD(XonoticServerCreateTab, fill, void(entity))
METHOD(XonoticServerCreateTab, gameTypeChangeNotify, void(entity))
METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity))
- ATTRIB(XonoticServerCreateTab, title, string, _("Create"))
ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9)
ATTRIB(XonoticServerCreateTab, rows, float, 23)
ATTRIB(XonoticServerCreateTab, columns, float, 6.2) // added extra .2 for center space
e.configureXonoticTextSlider(e, pCvar);
// clear old values
- float i;
+ int i;
for(i = 0; i <= e.nValues; ++i);
{
if(e.(valueStrings[i])) { strunzone(e.(valueStrings[i])); }
entity makeXonoticServerCreateTab()
{
entity me;
- me = spawnXonoticServerCreateTab();
+ me = NEW(XonoticServerCreateTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticMapInfoDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_CREATE_MAPINFO_H
+#define DIALOG_MULTIPLAYER_CREATE_MAPINFO_H
+#include "dialog.qc"
+CLASS(XonoticMapInfoDialog, XonoticDialog)
METHOD(XonoticMapInfoDialog, fill, void(entity))
METHOD(XonoticMapInfoDialog, loadMapInfo, void(entity, float, entity))
ATTRIB(XonoticMapInfoDialog, title, string, _("Map Information"))
#endif
#ifdef IMPLEMENTATION
-void XonoticMapInfoDialog_loadMapInfo(entity me, float i, entity mlb)
+void XonoticMapInfoDialog_loadMapInfo(entity me, int i, entity mlb)
{
me.currentMapIndex = i;
me.startButton.onClickEntity = mlb;
void XonoticMapInfoDialog_fill(entity me)
{
entity e;
- float w, wgt, i, n;
+ int i;
+ float w, wgt, n;
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, me.rows - 2, 3, e = makeXonoticImage(string_null, 4.0/3.0));
-#include "../../common/weapons/weapons.qh"
+#include "../../common/weapons/all.qh"
-#ifdef INTERFACE
-CLASS(XonoticMutatorsDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_CREATE_MUTATORS_H
+#define DIALOG_MULTIPLAYER_CREATE_MUTATORS_H
+#include "dialog.qc"
+CLASS(XonoticMutatorsDialog, XonoticDialog)
METHOD(XonoticMutatorsDialog, toString, string(entity))
METHOD(XonoticMutatorsDialog, fill, void(entity))
METHOD(XonoticMutatorsDialog, showNotify, void(entity))
-#ifdef INTERFACE
-CLASS(XonoticServerListTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_JOIN_H
+#define DIALOG_MULTIPLAYER_JOIN_H
+#include "tab.qc"
+CLASS(XonoticServerListTab, XonoticTab)
METHOD(XonoticServerListTab, fill, void(entity))
- ATTRIB(XonoticServerListTab, title, string, _("Join"))
ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9)
ATTRIB(XonoticServerListTab, rows, float, 23)
ATTRIB(XonoticServerListTab, columns, float, 6.5)
entity makeXonoticServerListTab()
{
entity me;
- me = spawnXonoticServerListTab();
+ me = NEW(XonoticServerListTab);
me.configureDialog(me);
return me;
}
#include "../../common/mapinfo.qh"
-#ifdef INTERFACE
-CLASS(XonoticServerInfoDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_JOIN_SERVERINFO_H
+#define DIALOG_MULTIPLAYER_JOIN_SERVERINFO_H
+#include "dialog.qc"
+CLASS(XonoticServerInfoDialog, XonoticDialog)
METHOD(XonoticServerInfoDialog, fill, void(entity))
METHOD(XonoticServerInfoDialog, loadServerInfo, void(entity, float))
ATTRIB(XonoticServerInfoDialog, title, string, _("Server Information"))
-#ifdef INTERFACE
-CLASS(XonoticMediaTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_H
+#define DIALOG_MULTIPLAYER_MEDIA_H
+#include "tab.qc"
+CLASS(XonoticMediaTab, XonoticTab)
METHOD(XonoticMediaTab, fill, void(entity))
- ATTRIB(XonoticMediaTab, title, string, _("Media"))
ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9)
ATTRIB(XonoticMediaTab, rows, float, 23)
ATTRIB(XonoticMediaTab, columns, float, 3)
entity makeXonoticMediaTab()
{
entity me;
- me = spawnXonoticMediaTab();
+ me = NEW(XonoticMediaTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticDemoBrowserTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_DEMO_H
+#define DIALOG_MULTIPLAYER_MEDIA_DEMO_H
+#include "tab.qc"
+CLASS(XonoticDemoBrowserTab, XonoticTab)
METHOD(XonoticDemoBrowserTab, fill, void(entity))
- ATTRIB(XonoticDemoBrowserTab, title, string, _("Demo"))
ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9)
ATTRIB(XonoticDemoBrowserTab, rows, float, 21)
ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5)
ATTRIB(XonoticDemoBrowserTab, democlicktype, float, 0)
ENDCLASS(XonoticDemoBrowserTab)
entity makeXonoticDemoBrowserTab();
-#ifdef IMPLEMENTATION
-// private:
-const float DMO_PLAY = 1;
-const float DMO_TIME = 2;
-#endif
#endif
#ifdef IMPLEMENTATION
+const float DMO_PLAY = 1;
+const float DMO_TIME = 2;
void DemoConfirm_Check_Gamestatus(entity btn, entity me)
{
if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
entity makeXonoticDemoBrowserTab()
{
entity me;
- me = spawnXonoticDemoBrowserTab();
+ me = NEW(XonoticDemoBrowserTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticDemoStartConfirmDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_DEMO_STARTCONFIRM_H
+#define DIALOG_MULTIPLAYER_MEDIA_DEMO_STARTCONFIRM_H
+#include "dialog.qc"
+CLASS(XonoticDemoStartConfirmDialog, XonoticDialog)
METHOD(XonoticDemoStartConfirmDialog, fill, void(entity))
ATTRIB(XonoticDemoStartConfirmDialog, title, string, _("Disconnect"))
ATTRIB(XonoticDemoStartConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-#ifdef INTERFACE
-CLASS(XonoticDemoTimeConfirmDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_DEMO_TIMECONFIRM_H
+#define DIALOG_MULTIPLAYER_MEDIA_DEMO_TIMECONFIRM_H
+#include "dialog.qc"
+CLASS(XonoticDemoTimeConfirmDialog, XonoticDialog)
METHOD(XonoticDemoTimeConfirmDialog, fill, void(entity))
ATTRIB(XonoticDemoTimeConfirmDialog, title, string, _("Disconnect"))
ATTRIB(XonoticDemoTimeConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-#ifdef INTERFACE
-CLASS(XonoticMusicPlayerTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_MUSICPLAYER_H
+#define DIALOG_MULTIPLAYER_MEDIA_MUSICPLAYER_H
+#include "tab.qc"
+CLASS(XonoticMusicPlayerTab, XonoticTab)
METHOD(XonoticMusicPlayerTab, fill, void(entity))
- ATTRIB(XonoticMusicPlayerTab, title, string, _("Music"))
ATTRIB(XonoticMusicPlayerTab, intendedWidth, float, 0.9)
ATTRIB(XonoticMusicPlayerTab, rows, float, 21)
ATTRIB(XonoticMusicPlayerTab, columns, float, 6.5)
entity makeXonoticMusicPlayerTab()
{
entity me;
- me = spawnXonoticMusicPlayerTab();
+ me = NEW(XonoticMusicPlayerTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticScreenshotBrowserTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_SCREENSHOT_H
+#define DIALOG_MULTIPLAYER_MEDIA_SCREENSHOT_H
+#include "tab.qc"
+CLASS(XonoticScreenshotBrowserTab, XonoticTab)
METHOD(XonoticScreenshotBrowserTab, fill, void(entity))
- ATTRIB(XonoticScreenshotBrowserTab, title, string, "Screenshot")
ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1)
ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21)
ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5)
entity makeXonoticScreenshotBrowserTab()
{
entity me;
- me = spawnXonoticScreenshotBrowserTab();
+ me = NEW(XonoticScreenshotBrowserTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticScreenshotViewerDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_MULTIPLAYER_MEDIA_SCREENSHOT_VIEWER_H
+#define DIALOG_MULTIPLAYER_MEDIA_SCREENSHOT_VIEWER_H
+#include "dialog.qc"
+CLASS(XonoticScreenshotViewerDialog, XonoticDialog)
METHOD(XonoticScreenshotViewerDialog, fill, void(entity))
METHOD(XonoticScreenshotViewerDialog, keyDown, float(entity, float, float, float))
METHOD(XonoticScreenshotViewerDialog, loadScreenshot, void(entity, string))
-#ifdef INTERFACE
-CLASS(XonoticProfileTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_MULTIPLAYER_PROFILE_H
+#define DIALOG_MULTIPLAYER_PROFILE_H
+#include "tab.qc"
+CLASS(XonoticProfileTab, XonoticTab)
METHOD(XonoticProfileTab, fill, void(entity))
METHOD(XonoticProfileTab, draw, void(entity))
- ATTRIB(XonoticProfileTab, title, string, _("Profile"))
ATTRIB(XonoticProfileTab, intendedWidth, float, 0.9)
ATTRIB(XonoticProfileTab, rows, float, 23)
ATTRIB(XonoticProfileTab, columns, float, 6.1) // added extra .2 for center space
entity makeXonoticProfileTab()
{
entity me;
- me = spawnXonoticProfileTab();
+ me = NEW(XonoticProfileTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticQuitDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_QUIT_H
+#define DIALOG_QUIT_H
+#include "dialog.qc"
+CLASS(XonoticQuitDialog, XonoticDialog)
METHOD(XonoticQuitDialog, fill, void(entity))
ATTRIB(XonoticQuitDialog, title, string, _("Quit"))
ATTRIB(XonoticQuitDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
-#ifdef INTERFACE
-CLASS(XonoticSandboxToolsDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_SANDBOXTOOLS_H
+#define DIALOG_SANDBOXTOOLS_H
+#include "rootdialog.qc"
+CLASS(XonoticSandboxToolsDialog, XonoticRootDialog)
METHOD(XonoticSandboxToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
ATTRIB(XonoticSandboxToolsDialog, title, string, _("Sandbox Tools")) // ;)
ATTRIB(XonoticSandboxToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
-#ifdef INTERFACE
-CLASS(XonoticSettingsDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SETTINGS_H
+#define DIALOG_SETTINGS_H
+#include "dialog.qc"
+CLASS(XonoticSettingsDialog, XonoticDialog)
METHOD(XonoticSettingsDialog, fill, void(entity))
ATTRIB(XonoticSettingsDialog, title, string, _("Settings"))
ATTRIB(XonoticSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
-#ifdef INTERFACE
-CLASS(XonoticAudioSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_AUDIO_H
+#define DIALOG_SETTINGS_AUDIO_H
+#include "tab.qc"
+CLASS(XonoticAudioSettingsTab, XonoticTab)
METHOD(XonoticAudioSettingsTab, fill, void(entity))
- ATTRIB(XonoticAudioSettingsTab, title, string, _("Audio"))
ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticAudioSettingsTab, rows, float, 15.5)
ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2) // added extra .2 for center space
entity makeXonoticAudioSettingsTab()
{
entity me;
- me = spawnXonoticAudioSettingsTab();
+ me = NEW(XonoticAudioSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticEffectsSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_EFFECTS_H
+#define DIALOG_SETTINGS_EFFECTS_H
+#include "tab.qc"
+CLASS(XonoticEffectsSettingsTab, XonoticTab)
METHOD(XonoticEffectsSettingsTab, fill, void(entity))
- ATTRIB(XonoticEffectsSettingsTab, title, string, _("Effects"))
ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticEffectsSettingsTab, rows, float, 15.5)
ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2) // added extra .2 for center space
entity makeXonoticEffectsSettingsTab()
{
entity me;
- me = spawnXonoticEffectsSettingsTab();
+ me = NEW(XonoticEffectsSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticGameSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_GAME_H
+#define DIALOG_SETTINGS_GAME_H
+#include "tab.qc"
+CLASS(XonoticGameSettingsTab, XonoticTab)
METHOD(XonoticGameSettingsTab, fill, void(entity))
- ATTRIB(XonoticGameSettingsTab, title, string, _("Game"))
ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticGameSettingsTab, rows, float, 15.5)
ATTRIB(XonoticGameSettingsTab, columns, float, 6.5)
entity makeXonoticGameSettingsTab()
{
entity me;
- me = spawnXonoticGameSettingsTab();
+ me = NEW(XonoticGameSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticGameCrosshairSettingsTab) EXTENDS(XonoticTab)
- //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
+#ifndef DIALOG_SETTINGS_GAME_CROSSHAIR_H
+#define DIALOG_SETTINGS_GAME_CROSSHAIR_H
+#include "tab.qc"
+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, 13)
ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2)
entity makeXonoticGameCrosshairSettingsTab()
{
entity me;
- me = spawnXonoticGameCrosshairSettingsTab();
+ me = NEW(XonoticGameCrosshairSettingsTab);
me.configureDialog(me);
return me;
}
void XonoticGameCrosshairSettingsTab_fill(entity me)
{
entity e;
- float i;
// crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
// FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
me.TR(me);
me.TDempty(me, 0.1);
- for(i = 31; i <= 42; ++i) {
- me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
- setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
- }
- // show a larger preview of the selected crosshair
- me.TDempty(me, 0.1);
- me.TDNoMargin(me, 3, 0.8, e = makeXonoticCrosshairButton(7, -1), '1 1 0'); // crosshair -1 makes this a preview
+ me.TD(me, 3, 2, e = makeXonoticCrosshairPicker());
+ setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+ me.TD(me, 3, 0.9, e = makeXonoticCrosshairPreview());
setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
me.TR(me);
- me.TDempty(me, 0.1);
- for(i = 43; i <= 54; ++i) {
- me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
- setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
- }
me.TR(me);
- me.TDempty(me, 0.1);
- for(i = 55; i <= 66; ++i) {
- me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
- setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
- }
me.TR(me);
me.TDempty(me, 0.1);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));
-#ifdef INTERFACE
-CLASS(XonoticGameHUDSettingsTab) EXTENDS(XonoticTab)
- //METHOD(XonoticGameHUDSettingsTab, toString, string(entity))
+#ifndef DIALOG_SETTINGS_GAME_HUD_H
+#define DIALOG_SETTINGS_GAME_HUD_H
+#include "tab.qc"
+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, 13)
ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2)
entity makeXonoticGameHUDSettingsTab()
{
entity me;
- me = spawnXonoticGameHUDSettingsTab();
+ me = NEW(XonoticGameHUDSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticHUDConfirmDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SETTINGS_GAME_HUDCONFIRM_H
+#define DIALOG_SETTINGS_GAME_HUDCONFIRM_H
+#include "dialog.qc"
+CLASS(XonoticHUDConfirmDialog, XonoticDialog)
METHOD(XonoticHUDConfirmDialog, fill, void(entity))
ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"))
ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-#ifdef INTERFACE
-CLASS(XonoticGameMessageSettingsTab) EXTENDS(XonoticTab)
- //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
+#ifndef DIALOG_SETTINGS_GAME_MESSAGES_H
+#define DIALOG_SETTINGS_GAME_MESSAGES_H
+#include "tab.qc"
+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, 13)
ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6)
entity makeXonoticGameMessageSettingsTab()
{
entity me;
- me = spawnXonoticGameMessageSettingsTab();
+ me = NEW(XonoticGameMessageSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticGameModelSettingsTab) EXTENDS(XonoticTab)
- //METHOD(XonoticGameModelSettingsTab, toString, string(entity))
+#ifndef DIALOG_SETTINGS_GAME_MODEL_H
+#define DIALOG_SETTINGS_GAME_MODEL_H
+#include "tab.qc"
+CLASS(XonoticGameModelSettingsTab, XonoticTab)
METHOD(XonoticGameModelSettingsTab, fill, void(entity))
METHOD(XonoticGameModelSettingsTab, showNotify, void(entity))
- ATTRIB(XonoticGameModelSettingsTab, title, string, _("Model"))
ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticGameModelSettingsTab, rows, float, 13)
ATTRIB(XonoticGameModelSettingsTab, columns, float, 5)
entity makeXonoticGameModelSettingsTab()
{
entity me;
- me = spawnXonoticGameModelSettingsTab();
+ me = NEW(XonoticGameModelSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticGameViewSettingsTab) EXTENDS(XonoticTab)
- //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
+#ifndef DIALOG_SETTINGS_GAME_VIEW_H
+#define DIALOG_SETTINGS_GAME_VIEW_H
+#include "tab.qc"
+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, 13)
ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2)
entity makeXonoticGameViewSettingsTab()
{
entity me;
- me = spawnXonoticGameViewSettingsTab();
+ me = NEW(XonoticGameViewSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticGameWeaponsSettingsTab) EXTENDS(XonoticTab)
- //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
+#ifndef DIALOG_SETTINGS_GAME_WEAPONS_H
+#define DIALOG_SETTINGS_GAME_WEAPONS_H
+#include "tab.qc"
+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, 13)
ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6)
entity makeXonoticGameWeaponsSettingsTab()
{
entity me;
- me = spawnXonoticGameWeaponsSettingsTab();
+ me = NEW(XonoticGameWeaponsSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticInputSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_INPUT_H
+#define DIALOG_SETTINGS_INPUT_H
+#include "tab.qc"
+CLASS(XonoticInputSettingsTab, XonoticTab)
METHOD(XonoticInputSettingsTab, fill, void(entity))
- ATTRIB(XonoticInputSettingsTab, title, string, _("Input"))
ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticInputSettingsTab, rows, float, 15.5)
ATTRIB(XonoticInputSettingsTab, columns, float, 6.2) // added extra .2 for center space
entity makeXonoticInputSettingsTab()
{
entity me;
- me = spawnXonoticInputSettingsTab();
+ me = NEW(XonoticInputSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticUserbindEditDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SETTINGS_INPUT_USERBIND_H
+#define DIALOG_SETTINGS_INPUT_USERBIND_H
+#include "dialog.qc"
+CLASS(XonoticUserbindEditDialog, XonoticDialog)
METHOD(XonoticUserbindEditDialog, loadUserBind, void(entity, string, string, string))
METHOD(XonoticUserbindEditDialog, fill, void(entity))
ATTRIB(XonoticUserbindEditDialog, title, string, _("User defined key bind"))
-#ifdef INTERFACE
-CLASS(XonoticMiscSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_MISC_H
+#define DIALOG_SETTINGS_MISC_H
+#include "tab.qc"
+CLASS(XonoticMiscSettingsTab, XonoticTab)
METHOD(XonoticMiscSettingsTab, fill, void(entity))
- ATTRIB(XonoticMiscSettingsTab, title, string, _("Misc"))
ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticMiscSettingsTab, rows, float, 15.5)
ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2)
entity makeXonoticMiscSettingsTab()
{
entity me;
- me = spawnXonoticMiscSettingsTab();
+ me = NEW(XonoticMiscSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticCvarsDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SETTINGS_MISC_CVARS_H
+#define DIALOG_SETTINGS_MISC_CVARS_H
+#include "dialog.qc"
+CLASS(XonoticCvarsDialog, XonoticDialog)
METHOD(XonoticCvarsDialog, fill, void(entity))
METHOD(XonoticCvarsDialog, showNotify, void(entity))
ATTRIB(XonoticCvarsDialog, title, string, _("Advanced settings"))
-#ifdef INTERFACE
-CLASS(XonoticResetDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SETTINGS_MISC_RESET_H
+#define DIALOG_SETTINGS_MISC_RESET_H
+#include "dialog.qc"
+CLASS(XonoticResetDialog, XonoticDialog)
METHOD(XonoticResetDialog, fill, void(entity))
ATTRIB(XonoticResetDialog, title, string, _("Factory reset"))
ATTRIB(XonoticResetDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
-#ifdef INTERFACE
-CLASS(XonoticUserSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_USER_H
+#define DIALOG_SETTINGS_USER_H
+#include "tab.qc"
+CLASS(XonoticUserSettingsTab, XonoticTab)
METHOD(XonoticUserSettingsTab, fill, void(entity))
- ATTRIB(XonoticUserSettingsTab, title, string, _("User"))
ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticUserSettingsTab, rows, float, 15.5)
ATTRIB(XonoticUserSettingsTab, columns, float, 6)
entity makeXonoticUserSettingsTab()
{
entity me;
- me = spawnXonoticUserSettingsTab();
+ me = NEW(XonoticUserSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticLanguageWarningDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SETTINGS_USER_LANGUAGEWARNING_H
+#define DIALOG_SETTINGS_USER_LANGUAGEWARNING_H
+#include "dialog.qc"
+CLASS(XonoticLanguageWarningDialog, XonoticDialog)
METHOD(XonoticLanguageWarningDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
ATTRIB(XonoticLanguageWarningDialog, title, string, _("Warning"))
ATTRIB(XonoticLanguageWarningDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-#ifdef INTERFACE
-CLASS(XonoticVideoSettingsTab) EXTENDS(XonoticTab)
+#ifndef DIALOG_SETTINGS_VIDEO_H
+#define DIALOG_SETTINGS_VIDEO_H
+#include "tab.qc"
+CLASS(XonoticVideoSettingsTab, XonoticTab)
METHOD(XonoticVideoSettingsTab, fill, void(entity))
- ATTRIB(XonoticVideoSettingsTab, title, string, _("Video"))
ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticVideoSettingsTab, rows, float, 15.5)
ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2) // added extra .2 for center space
entity makeXonoticVideoSettingsTab()
{
entity me;
- me = spawnXonoticVideoSettingsTab();
+ me = NEW(XonoticVideoSettingsTab);
me.configureDialog(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticSingleplayerDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SINGLEPLAYER_H
+#define DIALOG_SINGLEPLAYER_H
+#include "dialog.qc"
+CLASS(XonoticSingleplayerDialog, XonoticDialog)
METHOD(XonoticSingleplayerDialog, fill, void(entity))
ATTRIB(XonoticSingleplayerDialog, title, string, _("Singleplayer"))
ATTRIB(XonoticSingleplayerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
-#ifdef INTERFACE
-CLASS(XonoticWinnerDialog) EXTENDS(XonoticDialog)
+#ifndef DIALOG_SINGLEPLAYER_WINNER_H
+#define DIALOG_SINGLEPLAYER_WINNER_H
+#include "dialog.qc"
+CLASS(XonoticWinnerDialog, XonoticDialog)
METHOD(XonoticWinnerDialog, fill, void(entity))
METHOD(XonoticWinnerDialog, focusEnter, void(entity))
ATTRIB(XonoticWinnerDialog, title, string, _("Winner"))
-#ifdef INTERFACE
-CLASS(XonoticTeamSelectDialog) EXTENDS(XonoticRootDialog)
+#ifndef DIALOG_TEAMSELECT_H
+#define DIALOG_TEAMSELECT_H
+#include "rootdialog.qc"
+CLASS(XonoticTeamSelectDialog, XonoticRootDialog)
METHOD(XonoticTeamSelectDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
METHOD(XonoticTeamSelectDialog, showNotify, void(entity))
ATTRIB(XonoticTeamSelectDialog, title, string, _("Team Selection")) // ;)
-#ifdef INTERFACE
-CLASS(XonoticGametypeButton) EXTENDS(RadioButton)
+#ifndef GAMETYPEBUTTON_H
+#define GAMETYPEBUTTON_H
+#include "../item/radiobutton.qc"
+CLASS(XonoticGametypeButton, RadioButton)
METHOD(XonoticGametypeButton, configureXonoticGametypeButton, void(entity, float, string, string))
METHOD(XonoticGametypeButton, setChecked, void(entity, float))
ATTRIB(XonoticGametypeButton, fontSize, float, SKINFONTSIZE_NORMAL)
entity makeXonoticGametypeButton(float theGroup, string theCvar, string theText)
{
entity me;
- me = spawnXonoticGametypeButton();
+ me = NEW(XonoticGametypeButton);
me.configureXonoticGametypeButton(me, theGroup, theCvar, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticGametypeList) EXTENDS(XonoticListBox)
+#ifndef GAMETYPELIST_H
+#define GAMETYPELIST_H
+#include "listbox.qc"
+CLASS(XonoticGametypeList, XonoticListBox)
METHOD(XonoticGametypeList, configureXonoticGametypeList, void(entity))
ATTRIB(XonoticGametypeList, rowsPerItem, float, 2)
- METHOD(XonoticGametypeList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticGametypeList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticGametypeList, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(XonoticGametypeList, setSelected, void(entity, float))
METHOD(XonoticGametypeList, loadCvars, void(entity))
entity makeXonoticGametypeList(void)
{
entity me;
- me = spawnXonoticGametypeList();
+ me = NEW(XonoticGametypeList);
me.configureXonoticGametypeList(me);
return me;
}
me.configureXonoticListBox(me);
me.nItems = GameType_GetCount();
- // we want the pics mipmapped
- for(int i = 0; i < GameType_GetCount(); ++i)
- draw_PreloadPictureWithFlags(GameType_GetIcon(i), PRECACHE_PIC_MIPMAP);
+ if(SKINBOOL_GAMETYPELIST_ICON_BLUR)
+ {
+ for(int i = 0; i < GameType_GetCount(); ++i)
+ draw_PreloadPictureWithFlags(GameType_GetIcon(i), PRECACHE_PIC_MIPMAP);
+ }
me.loadCvars(me);
}
owner.gameTypeChangeNotify(owner);
}
}
-void XonoticGametypeList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticGametypeList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s1, s2;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
draw_Picture(me.columnIconOrigin * eX, GameType_GetIcon(i), me.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED);
s1 = GameType_GetName(i);
-#ifdef INTERFACE
-CLASS(XonoticImage) EXTENDS(Image)
+#ifndef IMAGE_H
+#define IMAGE_H
+#include "../item/image.qc"
+CLASS(XonoticImage, Image)
METHOD(XonoticImage, configureXonoticImage, void(entity, string, float))
ENDCLASS(XonoticImage)
entity makeXonoticImage(string theImage, float theAspect);
entity makeXonoticImage(string theImage, float theAspect)
{
entity me;
- me = spawnXonoticImage();
+ me = NEW(XonoticImage);
me.configureXonoticImage(me, theImage, theAspect);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticInputBox) EXTENDS(InputBox)
+#ifndef INPUTBOX_H
+#define INPUTBOX_H
+#include "../item/inputbox.qc"
+CLASS(XonoticInputBox, InputBox)
METHOD(XonoticInputBox, configureXonoticInputBox, void(entity, float, string))
METHOD(XonoticInputBox, focusLeave, void(entity))
METHOD(XonoticInputBox, setText, void(entity, string))
entity makeXonoticInputBox(float doEditColorCodes, string theCvar)
{
entity me;
- me = spawnXonoticInputBox();
+ me = NEW(XonoticInputBox);
me.configureXonoticInputBox(me, doEditColorCodes, theCvar);
return me;
}
{
me.saveCvars(me);
}
-void XonoticInputBox_setText(entity me, string new)
+void XonoticInputBox_setText(entity me, string val)
{
- if(me.text != new)
+ if(me.text != val)
{
- SUPER(XonoticInputBox).setText(me, new);
+ SUPER(XonoticInputBox).setText(me, val);
if(me.onChange)
me.onChange(me, me.onChangeEntity);
if(me.saveImmediately)
me.saveCvars(me);
}
else
- SUPER(XonoticInputBox).setText(me, new);
+ SUPER(XonoticInputBox).setText(me, val);
}
void XonoticInputBox_loadCvars(entity me)
{
-#ifdef INTERFACE
-CLASS(XonoticKeyBinder) EXTENDS(XonoticListBox)
+#ifndef KEYBINDER_H
+#define KEYBINDER_H
+#include "listbox.qc"
+CLASS(XonoticKeyBinder, XonoticListBox)
METHOD(XonoticKeyBinder, configureXonoticKeyBinder, void(entity))
- ATTRIB(XonoticKeyBinder, rowsPerItem, float, 1)
- METHOD(XonoticKeyBinder, drawListBoxItem, void(entity, float, vector, float))
+ 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, setSelected, void(entity, float))
ATTRIB(XonoticKeyBinder, columnKeysOrigin, float, 0)
ATTRIB(XonoticKeyBinder, columnKeysSize, float, 0)
- ATTRIB(XonoticKeyBinder, previouslySelected, float, -1)
+ ATTRIB(XonoticKeyBinder, previouslySelected, int, -1)
ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0)
ATTRIB(XonoticKeyBinder, userbindEditButton, entity, NULL)
ATTRIB(XonoticKeyBinder, keyGrabButton, entity, NULL)
void KeyBinder_Bind_Change(entity btn, entity me);
void KeyBinder_Bind_Clear(entity btn, entity me);
void KeyBinder_Bind_Edit(entity btn, entity me);
+void KeyBinder_Bind_Reset_All(entity btn, entity me);
#endif
#ifdef IMPLEMENTATION
const string KEY_NOT_BOUND_CMD = "// not bound";
-const float MAX_KEYS_PER_FUNCTION = 2;
-const float MAX_KEYBINDS = 256;
+const int MAX_KEYS_PER_FUNCTION = 2;
+const int MAX_KEYBINDS = 256;
string Xonotic_KeyBinds_Functions[MAX_KEYBINDS];
string Xonotic_KeyBinds_Descriptions[MAX_KEYBINDS];
-float Xonotic_KeyBinds_Count = -1;
+int Xonotic_KeyBinds_Count = -1;
void Xonotic_KeyBinds_Read()
{
- float fh;
+ int fh;
string s;
Xonotic_KeyBinds_Count = 0;
entity makeXonoticKeyBinder()
{
entity me;
- me = spawnXonoticKeyBinder();
+ me = NEW(XonoticKeyBinder);
me.configureXonoticKeyBinder(me);
return me;
}
void replace_bind(string from, string to)
{
- float n, j, k;
+ int n, j;
+ float k; // not sure if float or int
n = tokenize(findkeysforcommand(from, 0)); // uses '...' strings
for(j = 0; j < n; ++j)
{
me.clearButton.disabled = 1;
keyGrabber = me;
}
-void XonoticKeyBinder_keyGrabbed(entity me, float key, float ascii)
+void XonoticKeyBinder_keyGrabbed(entity me, int key, bool ascii)
{
- float n, j, k, nvalid;
+ int n, j, nvalid;
+ float k;
string func;
me.keyGrabButton.forcePressed = 0;
{
KeyBinder_Bind_Change(NULL, me);
}
-void XonoticKeyBinder_setSelected(entity me, float i)
+void XonoticKeyBinder_setSelected(entity me, int i)
{
// handling of "unselectable" items
i = floor(0.5 + bound(0, i, me.nItems - 1));
me.userbindEditButton.disabled = (substring(Xonotic_KeyBinds_Descriptions[i], 0, 1) != "$");
SUPER(XonoticKeyBinder).setSelected(me, i);
}
-float XonoticKeyBinder_keyDown(entity me, float key, float ascii, float shift)
+float XonoticKeyBinder_keyDown(entity me, int key, bool ascii, float shift)
{
- float r;
- r = 1;
+ bool r = true;
switch(key)
{
case K_ENTER:
}
return r;
}
-void XonoticKeyBinder_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticKeyBinder_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
- float j, k, n;
+ int j, n;
+ float k;
vector theColor;
float theAlpha;
string func, descr;
else
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
}
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
+
theAlpha = SKINALPHA_KEYGRABBER_KEYS;
theColor = SKINCOLOR_KEYGRABBER_KEYS;
extraMargin = me.realFontSize.x * 0.5;
-#ifdef INTERFACE
-CLASS(XonoticLanguageList) EXTENDS(XonoticListBox)
+#ifndef LANGUAGELIST_H
+#define LANGUAGELIST_H
+#include "listbox.qc"
+CLASS(XonoticLanguageList, XonoticListBox)
METHOD(XonoticLanguageList, configureXonoticLanguageList, void(entity))
ATTRIB(XonoticLanguageList, rowsPerItem, float, 1)
- METHOD(XonoticLanguageList, drawListBoxItem, void(entity, float, vector, float))
+ 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))
entity makeXonoticLanguageList()
{
entity me;
- me = spawnXonoticLanguageList();
+ me = NEW(XonoticLanguageList);
me.configureXonoticLanguageList(me);
return me;
}
me.loadCvars(me);
}
-void XonoticLanguageList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticLanguageList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s, p;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
s = me.languageParameter(me, i, LANGPARM_NAME_LOCALIZED);
-#ifdef INTERFACE
-CLASS(XonoticListBox) EXTENDS(ListBox)
+#ifndef LISTBOX_H
+#define LISTBOX_H
+#include "../item/listbox.qc"
+CLASS(XonoticListBox, ListBox)
METHOD(XonoticListBox, configureXonoticListBox, void(entity))
ATTRIB(XonoticListBox, fontSize, float, SKINFONTSIZE_NORMAL)
ATTRIB(XonoticListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR)
entity makeXonoticListBox()
{
entity me;
- me = spawnXonoticListBox();
+ me = NEW(XonoticListBox);
me.configureXonoticListBox(me);
return me;
}
-#ifdef INTERFACE
-CLASS(MainWindow) EXTENDS(ModalController)
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+#include "../item/modalcontroller.qc"
+CLASS(MainWindow, ModalController)
METHOD(MainWindow, configureMainWindow, void(entity))
METHOD(MainWindow, draw, void(entity))
ATTRIB(MainWindow, firstRunDialog, entity, NULL)
entity n, i;
// dialog run upon startup
- me.firstRunDialog = i = spawnXonoticFirstRunDialog();
+ me.firstRunDialog = i = NEW(XonoticFirstRunDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
// hud_configure dialogs
- i = spawnXonoticHUDExitDialog();
+ i = NEW(XonoticHUDExitDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDNotificationDialog();
+ i = NEW(XonoticHUDNotificationDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDAmmoDialog();
+ i = NEW(XonoticHUDAmmoDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDHealthArmorDialog();
+ i = NEW(XonoticHUDHealthArmorDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDChatDialog();
+ i = NEW(XonoticHUDChatDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDModIconsDialog();
+ i = NEW(XonoticHUDModIconsDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDPowerupsDialog();
+ i = NEW(XonoticHUDPowerupsDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDPressedKeysDialog();
+ i = NEW(XonoticHUDPressedKeysDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDRaceTimerDialog();
+ i = NEW(XonoticHUDRaceTimerDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
- i = spawnXonoticHUDRadarDialog();
- i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDScoreDialog();
+ i = NEW(XonoticHUDRadarDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDTimerDialog();
+ i = NEW(XonoticHUDScoreDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDVoteDialog();
+ i = NEW(XonoticHUDTimerDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDWeaponsDialog();
+ i = NEW(XonoticHUDVoteDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDEngineInfoDialog();
+ i = NEW(XonoticHUDWeaponsDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDInfoMessagesDialog();
+ i = NEW(XonoticHUDEngineInfoDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDPhysicsDialog();
+ i = NEW(XonoticHUDInfoMessagesDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.screenshotViewerDialog = i = spawnXonoticScreenshotViewerDialog();
+ i = NEW(XonoticHUDPhysicsDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDCenterprintDialog();
+ i = NEW(XonoticHUDCenterprintDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticHUDBuffsDialog();
+ i = NEW(XonoticHUDBuffsDialog);
i.configureDialog(i);
- me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
// dialogs used by settings
- me.userbindEditDialog = i = spawnXonoticUserbindEditDialog();
+ me.userbindEditDialog = i = NEW(XonoticUserbindEditDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.cvarsDialog = i = spawnXonoticCvarsDialog();
+ me.cvarsDialog = i = NEW(XonoticCvarsDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.resetDialog = i = spawnXonoticResetDialog();
+ me.resetDialog = i = NEW(XonoticResetDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog();
+ me.languageWarningDialog = i = NEW(XonoticLanguageWarningDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog();
+ me.hudconfirmDialog = i = NEW(XonoticHUDConfirmDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
// dialog used by singleplayer
- me.winnerDialog = i = spawnXonoticWinnerDialog();
+ me.winnerDialog = i = NEW(XonoticWinnerDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
// dialog used by multiplayer/join
- me.serverInfoDialog = i = spawnXonoticServerInfoDialog();
+ me.serverInfoDialog = i = NEW(XonoticServerInfoDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.demostartconfirmDialog = i = spawnXonoticDemoStartConfirmDialog();
+ me.demostartconfirmDialog = i = NEW(XonoticDemoStartConfirmDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.demotimeconfirmDialog = i = spawnXonoticDemoTimeConfirmDialog();
+ me.demotimeconfirmDialog = i = NEW(XonoticDemoTimeConfirmDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
// dialogs used by multiplayer/create
- me.mapInfoDialog = i = spawnXonoticMapInfoDialog();
+ me.mapInfoDialog = i = NEW(XonoticMapInfoDialog);
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ me.mutatorsDialog = i = NEW(XonoticMutatorsDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- me.mutatorsDialog = i = spawnXonoticMutatorsDialog();
+
+ // dialogs used by multiplayer/media
+ me.screenshotViewerDialog = i = NEW(XonoticScreenshotViewerDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
// mutator dialogs
- i = spawnXonoticSandboxToolsDialog();
+ i = NEW(XonoticSandboxToolsDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
// miscellaneous dialogs
- i = spawnXonoticTeamSelectDialog();
+ i = NEW(XonoticTeamSelectDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
- i = spawnXonoticMonsterToolsDialog();
+ i = NEW(XonoticMonsterToolsDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
// main dialogs/windows
- me.mainNexposee = n = spawnXonoticNexposee();
+ me.mainNexposee = n = NEW(XonoticNexposee);
/*
if(checkextension("DP_GECKO_SUPPORT"))
{
n.setNexposee(n, i, '0.1 0.1 0', SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
}
*/
- i = spawnXonoticSingleplayerDialog();
+ i = NEW(XonoticSingleplayerDialog);
i.configureDialog(i);
n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
n.setNexposee(n, i, SKINPOSITION_DIALOG_SINGLEPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
- i = spawnXonoticMultiplayerDialog();
+ i = NEW(XonoticMultiplayerDialog);
i.configureDialog(i);
n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
n.setNexposee(n, i, SKINPOSITION_DIALOG_MULTIPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
- i = spawnXonoticSettingsDialog();
+ i = NEW(XonoticSettingsDialog);
i.configureDialog(i);
n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
n.setNexposee(n, i, SKINPOSITION_DIALOG_SETTINGS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
- i = spawnXonoticCreditsDialog();
+ i = NEW(XonoticCreditsDialog);
i.configureDialog(i);
n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
n.setNexposee(n, i, SKINPOSITION_DIALOG_CREDITS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight));
- i = spawnXonoticQuitDialog();
+ i = NEW(XonoticQuitDialog);
i.configureDialog(i);
n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
n.setNexposee(n, i, SKINPOSITION_DIALOG_QUIT, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
-#ifdef INTERFACE
-CLASS(XonoticMapList) EXTENDS(XonoticListBox)
+#ifndef MAPLIST_H
+#define MAPLIST_H
+#include "listbox.qc"
+CLASS(XonoticMapList, XonoticListBox)
METHOD(XonoticMapList, configureXonoticMapList, void(entity))
ATTRIB(XonoticMapList, rowsPerItem, float, 4)
METHOD(XonoticMapList, draw, void(entity))
- METHOD(XonoticMapList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticMapList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticMapList, clickListBoxItem, void(entity, float, vector))
METHOD(XonoticMapList, doubleClickListBoxItem, void(entity, float, vector))
METHOD(XonoticMapList, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(XonoticMapList, destroy, void(entity))
- ATTRIB(XonoticListBox, alphaBG, float, 0)
+ ATTRIB(XonoticMapList, alphaBG, float, 0)
ENDCLASS(XonoticMapList)
entity makeXonoticMapList();
void MapList_All(entity btn, entity me);
entity makeXonoticMapList()
{
entity me;
- me = spawnXonoticMapList();
+ me = NEW(XonoticMapList);
me.configureXonoticMapList(me);
return me;
}
}
}
-void XonoticMapList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticMapList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
// layout: Ping, Map name, Map name, NP, TP, MP
string s;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
- else if(included)
- draw_Fill('0 0 0', '1 1 0', SKINCOLOR_MAPLIST_INCLUDEDBG, SKINALPHA_MAPLIST_INCLUDEDBG);
+ else
+ {
+ if(included)
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_MAPLIST_INCLUDEDBG, SKINALPHA_MAPLIST_INCLUDEDBG);
+ if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
+ }
if(draw_PictureSize(strcat("/maps/", MapInfo_Map_bspname)) == '0 0 0')
draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
-#ifdef INTERFACE
-CLASS(XonoticNexposee) EXTENDS(Nexposee)
+#ifndef NEXPOSEE_H
+#define NEXPOSEE_H
+#include "../item/nexposee.qc"
+CLASS(XonoticNexposee, Nexposee)
METHOD(XonoticNexposee, configureXonoticNexposee, void(entity))
METHOD(XonoticNexposee, close, void(entity))
ENDCLASS(XonoticNexposee)
entity makeXonoticNexposee()
{
entity me;
- me = spawnXonoticNexposee();
+ me = NEW(XonoticNexposee);
me.configureXonoticNexposee(me);
return me;
}
--- /dev/null
+#ifndef PICKER_H
+#define PICKER_H
+#include "../item.qc"
+CLASS(XonoticPicker, Item)
+ METHOD(XonoticPicker, configureXonoticPicker, void(entity))
+ METHOD(XonoticPicker, mousePress, float(entity, vector))
+ METHOD(XonoticPicker, mouseRelease, float(entity, vector))
+ METHOD(XonoticPicker, mouseMove, float(entity, vector))
+ 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, 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')
+ENDCLASS(XonoticPicker)
+entity makeXonoticPicker();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticPicker()
+{
+ entity me;
+ me = NEW(XonoticPicker);
+ me.configureXonoticPicker(me);
+ return me;
+}
+
+void XonoticPicker_configureXonoticPicker(entity me)
+{
+ me.realCellSize = eX / me.columns + eY / me.rows;
+}
+
+float XonoticPicker_mouseMove(entity me, vector coords)
+{
+ vector prevFocusedCell = me.focusedCell;
+ me.focusedCell_x = floor(coords.x * me.columns);
+ me.focusedCell_y = floor(coords.y * me.rows);
+
+ if(me.focusedCell.x < 0 || me.focusedCell.y < 0 ||
+ me.focusedCell.x >= me.columns || me.focusedCell.y >= me.rows)
+ {
+ me.focusedCell = '-1 -1 0';
+ return 0;
+ }
+
+ if(me.focusedCell != prevFocusedCell)
+ me.focusedCellAlpha = SKINALPHA_LISTBOX_FOCUSED;
+
+ return 1;
+}
+
+float XonoticPicker_mouseDrag(entity me, vector coords)
+{
+ return me.mouseMove(me, coords);
+}
+
+float XonoticPicker_mousePress(entity me, vector coords)
+{
+ me.mouseMove(me, coords);
+
+ if(me.focusedCell.x >= 0)
+ {
+ me.pressed = 1;
+ me.pressedCell = me.focusedCell;
+ }
+
+ return 1;
+}
+
+float XonoticPicker_mouseRelease(entity me, vector coords)
+{
+ if(!me.pressed)
+ return 0;
+
+ me.mouseMove(me, coords);
+
+ if(me.focusedCell == me.pressedCell)
+ me.cellSelect(me, me.focusedCell);
+
+ me.pressed = 0;
+ return 1;
+}
+
+float XonoticPicker_keyDown(entity me, float key, float ascii, float shift)
+{
+ switch(key)
+ {
+ case K_END:
+ case K_KP_END:
+ // lower left cell then left arrow to select the last valid cell
+ me.focusedCell = eY * (me.rows - 1);
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ me.moveFocus(me, me.focusedCell, '-1 0 0');
+ return 1;
+ case K_HOME:
+ case K_KP_HOME:
+ // upper right cell then right arrow to select the first valid cell
+ me.focusedCell = eX * (me.columns - 1);
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ me.moveFocus(me, me.focusedCell, '1 0 0');
+ return 1;
+ case K_UPARROW:
+ case K_KP_UPARROW:
+ me.moveFocus(me, me.focusedCell, '0 -1 0');
+ return 1;
+ case K_DOWNARROW:
+ case K_KP_DOWNARROW:
+ me.moveFocus(me, me.focusedCell, '0 1 0');
+ return 1;
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_INS:
+ case K_KP_INS:
+ me.cellSelect(me, me.focusedCell);
+ return 1;
+ }
+ return 0;
+}
+
+void XonoticPicker_moveFocus(entity me, vector initialCell, vector step)
+{
+ me.focusedCell_x = mod(me.focusedCell.x + step.x + me.columns, me.columns);
+ me.focusedCell_y = mod(me.focusedCell.y + step.y + me.rows, me.rows);
+
+ if(me.focusedCell != initialCell) // Recursion break
+ if(!me.cellIsValid(me, me.focusedCell))
+ me.moveFocus(me, initialCell, step);
+
+ me.focusedCellAlpha = SKINALPHA_LISTBOX_FOCUSED;
+}
+
+void XonoticPicker_cellSelect(entity me, vector cell)
+{
+ me.selectedCell = cell;
+}
+
+bool XonoticPicker_cellIsValid(entity me, vector cell)
+{
+ return true;
+}
+
+void XonoticPicker_cellDraw(entity me, vector cell, vector cellPos)
+{
+}
+
+void XonoticPicker_draw(entity me)
+{
+ float save;
+
+ me.focusable = !me.disabled;
+
+ save = draw_alpha;
+ if(me.disabled)
+ draw_alpha *= me.disabledAlpha;
+
+ vector cell, cellPos;
+ cell = '0 0 0';
+ cellPos = '0 0 0';
+
+ for(cell_y = 0; cell.y < me.rows; ++cell.y)
+ {
+ cellPos_y = mod(cell.y, me.rows) / me.rows;
+ for(cell_x = 0; cell.x < me.columns; ++cell.x)
+ {
+ if(!me.cellIsValid(me, cell))
+ continue;
+
+ cellPos_x = mod(cell.x, me.columns) / me.columns;
+
+ if(cell == me.selectedCell)
+ draw_Fill(cellPos, me.realCellSize, SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(cell == me.focusedCell && me.focused)
+ {
+ if(!me.pressed || me.focusedCell == me.pressedCell)
+ {
+ me.focusedCellAlpha = getFadedAlpha(me.focusedCellAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill(cellPos, me.realCellSize, SKINCOLOR_LISTBOX_FOCUSED, me.focusedCellAlpha);
+ }
+ }
+
+ me.cellDraw(me, cell, cellPos);
+ }
+ }
+
+ draw_alpha = save;
+
+ SUPER(XonoticPicker).draw(me);
+}
+#endif
-#ifdef INTERFACE
-CLASS(XonoticPlayerList) EXTENDS(XonoticListBox)
+#ifndef PLAYERLIST_H
+#define PLAYERLIST_H
+#include "listbox.qc"
+CLASS(XonoticPlayerList, XonoticListBox)
ATTRIB(XonoticPlayerList, rowsPerItem, float, 1)
METHOD(XonoticPlayerList, resizeNotify, void(entity, vector, vector, vector, vector))
- METHOD(XonoticPlayerList, drawListBoxItem, void(entity, float, vector, float))
+ 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)
entity makeXonoticPlayerList()
{
entity me;
- me = spawnXonoticPlayerList();
+ me = NEW(XonoticPlayerList);
me.configureXonoticListBox(me);
return me;
}
me.columnScoreOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize.x;
}
-void XonoticPlayerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticPlayerList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
string score;
-#ifdef INTERFACE
-CLASS(XonoticPlayerModelSelector) EXTENDS(XonoticImage)
+#ifndef PLAYERMODEL_H
+#define PLAYERMODEL_H
+#include "image.qc"
+CLASS(XonoticPlayerModelSelector, XonoticImage)
METHOD(XonoticPlayerModelSelector, configureXonoticPlayerModelSelector, void(entity))
METHOD(XonoticPlayerModelSelector, loadCvars, void(entity))
METHOD(XonoticPlayerModelSelector, saveCvars, void(entity))
entity makeXonoticPlayerModelSelector()
{
entity me;
- me = spawnXonoticPlayerModelSelector();
+ me = NEW(XonoticPlayerModelSelector);
me.configureXonoticPlayerModelSelector(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticPlayList) EXTENDS(XonoticListBox)
+#ifndef PLAYLIST_H
+#define PLAYLIST_H
+#include "listbox.qc"
+CLASS(XonoticPlayList, XonoticListBox)
METHOD(XonoticPlayList, configureXonoticPlayList, void(entity))
ATTRIB(XonoticPlayList, rowsPerItem, float, 1)
METHOD(XonoticPlayList, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(XonoticPlayList, draw, void(entity))
- METHOD(XonoticPlayList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticPlayList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticPlayList, stopSound, void(entity))
METHOD(XonoticPlayList, startSound, void(entity, float))
METHOD(XonoticPlayList, resumeSound, void(entity))
entity makeXonoticPlayList()
{
entity me;
- me = spawnXonoticPlayList();
+ me = NEW(XonoticPlayList);
me.configureXonoticPlayList(me);
return me;
}
SUPER(XonoticPlayList).draw(me);
}
-void XonoticPlayList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticPlayList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
if(i == me.playingTrack)
{
-#ifdef INTERFACE
-CLASS(XonoticRadioButton) EXTENDS(RadioButton)
+#ifndef RADIOBUTTON_H
+#define RADIOBUTTON_H
+#include "../item/radiobutton.qc"
+CLASS(XonoticRadioButton, RadioButton)
METHOD(XonoticRadioButton, configureXonoticRadioButton, void(entity, float, string, string, string))
METHOD(XonoticRadioButton, draw, void(entity))
METHOD(XonoticRadioButton, setChecked, void(entity, float))
entity makeXonoticRadioButton(float theGroup, string theCvar, string theValue, string theText)
{
entity me;
- me = spawnXonoticRadioButton();
+ me = NEW(XonoticRadioButton);
me.configureXonoticRadioButton(me, theGroup, theCvar, theValue, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticRootDialog) EXTENDS(XonoticDialog)
+#ifndef ROOTDIALOG_H
+#define ROOTDIALOG_H
+#include "dialog.qc"
+CLASS(XonoticRootDialog, XonoticDialog)
// still to be customized by user
/*
ATTRIB(XonoticDialog, closable, float, 1)
-#ifdef INTERFACE
-CLASS(XonoticScreenshotImage) EXTENDS(XonoticImage)
+#ifndef SCREENSHOTIMAGE_H
+#define SCREENSHOTIMAGE_H
+#include "image.qc"
+CLASS(XonoticScreenshotImage, XonoticImage)
METHOD(XonoticScreenshotImage, configureXonoticScreenshotImage, void(entity))
METHOD(XonoticScreenshotImage, load, void(entity, string))
METHOD(XonoticScreenshotImage, draw, void(entity))
entity makeXonoticScreenshotImage()
{
entity me;
- me = spawnXonoticScreenshotImage();
+ me = NEW(XonoticScreenshotImage);
me.configureXonoticScreenshotImage(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticScreenshotList) EXTENDS(XonoticListBox)
+#ifndef SCREENSHOTLIST_H
+#define SCREENSHOTLIST_H
+#include "listbox.qc"
+CLASS(XonoticScreenshotList, XonoticListBox)
METHOD(XonoticScreenshotList, configureXonoticScreenshotList, void(entity))
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, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticScreenshotList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticScreenshotList, getScreenshots, void(entity))
METHOD(XonoticScreenshotList, previewScreenshot, void(entity))
METHOD(XonoticScreenshotList, startScreenshot, void(entity))
entity makeXonoticScreenshotList()
{
entity me;
- me = spawnXonoticScreenshotList();
+ me = NEW(XonoticScreenshotList);
me.configureXonoticScreenshotList(me);
return me;
}
}
}
-void XonoticScreenshotList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticScreenshotList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
s = me.screenshotName(me,i);
s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-#ifdef INTERFACE
-CLASS(XonoticServerList) EXTENDS(XonoticListBox)
+#ifndef SERVERLIST_H
+#define SERVERLIST_H
+#include "listbox.qc"
+CLASS(XonoticServerList, XonoticListBox)
METHOD(XonoticServerList, configureXonoticServerList, void(entity))
ATTRIB(XonoticServerList, rowsPerItem, float, 1)
METHOD(XonoticServerList, draw, void(entity))
- METHOD(XonoticServerList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticServerList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticServerList, doubleClickListBoxItem, void(entity, float, vector))
METHOD(XonoticServerList, resizeNotify, void(entity, vector, vector, vector, vector))
METHOD(XonoticServerList, keyDown, float(entity, float, float, float))
void ServerList_Update_favoriteButton(entity btn, entity me);
// fields for category entities
-const float MAX_CATEGORIES = 9;
-const float CATEGORY_FIRST = 1;
+const int MAX_CATEGORIES = 9;
+const int CATEGORY_FIRST = 1;
entity categories[MAX_CATEGORIES];
-float category_ent_count;
+int category_ent_count;
.string cat_name;
.string cat_string;
.string cat_enoverride_string;
.float cat_dioverride;
// fields for drawing categories
-float category_name[MAX_CATEGORIES];
-float category_item[MAX_CATEGORIES];
-float category_draw_count;
+int category_name[MAX_CATEGORIES];
+int category_item[MAX_CATEGORIES];
+int category_draw_count;
#define SLIST_CATEGORIES \
SLIST_CATEGORY(CAT_FAVORITED, "", "", ZCTX(_("SLCAT^Favorites"))) \
#define SLIST_CATEGORY_AUTOCVAR(name) autocvar_menu_slist_categories_##name##_override
#define SLIST_CATEGORY(name,enoverride,dioverride,str) \
- float name; \
+ int name; \
string SLIST_CATEGORY_AUTOCVAR(name) = enoverride;
SLIST_CATEGORIES
#undef SLIST_CATEGORY
SLIST_CATEGORIES
#undef SLIST_CATEGORY
- float i, x, catnum;
+ int i, x, catnum;
string s;
#define PROCESS_OVERRIDE(override_string,override_field) \
}
// Supporting Functions
-entity RetrieveCategoryEnt(float catnum)
+entity RetrieveCategoryEnt(int catnum)
{
if((catnum > 0) && (catnum <= category_ent_count))
{
}
}
-float IsServerInList(string list, string srv)
+bool IsServerInList(string list, string srv)
{
string p;
- float i, n;
+ int i, n;
if(srv == "")
return false;
srv = netaddress_resolve(srv, 26000);
return false;
}
-float CheckCategoryOverride(float cat)
+int CheckCategoryOverride(int cat)
{
entity catent = RetrieveCategoryEnt(cat);
if(catent)
{
- float override = (autocvar_menu_slist_categories ? catent.cat_enoverride : catent.cat_dioverride);
+ int override = (autocvar_menu_slist_categories ? catent.cat_enoverride : catent.cat_dioverride);
if(override) { return override; }
else { return cat; }
}
}
}
-float CheckCategoryForEntry(float entry)
+int CheckCategoryForEntry(int entry)
{
string s, k, v, modtype = "";
- float j, m, impure = 0, freeslots = 0, sflags = 0;
+ int j, m, impure = 0, freeslots = 0, sflags = 0;
s = gethostcachestring(SLIST_FIELD_QCSTATUS, entry);
m = tokenizebyseparator(s, ":");
void XonoticServerList_toggleFavorite(entity me, string srv)
{
string s, s0, s1, s2, srv_resolved, p;
- float i, n, f;
+ int i, n;
+ bool f = false;
srv_resolved = netaddress_resolve(srv, 26000);
p = crypto_getidfp(srv_resolved);
s = cvar_string("net_slist_favorites");
n = tokenize_console(s);
- f = 0;
for(i = 0; i < n; ++i)
{
if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
cvar_set("net_slist_favorites", strcat(s0, s1, s2));
s = cvar_string("net_slist_favorites");
n = tokenize_console(s);
- f = 1;
+ f = true;
--i;
}
entity makeXonoticServerList()
{
entity me;
- me = spawnXonoticServerList();
+ me = NEW(XonoticServerList);
me.configureXonoticServerList(me);
return me;
}
// clear list
me.nItems = 0;
}
-void XonoticServerList_setSelected(entity me, float i)
+void XonoticServerList_setSelected(entity me, int i)
{
- float save;
- save = me.selectedItem;
+ //int save = me.selectedItem;
SUPER(XonoticServerList).setSelected(me, i);
/*
if(me.selectedItem == save)
me.ipAddressBox.cursorPos = strlen(me.selectedServer);
me.ipAddressBoxFocused = -1;
}
-void XonoticServerList_refreshServerList(entity me, float mode)
+void XonoticServerList_refreshServerList(entity me, int mode)
{
//print("refresh of type ", ftos(mode), "\n");
if(mode >= REFRESHSERVERLIST_REFILTER)
{
- float m, i, n;
- float listflags = 0;
+ float m;
+ int i, n;
+ int listflags = 0;
string s, typestr, modstr;
s = me.filterString;
void XonoticServerList_draw(entity me)
{
- float i, found, owned;
+ int i;
+ bool found = false, owned;
if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
{
me.infoButton.disabled = ((me.nItems == 0) || !owned);
me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
- found = 0;
if(me.selectedServer)
{
for(i = 0; i < me.nItems; ++i)
if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
{
me.selectedItem = i;
- found = 1;
+ found = true;
break;
}
}
me.ipAddressBox.cursorPos = 0;
me.ipAddressBoxFocused = -1;
}
-void XonoticServerList_setSortOrder(entity me, float fld, float direction)
+void XonoticServerList_setSortOrder(entity me, int fld, int direction)
{
if(me.currentSortField == fld)
direction = -me.currentSortOrder;
me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, _("Players"), ServerList_PlayerSort_Click);
- float f;
- f = me.currentSortField;
+ int f = me.currentSortField;
if(f >= 0)
{
me.currentSortField = -1;
vector sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
}
-void XonoticServerList_doubleClickListBoxItem(entity me, float i, vector where)
+void XonoticServerList_doubleClickListBoxItem(entity me, int i, vector where)
{
ServerList_Connect_Click(NULL, me);
}
-void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticServerList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
// layout: Ping, Server name, Map name, NP, TP, MP
- float p, q;
- float isv4, isv6;
+ float p;
+ int q;
+ bool isv4, isv6;
vector theColor;
float theAlpha;
- float m, pure, freeslots, j, sflags;
+ bool pure = false;
+ int freeslots = -1, sflags = -1, j, m;
string s, typestr, versionstr, k, v, modname;
//printf("time: %f, i: %d, item: %d, nitems: %d\n", time, i, item, me.nItems);
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
m = tokenizebyseparator(s, ":");
versionstr = argv(1);
}
freeslots = -1;
- sflags = -1;
modname = "";
- pure = 0;
for(j = 2; j < m; ++j)
{
if(argv(j) == "")
k = substring(argv(j), 0, 1);
v = substring(argv(j), 1, -1);
if(k == "P")
- pure = stof(v);
+ pure = stob(v);
else if(k == "S")
freeslots = stof(v);
else if(k == "F")
- sflags = stof(v);
+ sflags = stoi(v);
else if(k == "M")
modname = v;
}
if(modname != "CTS")
if(modname != "NIX")
if(modname != "NewToys")
- pure = 0;
+ pure = false;
if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
theAlpha = SKINALPHA_SERVERLIST_FULL;
theAlpha = 1;
p = gethostcachenumber(SLIST_FIELD_PING, i);
- const float PING_LOW = 75;
- const float PING_MED = 200;
- const float PING_HIGH = 500;
+ const int PING_LOW = 75;
+ const int PING_MED = 200;
+ const int PING_HIGH = 500;
if(p < PING_LOW)
theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
else if(p < PING_MED)
s = gethostcachestring(SLIST_FIELD_CNAME, i);
- isv4 = isv6 = 0;
+ isv4 = isv6 = false;
if(substring(s, 0, 1) == "[")
{
- isv6 = 1;
+ isv6 = true;
me.seenIPv6 += 1;
}
else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
{
- isv4 = 1;
+ isv4 = true;
me.seenIPv4 += 1;
}
iconPos_x = (me.columnIconsSize - 3 * iconSize.x) * 0.5;
iconPos_y = (1 - iconSize.y) * 0.5;
- string n;
-
- if (!(me.seenIPv4 && me.seenIPv6))
+ // IP
+ if(me.seenIPv4 && me.seenIPv6)
{
- iconPos.x += iconSize.x * 0.5;
- }
- else if(me.seenIPv4 && me.seenIPv6)
- {
- n = string_null;
if(isv6)
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
+ draw_Picture(iconPos, "icon_ipv6", iconSize, '1 1 1', 1);
else if(isv4)
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
- if(n)
- draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
- iconPos.x += iconSize.x;
+ draw_Picture(iconPos, "icon_ipv4", iconSize, '1 1 1', 1);
}
+ iconPos.x += iconSize.x;
+
+ // AES
if(q > 0)
- {
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
- draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
- }
+ draw_Picture(iconPos, strcat("icon_aeslevel", ftos(q)), iconSize, '1 1 1', 1);
+
iconPos.x += iconSize.x;
+ // Mod
if(modname == "Xonotic")
{
if(pure == 0)
- {
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
- draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
- }
+ draw_Picture(iconPos, "icon_pure1", iconSize, '1 1 1', 1);
}
else
{
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
- if(draw_PictureSize(n) == '0 0 0')
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
+ string icon = strcat("icon_mod_", modname);
+ if(draw_PictureSize(icon) == '0 0 0')
+ icon = "icon_mod_";
+
if(pure == 0)
- draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
+ draw_Picture(iconPos, icon, iconSize, '1 1 1', 1);
else
- draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
+ draw_Picture(iconPos, icon, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
}
+
iconPos.x += iconSize.x;
+ // Stats
if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
- {
- draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
- draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
- }
- iconPos.x += iconSize.x;
+ draw_Picture(iconPos, "icon_stats1", iconSize, '1 1 1', 1);
// --------------
// RENDER TEXT
draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
}
-float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
+bool XonoticServerList_keyDown(entity me, int scan, bool ascii, bool shift)
{
vector org, sz;
if(scan == K_ENTER || scan == K_KP_ENTER)
{
ServerList_Connect_Click(NULL, me);
- return 1;
+ return true;
}
else if(scan == K_MOUSE2 || scan == K_SPACE)
{
m_play_click_sound(MENU_SOUND_OPEN);
main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
{
{
me.toggleFavorite(me, me.selectedServer);
me.ipAddressBoxFocused = -1;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
- return 1;
+ return true;
else if(!me.controlledTextbox)
- return 0;
+ return false;
else
return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
}
-float XonoticServerList_getTotalHeight(entity me) {
+float XonoticServerList_getTotalHeight(entity me)
+{
float num_normal_rows = me.nItems;
- float num_headers = category_draw_count;
+ int num_headers = category_draw_count;
return me.itemHeight * (num_normal_rows + me.categoriesHeight * num_headers);
}
-float XonoticServerList_getItemAtPos(entity me, float pos) {
+int XonoticServerList_getItemAtPos(entity me, float pos)
+{
pos = pos / me.itemHeight;
- float i;
+ int i;
for (i = category_draw_count - 1; i >= 0; --i) {
- float itemidx = category_item[i];
+ int itemidx = category_item[i];
float itempos = i * me.categoriesHeight + category_item[i];
if (pos >= itempos + me.categoriesHeight + 1)
return itemidx + 1 + floor(pos - (itempos + me.categoriesHeight + 1));
// No category matches? Note that category 0 is... 0. Therefore no headings exist at all.
return floor(pos);
}
-float XonoticServerList_getItemStart(entity me, float item) {
- float i;
+float XonoticServerList_getItemStart(entity me, int item)
+{
+ int i;
for (i = category_draw_count - 1; i >= 0; --i) {
- float itemidx = category_item[i];
+ int itemidx = category_item[i];
float itempos = i * me.categoriesHeight + category_item[i];
if (item >= itemidx + 1)
return (itempos + me.categoriesHeight + 1 + item - (itemidx + 1)) * me.itemHeight;
// No category matches? Note that category 0 is... 0. Therefore no headings exist at all.
return item * me.itemHeight;
}
-float XonoticServerList_getItemHeight(entity me, float item) {
- float i;
+float XonoticServerList_getItemHeight(entity me, int item)
+{
+ int i;
for (i = 0; i < category_draw_count; ++i) {
// Matches exactly the headings with increased height.
if (item == category_item[i])
-#ifdef INTERFACE
-CLASS(XonoticSkinList) EXTENDS(XonoticListBox)
+#ifndef SKINLIST_H
+#define SKINLIST_H
+#include "listbox.qc"
+CLASS(XonoticSkinList, XonoticListBox)
METHOD(XonoticSkinList, configureXonoticSkinList, void(entity))
ATTRIB(XonoticSkinList, rowsPerItem, float, 4)
METHOD(XonoticSkinList, resizeNotify, void(entity, vector, vector, vector, vector))
- METHOD(XonoticSkinList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticSkinList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticSkinList, getSkins, void(entity))
METHOD(XonoticSkinList, setSkin, void(entity))
METHOD(XonoticSkinList, loadCvars, void(entity))
entity makeXonoticSkinList()
{
entity me;
- me = spawnXonoticSkinList();
+ me = NEW(XonoticSkinList);
me.configureXonoticSkinList(me);
return me;
}
void XonoticSkinList_getSkins(entity me)
{
float glob, buf, i, n, fh;
- string s;
+ string s, name;
buf = buf_create();
glob = search_begin("gfx/menu/*/skinvalues.txt", true, true);
for(i = 0; i < n; ++i)
{
s = search_getfilename(glob, i);
- bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_NAME, substring(s, 9, strlen(s) - 24)); // the * part
+ name = substring(s, 9, strlen(s) - 24); // the * part
+ bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_NAME, name);
bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, _("<TITLE>"));
bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, _("<AUTHOR>"));
if(draw_PictureSize(strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview")) == '0 0 0')
{
// these two are handled by skinlist.qc
if(substring(s, 0, 6) == "title ")
- bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, substring(s, 6, strlen(s) - 6));
+ {
+ if (name == cvar_defstring("menu_skin"))
+ bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, strcat(substring(s, 6, strlen(s) - 6), " (", _("Default"), ")"));
+ else
+ bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, substring(s, 6, strlen(s) - 6));
+ }
else if(substring(s, 0, 7) == "author ")
bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, substring(s, 7, strlen(s) - 7));
}
me.columnNameSize = 1 - me.columnPreviewSize - 2 * me.realFontSize.x;
}
-void XonoticSkinList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticSkinList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
s = me.skinParameter(me, i, SKINPARM_PREVIEW);
draw_Picture(me.columnPreviewOrigin * eX, s, me.columnPreviewSize * eX + eY, '1 1 1', 1);
-#ifdef INTERFACE
-CLASS(XonoticSlider) EXTENDS(Slider)
+#ifndef SLIDER_H
+#define SLIDER_H
+#include "../item/slider.qc"
+CLASS(XonoticSlider, Slider)
METHOD(XonoticSlider, configureXonoticSlider, void(entity, float, float, float, string))
METHOD(XonoticSlider, setValue, void(entity, float))
ATTRIB(XonoticSlider, fontSize, float, SKINFONTSIZE_NORMAL)
entity makeXonoticSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
{
entity me;
- me = spawnXonoticSlider();
+ me = NEW(XonoticSlider);
me.configureXonoticSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
return me;
}
#include "../../warpzonelib/mathlib.qh"
-#ifdef INTERFACE
-CLASS(XonoticDecibelsSlider) EXTENDS(XonoticSlider)
+#ifndef SLIDER_DECIBELS_H
+#define SLIDER_DECIBELS_H
+#include "slider.qc"
+CLASS(XonoticDecibelsSlider, XonoticSlider)
METHOD(XonoticDecibelsSlider, loadCvars, void(entity))
METHOD(XonoticDecibelsSlider, saveCvars, void(entity))
METHOD(XonoticDecibelsSlider, valueToText, string(entity, float))
entity makeXonoticDecibelsSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
{
entity me;
- me = spawnXonoticDecibelsSlider();
+ me = NEW(XonoticDecibelsSlider);
me.configureXonoticSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticParticlesSlider) EXTENDS(XonoticTextSlider)
+#ifndef SLIDER_PARTICLES_H
+#define SLIDER_PARTICLES_H
+#include "textslider.qc"
+CLASS(XonoticParticlesSlider, XonoticTextSlider)
METHOD(XonoticParticlesSlider, configureXonoticParticlesSlider, void(entity))
METHOD(XonoticParticlesSlider, loadCvars, void(entity))
METHOD(XonoticParticlesSlider, saveCvars, void(entity))
entity makeXonoticParticlesSlider()
{
entity me;
- me = spawnXonoticParticlesSlider();
+ me = NEW(XonoticParticlesSlider);
me.configureXonoticParticlesSlider(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticPicmipSlider) EXTENDS(XonoticTextSlider)
+#ifndef SLIDER_PICMIP_H
+#define SLIDER_PICMIP_H
+#include "textslider.qc"
+CLASS(XonoticPicmipSlider, XonoticTextSlider)
METHOD(XonoticPicmipSlider, configureXonoticPicmipSlider, void(entity))
METHOD(XonoticPicmipSlider, draw, void(entity))
METHOD(XonoticPicmipSlider, autofix, void(entity))
entity makeXonoticPicmipSlider()
{
entity me;
- me = spawnXonoticPicmipSlider();
+ me = NEW(XonoticPicmipSlider);
me.configureXonoticPicmipSlider(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticResolutionSlider) EXTENDS(XonoticTextSlider)
+#ifndef SLIDER_RESOLUTION_H
+#define SLIDER_RESOLUTION_H
+#include "textslider.qc"
+CLASS(XonoticResolutionSlider, XonoticTextSlider)
METHOD(XonoticResolutionSlider, configureXonoticResolutionSlider, void(entity))
METHOD(XonoticResolutionSlider, loadResolutions, void(entity, float))
METHOD(XonoticResolutionSlider, addResolution, void(entity, float, float, float))
entity makeXonoticResolutionSlider()
{
entity me;
- me = spawnXonoticResolutionSlider();
+ me = NEW(XonoticResolutionSlider);
me.configureXonoticResolutionSlider(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticScoreboardFadeTimeSlider) EXTENDS(XonoticTextSlider)
+#ifndef SLIDER_SBFADETIME_H
+#define SLIDER_SBFADETIME_H
+#include "textslider.qc"
+CLASS(XonoticScoreboardFadeTimeSlider, XonoticTextSlider)
METHOD(XonoticScoreboardFadeTimeSlider, configureXonoticScoreboardFadeTimeSlider, void(entity))
METHOD(XonoticScoreboardFadeTimeSlider, loadCvars, void(entity))
METHOD(XonoticScoreboardFadeTimeSlider, saveCvars, void(entity))
entity makeXonoticScoreboardFadeTimeSlider()
{
entity me;
- me = spawnXonoticScoreboardFadeTimeSlider();
+ me = NEW(XonoticScoreboardFadeTimeSlider);
me.configureXonoticScoreboardFadeTimeSlider(me);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticSoundList) EXTENDS(XonoticListBox)
+#ifndef SOUNDLIST_H
+#define SOUNDLIST_H
+#include "listbox.qc"
+CLASS(XonoticSoundList, XonoticListBox)
METHOD(XonoticSoundList, configureXonoticSoundList, void(entity))
ATTRIB(XonoticSoundList, rowsPerItem, float, 1)
METHOD(XonoticSoundList, resizeNotify, void(entity, vector, vector, vector, vector))
- METHOD(XonoticSoundList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticSoundList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticSoundList, getSounds, void(entity))
METHOD(XonoticSoundList, soundName, string(entity, float))
METHOD(XonoticSoundList, doubleClickListBoxItem, void(entity, float, vector))
entity makeXonoticSoundList()
{
entity me;
- me = spawnXonoticSoundList();
+ me = NEW(XonoticSoundList);
me.configureXonoticSoundList(me);
return me;
}
me.columnNameSize = 1 - me.columnNameOrigin - me.realFontSize.x;
}
-void XonoticSoundList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticSoundList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
string s;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
s = me.soundName(me,i);
if(s == cvar_string("menu_cdtrack")) // current menu track
#include "../../common/counting.qh"
#include "../../common/playerstats.qh"
-#ifdef INTERFACE
-CLASS(XonoticStatsList) EXTENDS(XonoticListBox)
+#ifndef STATSLIST_H
+#define STATSLIST_H
+#include "listbox.qc"
+CLASS(XonoticStatsList, XonoticListBox)
METHOD(XonoticStatsList, configureXonoticStatsList, void(entity))
ATTRIB(XonoticStatsList, rowsPerItem, float, 1.4)
METHOD(XonoticStatsList, resizeNotify, void(entity, vector, vector, vector, vector))
- METHOD(XonoticStatsList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(XonoticStatsList, drawListBoxItem, void(entity, int, vector, bool, bool))
METHOD(XonoticStatsList, getStats, void(entity))
METHOD(XonoticStatsList, doubleClickListBoxItem, void(entity, float, vector))
METHOD(XonoticStatsList, keyDown, float(entity, float, float, float))
entity makeXonoticStatsList()
{
entity me;
- me = spawnXonoticStatsList();
+ me = NEW(XonoticStatsList);
me.configureXonoticStatsList(me);
return me;
}
#endif
}
-void XonoticStatsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticStatsList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
string data = bufstr_get(me.listStats, i);
string s = car(data);
-#ifdef INTERFACE
-CLASS(XonoticTab) EXTENDS(Tab)
+#ifndef TAB_H
+#define TAB_H
+#include "../item/tab.qc"
+CLASS(XonoticTab, Tab)
// still to be customized by user
/*
ATTRIB(XonoticTab, intendedWidth, float, 0)
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, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
ATTRIB(XonoticTab, backgroundImage, string, string_null)
ENDCLASS(XonoticTab)
-#ifdef INTERFACE
-CLASS(XonoticTabController) EXTENDS(ModalController)
+#ifndef TABCONTROLLER_H
+#define TABCONTROLLER_H
+#include "../item/modalcontroller.qc"
+CLASS(XonoticTabController, ModalController)
METHOD(XonoticTabController, configureXonoticTabController, void(entity, float))
METHOD(XonoticTabController, makeTabButton, entity(entity, string, entity))
ATTRIB(XonoticTabController, rows, float, 0)
entity makeXonoticTabController(float theRows)
{
entity me;
- me = spawnXonoticTabController();
+ me = NEW(XonoticTabController);
me.configureXonoticTabController(me, theRows);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticTextLabel) EXTENDS(Label)
+#ifndef TEXTLABEL_H
+#define TEXTLABEL_H
+#include "../item/label.qc"
+CLASS(XonoticTextLabel, Label)
METHOD(XonoticTextLabel, configureXonoticTextLabel, void(entity, float, string))
METHOD(XonoticTextLabel, draw, void(entity))
ATTRIB(XonoticTextLabel, fontSize, float, SKINFONTSIZE_NORMAL)
ATTRIB(XonoticTextLabel, disabledAlpha, float, SKINALPHA_DISABLED)
ENDCLASS(XonoticTextLabel)
entity makeXonoticTextLabel(float theAlign, string theText);
+entity makeXonoticHeaderLabel(string theText);
#endif
#ifdef IMPLEMENTATION
entity makeXonoticTextLabel(float theAlign, string theText)
{
entity me;
- me = spawnXonoticTextLabel();
+ me = NEW(XonoticTextLabel);
me.configureXonoticTextLabel(me, theAlign, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticTextSlider) EXTENDS(TextSlider)
+#ifndef TEXTSLIDER_H
+#define TEXTSLIDER_H
+#include "../item/textslider.qc"
+CLASS(XonoticTextSlider, TextSlider)
METHOD(XonoticTextSlider, configureXonoticTextSlider, void(entity, string))
METHOD(XonoticTextSlider, setValue, void(entity, float))
METHOD(XonoticTextSlider, configureXonoticTextSliderValues, void(entity))
entity makeXonoticTextSlider(string theCvar)
{
entity me;
- me = spawnXonoticTextSlider();
+ me = NEW(XonoticTextSlider);
me.configureXonoticTextSlider(me, theCvar);
return me;
}
+#include "util.qh"
+#include "../menu.qh"
+#include "../oo/base.qh"
+#include "../../common/campaign_common.qh"
+#include "../../common/constants.qh"
+#include "../../common/mapinfo.qh"
#include "../../common/urllib.qh"
+#include "../../common/util.qh"
+#include "../../common/command/generic.qh"
float GL_CheckExtension(string ext)
{
return string_null;
}
+.entity parent, firstChild, nextSibling;
void forAllDescendants(entity root, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
{
depthfirst(root, parent, firstChild, nextSibling, funcPre, funcPost, pass);
void SUB_Null_ee(entity e1, entity e2)
{
}
+
+.void(entity) saveCvars;
void saveCvarsOf(entity ignore, entity e)
{
if(e.saveCvars)
e.saveCvars(e);
}
+
+.void(entity) loadCvars;
void loadCvarsOf(entity ignore, entity e)
{
if(e.loadCvars)
.string cvarString_setDependent;
.string cvarValue_setDependent;
.float(entity) func_setDependent;
+.bool disabled;
void setDependent_Check(entity e)
{
float f;
setDependent_Check(e);
e.draw_setDependent(e);
}
+.void(entity) draw;
void setDependent(entity e, string theCvarName, float theCvarMin, float theCvarMax)
{
e.draw_setDependent = e.draw;
draw_CenterText('0.5 0.1 0', sprintf(_("^1%s TEST BUILD"), autocvar_menu_watermark), globalToBoxSize('32 32 0', draw_scale), '1 1 1', 0.05, 1);
}
}
+void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
+.entity winnerDialog;
void preMenuDraw()
{
vector fs, sz = '0 0 0', line, mid;
// note: include only those that should be in the menu!
#define GAMETYPES \
- GAMETYPE(MAPINFO_TYPE_ASSAULT) \
+ GAMETYPE(MAPINFO_TYPE_DEATHMATCH) \
+ GAMETYPE(MAPINFO_TYPE_TEAM_DEATHMATCH) \
GAMETYPE(MAPINFO_TYPE_CTF) \
GAMETYPE(MAPINFO_TYPE_CA) \
- GAMETYPE(MAPINFO_TYPE_DEATHMATCH) \
- GAMETYPE(MAPINFO_TYPE_DOMINATION) \
GAMETYPE(MAPINFO_TYPE_FREEZETAG) \
GAMETYPE(MAPINFO_TYPE_KEEPAWAY) \
GAMETYPE(MAPINFO_TYPE_KEYHUNT) \
GAMETYPE(MAPINFO_TYPE_LMS) \
+ GAMETYPE(MAPINFO_TYPE_DOMINATION) \
GAMETYPE(MAPINFO_TYPE_NEXBALL) \
GAMETYPE(MAPINFO_TYPE_ONSLAUGHT) \
+ GAMETYPE(MAPINFO_TYPE_ASSAULT) \
if (cvar("developer")) GAMETYPE(MAPINFO_TYPE_RACE) \
GAMETYPE(MAPINFO_TYPE_CTS) \
- GAMETYPE(MAPINFO_TYPE_TEAM_DEATHMATCH) \
//GAMETYPE(MAPINFO_TYPE_INVASION) \
/* nothing */
return "";
}
+.void(entity) TR;
+.void(entity, float, float, entity) TD;
+.void(entity, float) TDempty;
+entity makeXonoticTextLabel(float theAlign, string theText);
+entity makeXonoticTextSlider(string);
+.void(entity, string, string) addValue;
+.void(entity) configureXonoticTextSliderValues;
+entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar);
+entity makeXonoticCheckBoxString(string, string, string, string);
+entity makeXonoticCheckBox(float, string, string);
+.bool sendCvars;
+
void dialog_hudpanel_common_notoggle(entity me, string panelname)
{
float i;
e.configureXonoticTextSliderValues(e);
}
+float getFadedAlpha(float currentAlpha, float startAlpha, float targetAlpha)
+{
+ if(startAlpha < targetAlpha)
+ currentAlpha = min(currentAlpha + frametime * 0.5, targetAlpha);
+ else
+ currentAlpha = max(currentAlpha - frametime * 0.5, targetAlpha);
+ return currentAlpha;
+}
+
void CheckSendCvars(entity me, string cvarnamestring)
{
if(me.sendCvars)
me.TD(me, 1, 4, e = makeXonoticCheckBox(0, strzone(strcat("hud_panel_", panelname)), _("Enable panel"))); \
DIALOG_HUDPANEL_COMMON_NOTOGGLE()
+float getFadedAlpha(float currentAlpha, float startAlpha, float targetAlpha);
+
string _Nex_ExtResponseSystem_BannedServers;
float _Nex_ExtResponseSystem_BannedServersNeedsRefresh;
string _Nex_ExtResponseSystem_PromotedServers;
-#ifdef INTERFACE
-CLASS(XonoticWeaponarenaCheckBox) EXTENDS(CheckBox)
+#ifndef WEAPONARENACHECKBOX_H
+#define WEAPONARENACHECKBOX_H
+#include "../item/checkbox.qc"
+CLASS(XonoticWeaponarenaCheckBox, CheckBox)
METHOD(XonoticWeaponarenaCheckBox, configureXonoticWeaponarenaCheckBox, void(entity, string, string))
METHOD(XonoticWeaponarenaCheckBox, setChecked, void(entity, float))
ATTRIB(XonoticWeaponarenaCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
entity makeXonoticWeaponarenaCheckBox(string theWeapon, string theText)
{
entity me;
- me = spawnXonoticWeaponarenaCheckBox();
+ me = NEW(XonoticWeaponarenaCheckBox);
me.configureXonoticWeaponarenaCheckBox(me, theWeapon, theText);
return me;
}
-#ifdef INTERFACE
-CLASS(XonoticWeaponsList) EXTENDS(XonoticListBox)
+#ifndef WEAPONSLIST_H
+#define WEAPONSLIST_H
+#include "listbox.qc"
+CLASS(XonoticWeaponsList, XonoticListBox)
METHOD(XonoticWeaponsList, configureXonoticWeaponsList, void(entity))
METHOD(XonoticWeaponsList, toString, string(entity))
ATTRIB(XonoticWeaponsList, rowsPerItem, float, 1)
METHOD(XonoticWeaponsList, draw, void(entity))
- METHOD(XonoticWeaponsList, drawListBoxItem, void(entity, float, vector, float))
+ 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')
entity makeXonoticWeaponsList()
{
entity me;
- me = spawnXonoticWeaponsList();
+ me = NEW(XonoticWeaponsList);
me.configureXonoticWeaponsList(me);
return me;
}
}
float XonoticWeaponsList_mouseDrag(entity me, vector pos)
{
- float f, i;
- i = me.selectedItem;
- f = SUPER(XonoticWeaponsList).mouseDrag(me, pos);
+ int i = me.selectedItem;
+ float f = SUPER(XonoticWeaponsList).mouseDrag(me, pos);
if(me.pressed != 1) // don't change priority if the person is just scrolling
{
}
return substring(s, 0, strlen(s) - 2);
}
-void XonoticWeaponsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+void XonoticWeaponsList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
entity e;
if(isSelected)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(isFocused)
+ {
+ me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
+ }
e = get_weaponinfo(stof(argv(i)));
string msg = e.message;
if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
--- /dev/null
+#ifndef SERVER_ALL_H
+#define SERVER_ALL_H
+
+#include "autocvars.qh"
+#include "constants.qh"
+#include "defs.qh"
+#include "miscfunctions.qh"
+
+#include "../dpdefs/progsdefs.qh"
+#include "../dpdefs/dpextensions.qh"
+
+#endif
void mean_accumulate(entity e, .float a, .float c, float mean, float value, float weight)
{
- if(weight == 0)
+ if (weight == 0)
return;
- if(mean == 0)
- e.a *= pow(value, weight);
+ if (mean == 0)
+ e.(a) *= pow(value, weight);
else
- e.a += pow(value, mean) * weight;
- e.c += weight;
+ e.(a) += pow(value, mean) * weight;
+ e.(c) += weight;
}
float mean_evaluate(entity e, .float a, .float c, float mean)
{
- if(e.c == 0)
+ if (e.(c) == 0)
return 0;
- if(mean == 0)
- return pow(e.a, 1.0 / e.c);
+ if (mean == 0)
+ return pow(e.(a), 1.0 / e.(c));
else
- return pow(e.a / e.c, 1.0 / mean);
+ return pow(e.(a) / e.(c), 1.0 / mean);
}
#define MEAN_ACCUMULATE(prefix,v,w) mean_accumulate(self,prefix##_accumulator,prefix##_count,prefix##_mean,v,w)
#elif defined(SVQC)
#include "../dpdefs/progsdefs.qh"
#include "../dpdefs/dpextensions.qh"
- #include "vehicles/vehicles_def.qh"
+ #include "vehicles/vehicle.qh"
#include "antilag.qh"
#endif
vector antilag_takebackorigin(entity e, float t)
{
- float i0, i1;
-
- i0 = antilag_find(e, t);
- if(i0 < 0)
+ int i0 = antilag_find(e, t);
+ if (i0 < 0)
{
// IN THE PRESENT
if(e.antilag_takenback)
else
return e.origin;
}
- i1 = i0 + 1;
- if(i1 >= ANTILAG_MAX_ORIGINS)
+ int i1 = i0 + 1;
+ if (i1 >= ANTILAG_MAX_ORIGINS)
i1 = 0;
return lerpv(e.(antilag_times[i0]), e.(antilag_origins[i0]), e.(antilag_times[i1]), e.(antilag_origins[i1]), t);
void antilag_clear(entity e)
{
- float i;
-
antilag_restore(e);
- for(i = 0; i < ANTILAG_MAX_ORIGINS; ++i)
+ for (int i = 0; i < ANTILAG_MAX_ORIGINS; ++i)
{
e.(antilag_times[i]) = -2342;
e.(antilag_origins[i]) = e.origin;
float autocvar_g_balance_keyhunt_dropvelocity;
float autocvar_g_balance_keyhunt_maxdist;
float autocvar_g_balance_keyhunt_protecttime;
-float autocvar_g_balance_keyhunt_score_capture;
-float autocvar_g_balance_keyhunt_score_carrierfrag;
-float autocvar_g_balance_keyhunt_score_collect;
-float autocvar_g_balance_keyhunt_score_destroyed;
-float autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
-float autocvar_g_balance_keyhunt_score_push;
+int autocvar_g_balance_keyhunt_score_capture;
+int autocvar_g_balance_keyhunt_score_carrierfrag;
+int autocvar_g_balance_keyhunt_score_collect;
+int autocvar_g_balance_keyhunt_score_destroyed;
+int autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
+int autocvar_g_balance_keyhunt_score_push;
float autocvar_g_balance_keyhunt_throwvelocity;
float autocvar_g_balance_kill_delay;
float autocvar_g_balance_kill_antispam;
float autocvar_g_balance_nexball_secondary_lifetime;
float autocvar_g_balance_nexball_secondary_refire;
float autocvar_g_balance_nexball_secondary_speed;
-float autocvar_g_balance_nix_ammo_cells;
-float autocvar_g_balance_nix_ammo_plasma;
-float autocvar_g_balance_nix_ammo_fuel;
-float autocvar_g_balance_nix_ammo_nails;
-float autocvar_g_balance_nix_ammo_rockets;
-float autocvar_g_balance_nix_ammo_shells;
-float autocvar_g_balance_nix_ammoincr_cells;
-float autocvar_g_balance_nix_ammoincr_plasma;
-float autocvar_g_balance_nix_ammoincr_fuel;
-float autocvar_g_balance_nix_ammoincr_nails;
-float autocvar_g_balance_nix_ammoincr_rockets;
-float autocvar_g_balance_nix_ammoincr_shells;
+int autocvar_g_balance_nix_ammo_cells;
+int autocvar_g_balance_nix_ammo_plasma;
+int autocvar_g_balance_nix_ammo_fuel;
+int autocvar_g_balance_nix_ammo_nails;
+int autocvar_g_balance_nix_ammo_rockets;
+int autocvar_g_balance_nix_ammo_shells;
+int autocvar_g_balance_nix_ammoincr_cells;
+int autocvar_g_balance_nix_ammoincr_plasma;
+int autocvar_g_balance_nix_ammoincr_fuel;
+int autocvar_g_balance_nix_ammoincr_nails;
+int autocvar_g_balance_nix_ammoincr_rockets;
+int autocvar_g_balance_nix_ammoincr_shells;
float autocvar_g_balance_nix_incrtime;
float autocvar_g_balance_nix_roundtime;
float autocvar_g_balance_pause_armor_rot;
float autocvar_g_balance_powerup_strength_time;
float autocvar_g_balance_superweapons_time;
float autocvar_g_balance_selfdamagepercent;
-float autocvar_g_balance_teams;
-float autocvar_g_balance_teams_prevent_imbalance;
+bool autocvar_g_balance_teams;
+bool autocvar_g_balance_teams_prevent_imbalance;
float autocvar_g_balance_teams_scorefactor;
float autocvar_g_ballistics_density_corpse;
float autocvar_g_ballistics_density_player;
float autocvar_g_ban_sync_interval;
float autocvar_g_ban_sync_timeout;
string autocvar_g_ban_sync_trusted_servers;
-float autocvar_g_ban_sync_trusted_servers_verify;
+bool autocvar_g_ban_sync_trusted_servers_verify;
string autocvar_g_ban_sync_uri;
string autocvar_g_banned_list;
-float autocvar_g_banned_list_idmode;
-float autocvar_g_bastet;
-float autocvar_g_botclip_collisions;
-float autocvar_g_bugrigs;
+bool autocvar_g_banned_list_idmode;
+bool autocvar_g_bastet;
+bool autocvar_g_botclip_collisions;
+bool autocvar_g_bugrigs;
float autocvar_g_ca_damage2score_multiplier;
-float autocvar_g_ca_point_leadlimit;
-float autocvar_g_ca_point_limit;
+int autocvar_g_ca_point_leadlimit;
+int autocvar_g_ca_point_limit;
float autocvar_g_ca_round_timelimit;
-float autocvar_g_ca_spectate_enemies;
-float autocvar_g_ca_teams;
-float autocvar_g_ca_teams_override;
-float autocvar_g_ca_team_spawns;
+bool autocvar_g_ca_spectate_enemies;
+int autocvar_g_ca_teams;
+int autocvar_g_ca_teams_override;
+bool autocvar_g_ca_team_spawns;
float autocvar_g_ca_warmup;
-float autocvar_g_campaign;
+bool autocvar_g_campaign;
#define autocvar_g_campaign_forceteam cvar("g_campaign_forceteam")
-float autocvar_g_campaign_skill;
-float autocvar_g_casings;
-float autocvar_g_changeteam_banned;
+int autocvar_g_campaign_skill;
+int autocvar_g_casings;
+bool autocvar_g_changeteam_banned;
float autocvar_g_chat_flood_burst;
float autocvar_g_chat_flood_burst_team;
float autocvar_g_chat_flood_burst_tell;
float autocvar_g_chat_flood_lmax;
float autocvar_g_chat_flood_lmax_team;
float autocvar_g_chat_flood_lmax_tell;
-float autocvar_g_chat_flood_notify_flooder;
+bool autocvar_g_chat_flood_notify_flooder;
float autocvar_g_chat_flood_spl;
float autocvar_g_chat_flood_spl_team;
float autocvar_g_chat_flood_spl_tell;
-float autocvar_g_chat_nospectators;
-float autocvar_g_chat_teamcolors;
-float autocvar_g_chat_tellprivacy;
-float autocvar_g_ctf_allow_vehicle_carry;
-float autocvar_g_ctf_allow_vehicle_touch;
-float autocvar_g_ctf_allow_monster_touch;
-float autocvar_g_ctf_throw;
+int autocvar_g_chat_nospectators;
+bool autocvar_g_chat_teamcolors;
+bool autocvar_g_chat_tellprivacy;
+bool autocvar_g_ctf_allow_vehicle_carry;
+bool autocvar_g_ctf_allow_vehicle_touch;
+bool autocvar_g_ctf_allow_monster_touch;
+bool autocvar_g_ctf_throw;
float autocvar_g_ctf_throw_angle_max;
float autocvar_g_ctf_throw_angle_min;
-float autocvar_g_ctf_throw_punish_count;
+int autocvar_g_ctf_throw_punish_count;
float autocvar_g_ctf_throw_punish_delay;
float autocvar_g_ctf_throw_punish_time;
float autocvar_g_ctf_throw_strengthmultiplier;
float autocvar_g_ctf_throw_velocity_up;
float autocvar_g_ctf_drop_velocity_up;
float autocvar_g_ctf_drop_velocity_side;
-float autocvar_g_ctf_portalteleport;
-float autocvar_g_ctf_pass;
+bool autocvar_g_ctf_portalteleport;
+bool autocvar_g_ctf_pass;
float autocvar_g_ctf_pass_arc;
float autocvar_g_ctf_pass_arc_max;
float autocvar_g_ctf_pass_directional_max;
float autocvar_g_ctf_pass_directional_min;
float autocvar_g_ctf_pass_radius;
float autocvar_g_ctf_pass_wait;
-float autocvar_g_ctf_pass_request;
+bool autocvar_g_ctf_pass_request;
float autocvar_g_ctf_pass_turnrate;
float autocvar_g_ctf_pass_timelimit;
float autocvar_g_ctf_pass_velocity;
-float autocvar_g_ctf_dynamiclights;
+bool autocvar_g_ctf_dynamiclights;
string autocvar_g_ctf_flag_blue_model;
-float autocvar_g_ctf_flag_blue_skin;
+int autocvar_g_ctf_flag_blue_skin;
float autocvar_g_ctf_flag_collect_delay;
float autocvar_g_ctf_flag_damageforcescale;
-float autocvar_g_ctf_flag_dropped_waypoint;
+int autocvar_g_ctf_flag_dropped_waypoint;
float autocvar_g_ctf_flag_dropped_floatinwater;
-float autocvar_g_ctf_flag_glowtrails;
+bool autocvar_g_ctf_flag_glowtrails;
float autocvar_g_ctf_flag_health;
string autocvar_g_ctf_flag_red_model;
-float autocvar_g_ctf_flag_red_skin;
+int autocvar_g_ctf_flag_red_skin;
float autocvar_g_ctf_flag_return_time;
-float autocvar_g_ctf_flag_return_when_unreachable;
+bool autocvar_g_ctf_flag_return_when_unreachable;
float autocvar_g_ctf_flag_return_damage;
float autocvar_g_ctf_flag_return_dropped;
float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
float autocvar_g_ctf_flagcarrier_damagefactor;
float autocvar_g_ctf_flagcarrier_forcefactor;
//float autocvar_g_ctf_flagcarrier_waypointforenemy_spotting;
-float autocvar_g_ctf_fullbrightflags;
-float autocvar_g_ctf_ignore_frags;
-float autocvar_g_ctf_score_capture;
-float autocvar_g_ctf_score_capture_assist;
-float autocvar_g_ctf_score_kill;
-float autocvar_g_ctf_score_penalty_drop;
-//float autocvar_g_ctf_score_penalty_suicidedrop;
-float autocvar_g_ctf_score_penalty_returned;
-float autocvar_g_ctf_score_pickup_base;
-float autocvar_g_ctf_score_pickup_dropped_early;
-float autocvar_g_ctf_score_pickup_dropped_late;
-float autocvar_g_ctf_score_return;
+bool autocvar_g_ctf_fullbrightflags;
+bool autocvar_g_ctf_ignore_frags;
+int autocvar_g_ctf_score_capture;
+int autocvar_g_ctf_score_capture_assist;
+int autocvar_g_ctf_score_kill;
+int autocvar_g_ctf_score_penalty_drop;
+//int autocvar_g_ctf_score_penalty_suicidedrop;
+int autocvar_g_ctf_score_penalty_returned;
+int autocvar_g_ctf_score_pickup_base;
+int autocvar_g_ctf_score_pickup_dropped_early;
+int autocvar_g_ctf_score_pickup_dropped_late;
+int autocvar_g_ctf_score_return;
float autocvar_g_ctf_shield_force;
float autocvar_g_ctf_shield_max_ratio;
-float autocvar_g_ctf_shield_min_negscore;
-float autocvar_g_ctf_stalemate;
-float autocvar_g_ctf_stalemate_endcondition;
+int autocvar_g_ctf_shield_min_negscore;
+bool autocvar_g_ctf_stalemate;
+int autocvar_g_ctf_stalemate_endcondition;
float autocvar_g_ctf_stalemate_time;
-float autocvar_g_ctf_reverse;
+bool autocvar_g_ctf_reverse;
float autocvar_g_ctf_dropped_capture_delay;
float autocvar_g_ctf_dropped_capture_radius;
float autocvar_g_cts_finish_kill_delay;
-float autocvar_g_cts_selfdamage;
-float autocvar_g_debug_bot_commands;
-float autocvar_g_domination_default_teams;
-float autocvar_g_domination_disable_frags;
-float autocvar_g_domination_point_amt;
-float autocvar_g_domination_point_fullbright;
-float autocvar_g_domination_point_leadlimit;
-float autocvar_g_domination_roundbased;
-float autocvar_g_domination_roundbased_point_limit;
+bool autocvar_g_cts_selfdamage;
+bool autocvar_g_debug_bot_commands;
+int autocvar_g_domination_default_teams;
+bool autocvar_g_domination_disable_frags;
+int autocvar_g_domination_point_amt;
+bool autocvar_g_domination_point_fullbright;
+int autocvar_g_domination_point_leadlimit;
+bool autocvar_g_domination_roundbased;
+int autocvar_g_domination_roundbased_point_limit;
float autocvar_g_domination_round_timelimit;
float autocvar_g_domination_warmup;
#define autocvar_g_domination_point_limit cvar("g_domination_point_limit")
float autocvar_g_domination_point_rate;
-float autocvar_g_domination_teams_override;
-float autocvar_g_forced_respawn;
+int autocvar_g_domination_teams_override;
+bool autocvar_g_forced_respawn;
string autocvar_g_forced_team_blue;
string autocvar_g_forced_team_otherwise;
string autocvar_g_forced_team_pink;
string autocvar_g_forced_team_red;
string autocvar_g_forced_team_yellow;
-float autocvar_g_freezetag_frozen_damage_trigger;
+bool autocvar_g_freezetag_frozen_damage_trigger;
float autocvar_g_freezetag_frozen_force;
float autocvar_g_freezetag_frozen_maxtime;
float autocvar_g_freezetag_revive_falldamage;
float autocvar_g_freezetag_revive_falldamage_health;
-float autocvar_g_freezetag_revive_nade;
+bool autocvar_g_freezetag_revive_nade;
float autocvar_g_freezetag_revive_nade_health;
-float autocvar_g_freezetag_point_leadlimit;
-float autocvar_g_freezetag_point_limit;
+int autocvar_g_freezetag_point_leadlimit;
+int autocvar_g_freezetag_point_limit;
float autocvar_g_freezetag_revive_extra_size;
float autocvar_g_freezetag_revive_speed;
float autocvar_g_freezetag_revive_clearspeed;
float autocvar_g_freezetag_round_timelimit;
-float autocvar_g_freezetag_teams;
-float autocvar_g_freezetag_teams_override;
-float autocvar_g_freezetag_team_spawns;
+int autocvar_g_freezetag_teams;
+int autocvar_g_freezetag_teams_override;
+bool autocvar_g_freezetag_team_spawns;
float autocvar_g_freezetag_warmup;
#define autocvar_g_friendlyfire cvar("g_friendlyfire")
#define autocvar_g_friendlyfire_virtual cvar("g_friendlyfire_virtual")
#define autocvar_g_friendlyfire_virtual_force cvar("g_friendlyfire_virtual_force")
-float autocvar_g_full_getstatus_responses;
-float autocvar_g_fullbrightitems;
-float autocvar_g_fullbrightplayers;
+bool autocvar_g_full_getstatus_responses;
+bool autocvar_g_fullbrightitems;
+bool autocvar_g_fullbrightplayers;
#define autocvar_g_grappling_hook cvar("g_grappling_hook")
-float autocvar_g_grappling_hook_tarzan;
-float autocvar_g_hitplots;
+int autocvar_g_grappling_hook_tarzan;
+bool autocvar_g_hitplots;
string autocvar_g_hitplots_individuals;
float autocvar_g_jetpack_acceleration_side;
float autocvar_g_jetpack_acceleration_up;
float autocvar_g_jetpack_antigravity;
-float autocvar_g_jetpack_fuel;
+int autocvar_g_jetpack_fuel;
float autocvar_g_jetpack_maxspeed_side;
float autocvar_g_jetpack_maxspeed_up;
-float autocvar_g_keepaway_ballcarrier_effects;
+int autocvar_g_keepaway_ballcarrier_effects;
float autocvar_g_keepaway_ballcarrier_damage;
float autocvar_g_keepaway_ballcarrier_force;
float autocvar_g_keepaway_ballcarrier_highspeed;
float autocvar_g_keepaway_noncarrier_force;
float autocvar_g_keepaway_noncarrier_selfdamage;
float autocvar_g_keepaway_noncarrier_selfforce;
-float autocvar_g_keepaway_noncarrier_warn;
-float autocvar_g_keepaway_score_bckill;
-float autocvar_g_keepaway_score_killac;
-float autocvar_g_keepaway_score_timepoints;
+bool autocvar_g_keepaway_noncarrier_warn;
+int autocvar_g_keepaway_score_bckill;
+int autocvar_g_keepaway_score_killac;
+int autocvar_g_keepaway_score_timepoints;
float autocvar_g_keepaway_score_timeinterval;
float autocvar_g_keepawayball_damageforcescale;
-float autocvar_g_keepawayball_effects;
+int autocvar_g_keepawayball_effects;
float autocvar_g_keepawayball_respawntime;
-float autocvar_g_keepawayball_trail_color;
-float autocvar_g_keyhunt_point_leadlimit;
+int autocvar_g_keepawayball_trail_color;
+int autocvar_g_keyhunt_point_leadlimit;
#define autocvar_g_keyhunt_point_limit cvar("g_keyhunt_point_limit")
-float autocvar_g_keyhunt_teams;
-float autocvar_g_keyhunt_teams_override;
-float autocvar_g_lms_extra_lives;
-float autocvar_g_lms_join_anytime;
-float autocvar_g_lms_last_join;
+int autocvar_g_keyhunt_teams;
+int autocvar_g_keyhunt_teams_override;
+int autocvar_g_lms_extra_lives;
+bool autocvar_g_lms_join_anytime;
+int autocvar_g_lms_last_join;
#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
-float autocvar_g_lms_regenerate;
+bool autocvar_g_lms_regenerate;
#define autocvar_g_maplist cvar_string("g_maplist")
-float autocvar_g_maplist_check_waypoints;
-float autocvar_g_maplist_index;
+bool autocvar_g_maplist_check_waypoints;
+int autocvar_g_maplist_index;
string autocvar_g_maplist_mostrecent;
-float autocvar_g_maplist_mostrecent_count;
-float autocvar_g_maplist_selectrandom;
+int autocvar_g_maplist_mostrecent_count;
+bool autocvar_g_maplist_selectrandom;
float autocvar_g_maplist_shuffle;
#define autocvar_g_maplist_votable cvar("g_maplist_votable")
-float autocvar_g_maplist_votable_abstain;
+bool autocvar_g_maplist_votable_abstain;
float autocvar_g_maplist_votable_keeptwotime;
-float autocvar_g_maplist_votable_nodetail;
+bool autocvar_g_maplist_votable_nodetail;
string autocvar_g_maplist_votable_screenshot_dir;
-float autocvar_g_maplist_votable_suggestions;
-float autocvar_g_maplist_votable_suggestions_override_mostrecent;
+bool autocvar_g_maplist_votable_suggestions;
+bool autocvar_g_maplist_votable_suggestions_override_mostrecent;
float autocvar_g_maplist_votable_timeout;
-float autocvar_g_maxplayers;
+int autocvar_g_maxplayers;
float autocvar_g_maxplayers_spectator_blocktime;
float autocvar_g_maxpushtime;
float autocvar_g_maxspeed;
float autocvar_g_midair_shieldtime;
#define autocvar_g_instagib cvar("g_instagib")
-float autocvar_g_instagib_ammo_drop;
-float autocvar_g_instagib_extralives;
+int autocvar_g_instagib_ammo_drop;
+int autocvar_g_instagib_extralives;
float autocvar_g_instagib_speed_highspeed;
float autocvar_g_instagib_invis_alpha;
#define autocvar_g_mirrordamage cvar("g_mirrordamage")
#define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
float autocvar_g_movement_highspeed = 1;
-float autocvar_g_multijump;
+int autocvar_g_multijump;
float autocvar_g_multijump_add;
float autocvar_g_multijump_speed;
string autocvar_g_mutatormsg;
float autocvar_g_nexball_basketball_bouncefactor;
float autocvar_g_nexball_basketball_bouncestop;
float autocvar_g_nexball_basketball_carrier_highspeed;
-float autocvar_g_nexball_basketball_meter;
+bool autocvar_g_nexball_basketball_meter;
float autocvar_g_nexball_basketball_meter_maxpower;
float autocvar_g_nexball_basketball_meter_minpower;
float autocvar_g_nexball_delay_collect;
float autocvar_g_nexball_delay_start;
float autocvar_g_nexball_football_bouncefactor;
float autocvar_g_nexball_football_bouncestop;
-float autocvar_g_nexball_goalleadlimit;
+int autocvar_g_nexball_goalleadlimit;
#define autocvar_g_nexball_goallimit cvar("g_nexball_goallimit")
-float autocvar_g_nexball_radar_showallplayers;
-float autocvar_g_nexball_sound_bounce;
-float autocvar_g_nexball_trail_color;
+bool autocvar_g_nexball_radar_showallplayers;
+bool autocvar_g_nexball_sound_bounce;
+int autocvar_g_nexball_trail_color;
//float autocvar_g_nick_flood_penalty;
-float autocvar_g_nick_flood_penalty_red;
-float autocvar_g_nick_flood_penalty_yellow;
+int autocvar_g_nick_flood_penalty_red;
+int autocvar_g_nick_flood_penalty_yellow;
//float autocvar_g_nick_flood_timeout;
-float autocvar_g_nix_with_healtharmor;
-float autocvar_g_nix_with_blaster;
-float autocvar_g_nix_with_powerups;
-float autocvar_g_nodepthtestitems;
-float autocvar_g_nodepthtestplayers;
-float autocvar_g_norecoil;
+bool autocvar_g_nix_with_healtharmor;
+bool autocvar_g_nix_with_blaster;
+bool autocvar_g_nix_with_powerups;
+bool autocvar_g_nodepthtestitems;
+bool autocvar_g_nodepthtestplayers;
+bool autocvar_g_norecoil;
float autocvar_g_onslaught_cp_buildhealth;
float autocvar_g_onslaught_cp_buildtime;
float autocvar_g_onslaught_cp_health;
float autocvar_g_onslaught_cp_regen;
float autocvar_g_onslaught_gen_health;
-float autocvar_g_pickup_cells_max;
-float autocvar_g_pickup_plasma_max;
-float autocvar_g_pickup_fuel_max;
-float autocvar_g_pickup_items;
-float autocvar_g_pickup_nails_max;
-float autocvar_g_pickup_rockets_max;
-float autocvar_g_pickup_shells_max;
+int autocvar_g_pickup_cells_max;
+int autocvar_g_pickup_plasma_max;
+int autocvar_g_pickup_fuel_max;
+int autocvar_g_pickup_items;
+int autocvar_g_pickup_nails_max;
+int autocvar_g_pickup_rockets_max;
+int autocvar_g_pickup_shells_max;
float autocvar_g_player_alpha;
float autocvar_g_player_brightness;
-float autocvar_g_playerclip_collisions;
-float autocvar_g_powerups;
-float autocvar_g_projectiles_damage;
-float autocvar_g_projectiles_keep_owner;
-float autocvar_g_projectiles_newton_style;
+bool autocvar_g_playerclip_collisions;
+int autocvar_g_powerups;
+int autocvar_g_projectiles_damage;
+bool autocvar_g_projectiles_keep_owner;
+int autocvar_g_projectiles_newton_style;
float autocvar_g_projectiles_newton_style_2_maxfactor;
float autocvar_g_projectiles_newton_style_2_minfactor;
-float autocvar_g_projectiles_spread_style;
+int autocvar_g_projectiles_spread_style;
#define autocvar_g_race_laps_limit cvar("g_race_laps_limit")
float autocvar_g_race_qualifying_timelimit;
float autocvar_g_race_qualifying_timelimit_override;
-float autocvar_g_race_teams;
+int autocvar_g_race_teams;
float autocvar_g_respawn_delay_small;
-float autocvar_g_respawn_delay_small_count;
+int autocvar_g_respawn_delay_small_count;
float autocvar_g_respawn_delay_large;
-float autocvar_g_respawn_delay_large_count;
+int autocvar_g_respawn_delay_large_count;
float autocvar_g_respawn_delay_max;
-float autocvar_g_respawn_ghosts;
+bool autocvar_g_respawn_ghosts;
float autocvar_g_respawn_ghosts_maxtime;
float autocvar_g_respawn_ghosts_speed;
-float autocvar_g_respawn_waves;
-float autocvar_g_running_guns;
-float autocvar_g_shootfromcenter;
-float autocvar_g_shootfromclient;
-float autocvar_g_shootfromeye;
+int autocvar_g_respawn_waves;
+bool autocvar_g_running_guns;
+bool autocvar_g_shootfromcenter;
+int autocvar_g_shootfromclient;
+bool autocvar_g_shootfromeye;
string autocvar_g_shootfromfixedorigin;
-float autocvar_g_showweaponspawns;
-float autocvar_g_spawn_alloweffects;
+int autocvar_g_showweaponspawns;
+bool autocvar_g_spawn_alloweffects;
float autocvar_g_spawn_furthest;
-float autocvar_g_spawn_useallspawns;
-float autocvar_g_spawnpoints_auto_move_out_of_solid;
+bool autocvar_g_spawn_useallspawns;
+bool autocvar_g_spawnpoints_auto_move_out_of_solid;
#define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
-float autocvar_g_tdm_team_spawns;
-float autocvar_g_tdm_point_limit;
-float autocvar_g_tdm_point_leadlimit;
-float autocvar_g_tdm_teams;
-float autocvar_g_tdm_teams_override;
+bool autocvar_g_tdm_team_spawns;
+int autocvar_g_tdm_point_limit;
+int autocvar_g_tdm_point_leadlimit;
+int autocvar_g_tdm_teams;
+int autocvar_g_tdm_teams_override;
float autocvar_g_teamdamage_resetspeed;
float autocvar_g_teamdamage_threshold;
-float autocvar_g_telefrags;
-float autocvar_g_telefrags_avoid;
-float autocvar_g_telefrags_teamplay;
+bool autocvar_g_telefrags;
+bool autocvar_g_telefrags_avoid;
+bool autocvar_g_telefrags_teamplay;
float autocvar_g_teleport_maxspeed;
-float autocvar_g_throughfloor_debug;
+bool autocvar_g_throughfloor_debug;
float autocvar_g_throughfloor_damage;
float autocvar_g_throughfloor_force;
float autocvar_g_throughfloor_damage_max_stddev;
float autocvar_g_triggerimpulse_accel_power;
float autocvar_g_triggerimpulse_directional_multiplier;
float autocvar_g_triggerimpulse_radial_multiplier;
-float autocvar_g_turrets;
+bool autocvar_g_turrets;
float autocvar_g_turrets_aimidle_delay;
-float autocvar_g_turrets_nofire;
-float autocvar_g_turrets_reloadcvars;
+bool autocvar_g_turrets_nofire;
+bool autocvar_g_turrets_reloadcvars;
float autocvar_g_turrets_targetscan_maxdelay;
float autocvar_g_turrets_targetscan_mindelay;
float autocvar_g_turrets_unit_ewheel_speed_fast;
float autocvar_g_turrets_unit_walker_turn_run;
float autocvar_g_turrets_unit_walker_turn_strafe;
float autocvar_g_turrets_unit_walker_turn_swim;
-float autocvar_g_use_ammunition;
-float autocvar_g_waypointeditor;
-float autocvar_g_waypointeditor_auto;
-float autocvar_g_waypoints_for_items;
+bool autocvar_g_use_ammunition;
+bool autocvar_g_waypointeditor;
+int autocvar_g_waypointeditor_auto;
+int autocvar_g_waypoints_for_items;
float autocvar_g_weapon_charge_colormod_blue_full;
float autocvar_g_weapon_charge_colormod_blue_half;
float autocvar_g_weapon_charge_colormod_green_full;
float autocvar_g_weapon_charge_colormod_red_full;
float autocvar_g_weapon_charge_colormod_red_half;
#define autocvar_g_weapon_stay cvar("g_weapon_stay")
-float autocvar_g_weapon_throwable;
+bool autocvar_g_weapon_throwable;
#define autocvar_g_weaponarena cvar_string("g_weaponarena")
string autocvar_g_xonoticversion;
float autocvar_gameversion;
float autocvar_gameversion_min;
float autocvar_gameversion_max;
string autocvar_hostname;
-float autocvar_lastlevel;
-float autocvar_leadlimit;
-float autocvar_leadlimit_and_fraglimit;
-float autocvar_leadlimit_override;
-float autocvar_loddebug;
-float autocvar_minplayers;
+bool autocvar_lastlevel;
+int autocvar_leadlimit;
+int autocvar_leadlimit_and_fraglimit;
+int autocvar_leadlimit_override;
+int autocvar_loddebug;
+int autocvar_minplayers;
string autocvar_nextmap;
-float autocvar_prvm_backtraceforwarnings;
+bool autocvar_prvm_backtraceforwarnings;
string autocvar_quit_and_redirect;
float autocvar_quit_and_redirect_timer;
-float autocvar_quit_when_empty;
+bool autocvar_quit_when_empty;
float autocvar_r_showbboxes;
-float autocvar_rescan_pending;
-float autocvar_samelevel;
+int autocvar_rescan_pending;
+bool autocvar_samelevel;
string autocvar_sessionid;
#define autocvar_skill cvar("skill")
float autocvar_skill_auto;
#define autocvar_slowmo cvar("slowmo")
float autocvar_snd_soundradius;
-float autocvar_spawn_debug;
-float autocvar_speedmeter;
-float autocvar_sv_accelerate;
+int autocvar_spawn_debug;
+bool autocvar_speedmeter;
float autocvar_sv_accuracy_data_share = 1;
string autocvar_sv_adminnick;
-float autocvar_sv_airaccel_qw;
-float autocvar_sv_airaccel_qw_stretchfactor;
-float autocvar_sv_airaccel_sideways_friction;
-float autocvar_sv_airaccelerate;
-float autocvar_sv_aircontrol;
-float autocvar_sv_aircontrol_penalty;
-float autocvar_sv_aircontrol_power;
-float autocvar_sv_airspeedlimit_nonqw;
-float autocvar_sv_airstopaccelerate;
-float autocvar_sv_airstrafeaccel_qw;
-float autocvar_sv_airstrafeaccelerate;
-float autocvar_sv_autoscreenshot;
-float autocvar_sv_cheats;
+bool autocvar_sv_autoscreenshot;
+int autocvar_sv_cheats;
float autocvar_sv_clientcommand_antispam_time;
-float autocvar_sv_clientcommand_antispam_count;
-float autocvar_sv_curl_serverpackages_auto;
-float autocvar_sv_db_saveasdump;
-float autocvar_sv_defaultcharacter;
+int autocvar_sv_clientcommand_antispam_count;
+bool autocvar_sv_curl_serverpackages_auto;
+bool autocvar_sv_db_saveasdump;
+bool autocvar_sv_defaultcharacter;
string autocvar_sv_defaultplayercolors;
string autocvar_sv_defaultplayermodel;
string autocvar_sv_defaultplayermodel_blue;
string autocvar_sv_defaultplayermodel_pink;
string autocvar_sv_defaultplayermodel_red;
string autocvar_sv_defaultplayermodel_yellow;
-float autocvar_sv_defaultplayerskin;
+int autocvar_sv_defaultplayerskin;
float autocvar_sv_dodging_delay;
float autocvar_sv_dodging_height_threshold;
float autocvar_sv_dodging_horiz_speed;
float autocvar_sv_dodging_horiz_speed_frozen;
float autocvar_sv_dodging_ramp_time;
-float autocvar_sv_dodging_sound;
+bool autocvar_sv_dodging_sound;
float autocvar_sv_dodging_up_speed;
float autocvar_sv_dodging_wall_distance_threshold;
-float autocvar_sv_dodging_wall_dodging;
-float autocvar_sv_dodging_frozen;
-float autocvar_sv_dodging_frozen_doubletap;
-float autocvar_sv_doublejump;
-float autocvar_sv_eventlog;
-float autocvar_sv_eventlog_console;
-float autocvar_sv_eventlog_files;
-float autocvar_sv_eventlog_files_counter;
+bool autocvar_sv_dodging_wall_dodging;
+bool autocvar_sv_dodging_frozen;
+bool autocvar_sv_dodging_frozen_doubletap;
+bool autocvar_sv_doublejump;
+bool autocvar_sv_eventlog;
+bool autocvar_sv_eventlog_console;
+bool autocvar_sv_eventlog_files;
+int autocvar_sv_eventlog_files_counter;
string autocvar_sv_eventlog_files_nameprefix;
string autocvar_sv_eventlog_files_namesuffix;
-float autocvar_sv_eventlog_files_timestamps;
-float autocvar_sv_friction;
+bool autocvar_sv_eventlog_files_timestamps;
float autocvar_sv_friction_on_land;
+var float autocvar_sv_friction_slick = 0.5;
float autocvar_sv_gameplayfix_q2airaccelerate;
-float autocvar_sv_gentle;
+int autocvar_sv_gentle;
#define autocvar_sv_gravity cvar("sv_gravity")
string autocvar_sv_intermission_cdtrack;
-string autocvar_sv_jumpspeedcap_max;
+float autocvar_sv_jumpspeedcap_max;
float autocvar_sv_jumpspeedcap_max_disable_on_ramps;
-string autocvar_sv_jumpspeedcap_min;
+float autocvar_sv_jumpspeedcap_min;
float autocvar_sv_jumpvelocity;
-float autocvar_sv_logscores_bots;
-float autocvar_sv_logscores_console;
-float autocvar_sv_logscores_file;
+bool autocvar_sv_logscores_bots;
+bool autocvar_sv_logscores_console;
+bool autocvar_sv_logscores_file;
string autocvar_sv_logscores_filename;
float autocvar_sv_mapchange_delay;
float autocvar_sv_maxairspeed;
-float autocvar_sv_maxairstrafespeed;
float autocvar_sv_maxspeed;
string autocvar_sv_motd;
-float autocvar_sv_precacheplayermodels;
+bool autocvar_sv_precacheplayermodels;
//float autocvar_sv_precacheweapons; // WEAPONTODO?
-float autocvar_sv_q3acompat_machineshotgunswap;
-float autocvar_sv_ready_restart;
-float autocvar_sv_ready_restart_after_countdown;
-float autocvar_sv_ready_restart_repeatable;
-float autocvar_sv_servermodelsonly;
-float autocvar_sv_spectate;
+bool autocvar_sv_q3acompat_machineshotgunswap;
+bool autocvar_sv_ready_restart;
+bool autocvar_sv_ready_restart_after_countdown;
+bool autocvar_sv_ready_restart_repeatable;
+bool autocvar_sv_servermodelsonly;
+int autocvar_sv_spectate;
float autocvar_sv_spectator_speed_multiplier;
-float autocvar_sv_status_privacy;
+bool autocvar_sv_status_privacy;
float autocvar_sv_stepheight;
-float autocvar_sv_stopspeed;
float autocvar_sv_strengthsound_antispam_refire_threshold;
float autocvar_sv_strengthsound_antispam_time;
-float autocvar_sv_teamnagger;
-float autocvar_sv_timeout;
+bool autocvar_sv_teamnagger;
+bool autocvar_sv_timeout;
float autocvar_sv_timeout_leadtime;
float autocvar_sv_timeout_length;
-float autocvar_sv_timeout_number;
+int autocvar_sv_timeout_number;
float autocvar_sv_timeout_resumetime;
-float autocvar_sv_vote_call;
-float autocvar_sv_vote_change;
+bool autocvar_sv_vote_call;
+bool autocvar_sv_vote_change;
string autocvar_sv_vote_commands;
-float autocvar_sv_vote_gametype;
+bool autocvar_sv_vote_gametype;
float autocvar_sv_vote_gametype_timeout;
string autocvar_sv_vote_gametype_options;
float autocvar_sv_vote_gametype_keeptwotime;
-float autocvar_sv_vote_gametype_default_current;
-float autocvar_sv_vote_limit;
+bool autocvar_sv_vote_gametype_default_current;
+int autocvar_sv_vote_limit;
float autocvar_sv_vote_majority_factor;
float autocvar_sv_vote_majority_factor_of_voted;
-float autocvar_sv_vote_master;
-float autocvar_sv_vote_master_callable;
+bool autocvar_sv_vote_master;
+bool autocvar_sv_vote_master_callable;
string autocvar_sv_vote_master_commands;
string autocvar_sv_vote_master_password;
-float autocvar_sv_vote_master_playerlimit;
-float autocvar_sv_vote_no_stops_vote;
-float autocvar_sv_vote_nospectators;
+int autocvar_sv_vote_master_playerlimit;
+bool autocvar_sv_vote_no_stops_vote;
+int autocvar_sv_vote_nospectators;
//string autocvar_sv_vote_only_commands;
-float autocvar_sv_vote_override_mostrecent;
-float autocvar_sv_vote_singlecount;
+bool autocvar_sv_vote_override_mostrecent;
+bool autocvar_sv_vote_singlecount;
float autocvar_sv_vote_stop;
float autocvar_sv_vote_timeout;
float autocvar_sv_vote_wait;
-float autocvar_sv_vote_gamestart;
-float autocvar_sv_warsowbunny_accel;
-float autocvar_sv_warsowbunny_airforwardaccel;
-float autocvar_sv_warsowbunny_backtosideratio;
-float autocvar_sv_warsowbunny_topspeed;
-float autocvar_sv_warsowbunny_turnaccel;
+bool autocvar_sv_vote_gamestart;
float autocvar_sv_waypointsprite_deadlifetime;
float autocvar_sv_waypointsprite_deployed_lifetime;
float autocvar_sv_waypointsprite_limitedrange;
string autocvar_sv_weaponstats_file;
float autocvar_sv_gibhealth;
float autocvar_sys_ticrate;
-float autocvar_teamplay_lockonrestart;
-float autocvar_teamplay_mode;
+bool autocvar_teamplay_lockonrestart;
+int autocvar_teamplay_mode;
#define autocvar_timelimit cvar("timelimit")
#define autocvar_timelimit_override cvar("timelimit_override")
float autocvar_timelimit_increment;
float autocvar_timelimit_min;
float autocvar_timelimit_max;
float autocvar_timelimit_overtime;
-float autocvar_timelimit_overtimes;
+int autocvar_timelimit_overtimes;
float autocvar_timelimit_suddendeath;
#define autocvar_utf8_enable cvar("utf8_enable")
-float autocvar_waypoint_benchmark;
+bool autocvar_waypoint_benchmark;
float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
+bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag;
float autocvar_g_trueaim_minrange;
-float autocvar_g_debug_defaultsounds;
+bool autocvar_g_debug_defaultsounds;
float autocvar_g_grab_range;
-float autocvar_g_sandbox_info;
-float autocvar_g_sandbox_readonly;
+int autocvar_g_sandbox_info;
+bool autocvar_g_sandbox_readonly;
string autocvar_g_sandbox_storage_name;
float autocvar_g_sandbox_storage_autosave;
-float autocvar_g_sandbox_storage_autoload;
+bool autocvar_g_sandbox_storage_autoload;
float autocvar_g_sandbox_editor_flood;
-float autocvar_g_sandbox_editor_maxobjects;
-float autocvar_g_sandbox_editor_free;
+int autocvar_g_sandbox_editor_maxobjects;
+int autocvar_g_sandbox_editor_free;
float autocvar_g_sandbox_editor_distance_spawn;
float autocvar_g_sandbox_editor_distance_edit;
float autocvar_g_sandbox_object_scale_min;
float autocvar_g_sandbox_object_scale_max;
float autocvar_g_sandbox_object_material_velocity_min;
float autocvar_g_sandbox_object_material_velocity_factor;
-float autocvar_g_max_info_autoscreenshot;
-float autocvar_physics_ode;
-float autocvar_g_physical_items;
+int autocvar_g_max_info_autoscreenshot;
+bool autocvar_physics_ode;
+int autocvar_g_physical_items;
float autocvar_g_physical_items_damageforcescale;
float autocvar_g_physical_items_reset;
float autocvar_g_monsters;
-float autocvar_g_monsters_edit;
-float autocvar_g_monsters_sounds;
+bool autocvar_g_monsters_edit;
+bool autocvar_g_monsters_sounds;
float autocvar_g_monsters_think_delay;
-float autocvar_g_monsters_max;
-float autocvar_g_monsters_max_perplayer;
+int autocvar_g_monsters_max;
+int autocvar_g_monsters_max_perplayer;
float autocvar_g_monsters_target_range;
-float autocvar_g_monsters_target_infront;
+bool autocvar_g_monsters_target_infront;
float autocvar_g_monsters_attack_range;
-float autocvar_g_monsters_score_kill;
-float autocvar_g_monsters_score_spawned;
-float autocvar_g_monsters_typefrag;
-float autocvar_g_monsters_owners;
+int autocvar_g_monsters_score_kill;
+int autocvar_g_monsters_score_spawned;
+bool autocvar_g_monsters_typefrag;
+bool autocvar_g_monsters_owners;
float autocvar_g_monsters_miniboss_chance;
float autocvar_g_monsters_miniboss_healthboost;
float autocvar_g_monsters_drop_time;
float autocvar_g_monsters_spawnshieldtime;
-float autocvar_g_monsters_teams;
+bool autocvar_g_monsters_teams;
float autocvar_g_monsters_respawn_delay;
-float autocvar_g_monsters_respawn;
+bool autocvar_g_monsters_respawn;
float autocvar_g_monsters_armor_blockpercent;
float autocvar_g_touchexplode_radius;
float autocvar_g_touchexplode_damage;
float autocvar_g_touchexplode_edgedamage;
float autocvar_g_touchexplode_force;
float autocvar_g_invasion_round_timelimit;
-float autocvar_g_invasion_teams;
-float autocvar_g_invasion_team_spawns;
+int autocvar_g_invasion_teams;
+bool autocvar_g_invasion_team_spawns;
float autocvar_g_invasion_spawnpoint_spawn_delay;
#define autocvar_g_invasion_point_limit cvar("g_invasion_point_limit")
float autocvar_g_invasion_warmup;
-float autocvar_g_invasion_monster_count;
-float autocvar_g_invasion_zombies_only;
+int autocvar_g_invasion_monster_count;
+bool autocvar_g_invasion_zombies_only;
float autocvar_g_invasion_spawn_delay;
#define autocvar_g_bloodloss cvar("g_bloodloss")
float autocvar_g_random_gravity_negative_chance;
float autocvar_g_random_gravity_positive;
float autocvar_g_random_gravity_negative;
float autocvar_g_random_gravity_delay;
-float autocvar_g_nades;
+bool autocvar_g_nades;
vector autocvar_g_nades_throw_offset;
-float autocvar_g_nades_spawn;
-float autocvar_g_nades_spawn_count;
-float autocvar_g_nades_client_select;
+bool autocvar_g_nades_spawn;
+int autocvar_g_nades_spawn_count;
+bool autocvar_g_nades_client_select;
float autocvar_g_nades_nade_lifetime;
float autocvar_g_nades_nade_minforce;
float autocvar_g_nades_nade_maxforce;
float autocvar_g_nades_nade_edgedamage;
float autocvar_g_nades_nade_radius;
float autocvar_g_nades_nade_force;
-float autocvar_g_nades_nade_newton_style;
+int autocvar_g_nades_nade_newton_style;
int autocvar_g_nades_napalm_ball_count;
float autocvar_g_nades_napalm_ball_spread;
float autocvar_g_nades_napalm_ball_damage;
float autocvar_g_nades_napalm_ball_damageforcescale;
float autocvar_g_nades_napalm_ball_lifetime;
float autocvar_g_nades_napalm_ball_radius;
-float autocvar_g_nades_napalm_blast;
+bool autocvar_g_nades_napalm_blast;
float autocvar_g_nades_napalm_fountain_lifetime;
float autocvar_g_nades_napalm_fountain_delay;
float autocvar_g_nades_napalm_fountain_radius;
float autocvar_g_nades_napalm_fountain_damage;
float autocvar_g_nades_napalm_fountain_edgedamage;
float autocvar_g_nades_napalm_burntime;
-float autocvar_g_nades_napalm_selfdamage;
-float autocvar_g_nades_nade_type;
-float autocvar_g_nades_bonus_type;
-float autocvar_g_nades_bonus;
-float autocvar_g_nades_bonus_onstrength;
-float autocvar_g_nades_bonus_client_select;
-float autocvar_g_nades_bonus_max;
-float autocvar_g_nades_bonus_score_max;
-float autocvar_g_nades_bonus_score_time;
-float autocvar_g_nades_bonus_score_time_flagcarrier;
-float autocvar_g_nades_bonus_score_minor;
-float autocvar_g_nades_bonus_score_low;
-float autocvar_g_nades_bonus_score_high;
-float autocvar_g_nades_bonus_score_medium;
-float autocvar_g_nades_bonus_score_spree;
+bool autocvar_g_nades_napalm_selfdamage;
+int autocvar_g_nades_nade_type;
+int autocvar_g_nades_bonus_type;
+bool autocvar_g_nades_bonus;
+bool autocvar_g_nades_bonus_onstrength;
+bool autocvar_g_nades_bonus_client_select;
+int autocvar_g_nades_bonus_max;
+int autocvar_g_nades_bonus_score_max;
+int autocvar_g_nades_bonus_score_time;
+int autocvar_g_nades_bonus_score_time_flagcarrier;
+int autocvar_g_nades_bonus_score_minor;
+int autocvar_g_nades_bonus_score_low;
+int autocvar_g_nades_bonus_score_high;
+int autocvar_g_nades_bonus_score_medium;
+int autocvar_g_nades_bonus_score_spree;
float autocvar_g_nades_ice_freeze_time;
float autocvar_g_nades_ice_health;
-float autocvar_g_nades_ice_explode;
-float autocvar_g_nades_ice_teamcheck;
+bool autocvar_g_nades_ice_explode;
+bool autocvar_g_nades_ice_teamcheck;
float autocvar_g_nades_heal_time;
float autocvar_g_nades_heal_rate;
float autocvar_g_nades_heal_friend;
float autocvar_g_campcheck_damage;
float autocvar_g_campcheck_distance;
float autocvar_g_campcheck_interval;
-float autocvar_g_jump_grunt;
-float autocvar_g_overkill_powerups_replace;
+bool autocvar_g_jump_grunt;
+bool autocvar_g_overkill_powerups_replace;
float autocvar_g_overkill_superguns_respawn_time;
-float autocvar_g_overkill_100h_anyway;
-float autocvar_g_overkill_100a_anyway;
-float autocvar_g_overkill_ammo_charge;
+bool autocvar_g_overkill_100h_anyway;
+bool autocvar_g_overkill_100a_anyway;
+bool autocvar_g_overkill_ammo_charge;
float autocvar_g_overkill_ammo_charge_notice;
float autocvar_g_overkill_ammo_charge_limit;
float autocvar_g_spawn_near_teammate_distance;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint;
+bool autocvar_g_spawn_near_teammate_ignore_spawnpoint;
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
+bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
+bool autocvar_g_physics_clientselect;
+string autocvar_g_physics_clientselect_options;
+string autocvar_g_physics_clientselect_default;
bool autocvar_g_buffs_effects;
float autocvar_g_buffs_waypoint_distance;
-float autocvar_g_buffs_randomize;
+bool autocvar_g_buffs_randomize;
float autocvar_g_buffs_random_lifetime;
-float autocvar_g_buffs_random_location;
-float autocvar_g_buffs_random_location_attempts;
-float autocvar_g_buffs_spawn_count;
-float autocvar_g_buffs_replace_powerups;
+bool autocvar_g_buffs_random_location;
+int autocvar_g_buffs_random_location_attempts;
+int autocvar_g_buffs_spawn_count;
+bool autocvar_g_buffs_replace_powerups;
float autocvar_g_buffs_cooldown_activate;
float autocvar_g_buffs_cooldown_respawn;
float autocvar_g_buffs_resistance_blockpercent;
float autocvar_g_buffs_inferno_damagemultiplier;
float autocvar_g_buffs_swapper_range;
float autocvar_g_buffs_magnet_range_item;
+float autocvar_sv_player_scale;
#endif
+#include "aim.qh"
+#include "../_all.qh"
+
+#include "bot.qh"
+
+#include "../mutators/mutators_include.qh"
// traces multiple trajectories to find one that will impact the target
// 'end' vector is the place it aims for,
* Functions
*/
+float lag_additem(float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4);
void lag_update();
void bot_lagfunc(float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4);
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/util_server.qh"
- #include "../../common/constants.qh"
- #include "../../common/teams.qh"
- #include "../../common/util.qh"
- #include "../../common/weapons/weapons.qh"
- #include "../weapons/accuracy.qh"
- #include "../t_items.qh"
- #include "../autocvars.qh"
- #include "../constants.qh"
- #include "../defs.qh"
- #include "../mutators/mutators_include.qh"
- #include "../campaign.qh"
- #include "../../common/mapinfo.qh"
- #include "../../csqcmodellib/sv_model.qh"
- #include "../antilag.qh"
-#endif
-
#include "bot.qh"
+#include "../_all.qh"
+
#include "aim.qh"
#include "navigation.qh"
+#include "scripting.qh"
#include "waypoints.qh"
-#include "aim.qc"
-#include "navigation.qc"
-#include "waypoints.qc"
-#include "scripting.qc"
+#include "havocbot/havocbot.qh"
+#include "havocbot/scripting.qh"
+
+#include "../antilag.qh"
+#include "../autocvars.qh"
+#include "../campaign.qh"
+#include "../cl_client.qh"
+#include "../constants.qh"
+#include "../defs.qh"
+#include "../race.qh"
+#include "../t_items.qh"
+
+#include "../mutators/mutators_include.qh"
+
+#include "../weapons/accuracy.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/mapinfo.qh"
+#include "../../common/teams.qh"
+#include "../../common/util.qh"
+
+#include "../../common/weapons/all.qh"
+
+#include "../../csqcmodellib/sv_model.qh"
+
+#include "../../dpdefs/dpextensions.qh"
+#include "../../dpdefs/progsdefs.qh"
-#include "havocbot/havocbot.qc"
+#include "../../warpzonelib/common.qh"
+#include "../../warpzonelib/util_server.qh"
entity bot_spawn()
{
*/
entity bot_spawn();
+float bot_fixcount();
void bot_think();
void bot_setnameandstuff();
#include "havocbot.qh"
-#include "role_onslaught.qc"
-#include "role_keyhunt.qc"
-#include "roles.qc"
+#include "../../_all.qh"
+
+#include "../aim.qh"
+#include "../bot.qh"
+#include "../navigation.qh"
+#include "../scripting.qh"
+#include "../waypoints.qh"
+
+#include "../../../common/constants.qh"
+
+#include "../../../common/triggers/trigger/jumppads.qh"
+
+#include "../../../warpzonelib/common.qh"
void havocbot_ai()
{
// if the bot is not attacking, consider reloading weapons
if (!(self.aistatus & AI_STATUS_ATTACKING))
{
- float i;
- entity e;
-
// 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(self.clip_load < self.clip_size)
if(skill >= 5) // bots can only look for unloaded weapons past this skill
if(self.clip_load >= 0) // only if we're not reloading a weapon already
{
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ for (int i = WEP_FIRST; i <= WEP_LAST; ++i)
{
- e = get_weaponinfo(i);
+ entity e = get_weaponinfo(i);
if ((self.weapons & WepSet_FromWeapon(i)) && (e.spawnflags & WEP_FLAG_RELOADABLE) && (self.weapon_load[i] < e.reloading_ammo))
self.switchweapon = i;
}
// Flying
self.BUTTON_HOOK = true;
- if(self.navigation_jetpack_point.z - PL_MAX_z + PL_MIN_z < self.origin.z)
+ if(self.navigation_jetpack_point.z - PL_MAX.z + PL_MIN.z < self.origin.z)
{
self.movement_x = dir * v_forward * maxspeed;
self.movement_y = dir * v_right * maxspeed;
+#include "role_keyhunt.qh"
+#include "../../_all.qh"
+
+#include "havocbot.qh"
+
+#include "../bot.qh"
+#include "../navigation.qh"
+
+#include "../../mutators/mutators_include.qh"
+
void() havocbot_role_kh_carrier;
void() havocbot_role_kh_defense;
void() havocbot_role_kh_offense;
void() havocbot_role_kh_freelancer;
-entity kh_worldkeylist;
-.entity kh_worldkeynext;
void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
{
--- /dev/null
+#ifndef ROLE_KEYHUNT_H
+#define ROLE_KEYHUNT_H
+
+entity kh_worldkeylist;
+.entity kh_worldkeynext;
+
+void havocbot_chooserole_kh();
+#endif
+#include "../../_all.qh"
+
+#include "havocbot.qh"
+
+#include "../bot.qh"
+#include "../navigation.qh"
+#include "../waypoints.qh"
+
+#include "../../mutators/mutators_include.qh"
+
+#include "../../../common/teams.qh"
+
const int HAVOCBOT_ONS_ROLE_NONE = 0;
const int HAVOCBOT_ONS_ROLE_DEFENSE = 2;
const int HAVOCBOT_ONS_ROLE_ASSISTANT = 4;
--- /dev/null
+#ifndef ROLE_ONSLAUGHT_H
+#define ROLE_ONSLAUGHT_H
+void havocbot_chooserole_ons();
+#endif
+#include "../../_all.qh"
+
+#include "havocbot.qh"
+#include "role_keyhunt.qh"
+#include "role_onslaught.qh"
+
+#include "../bot.qh"
+#include "../navigation.qh"
.float max_armorvalue;
.float havocbot_role_timeout;
--- /dev/null
+#ifndef ROLES_H
+#define ROLES_H
+void havocbot_goalrating_controlpoints(float ratingscale, vector org, float sradius);
+#endif
--- /dev/null
+#ifndef HAVOCBOT_SCRIPTING_H
+#define HAVOCBOT_SCRIPTING_H
+
+void bot_clearqueue(entity bot);
+#endif
+#include "navigation.qh"
+#include "../_all.qh"
+
+#include "bot.qh"
+#include "waypoints.qh"
+
+#include "../t_items.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/triggers/trigger/jumppads.qh"
+
void bot_debug(string input)
{
switch(autocvar_bot_debug)
}
org = ent.origin + 0.5 * (ent.mins + ent.maxs);
- org.z = ent.origin.z + ent.mins.z - PL_MIN_z; // player height
+ org.z = ent.origin.z + ent.mins.z - PL_MIN.z; // player height
// TODO possibly make other code have the same support for bboxes
if(ent.tag_entity)
org = org + ent.tag_entity.origin;
float zdistance, xydistance, cost, t, fuel;
vector down, npa, npb;
- down = '0 0 -1' * (PL_MAX_z - PL_MIN_z) * 10;
+ down = '0 0 -1' * (PL_MAX.z - PL_MIN.z) * 10;
do{
npa = pointa + down;
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);
#endif
+#include "scripting.qh"
+#include "../_all.qh"
+
+#include "bot.qh"
+
.float bot_cmdqueuebuf_allocated;
.float bot_cmdqueuebuf;
.float bot_cmdqueuebuf_start;
}
-// 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(vector) cmd_moveto;
-.float() 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
-
// Initialize global commands list
// NOTE: New commands should be initialized here
void bot_commands_init()
// Commands code
.int bot_exec_status;
-#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
-
void SV_ParseClientCommand(string s);
float bot_cmd_cc()
{
void bot_resetqueues()
{
entity cl;
- float i;
FOR_EACH_CLIENT(cl) if(cl.isbot)
{
bot_clearqueue(cl);
// also, cancel all barriers
cl.bot_barrier = 0;
- for(i = 0; i < cl.bot_places_count; ++i)
+ for(int i = 0; i < cl.bot_places_count; ++i)
{
strunzone(cl.(bot_placenames[i]));
cl.(bot_placenames[i]) = string_null;
--- /dev/null
+#ifndef BOT_SCRIPTING_H
+#define BOT_SCRIPTING_H
+
+#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(vector) cmd_moveto;
+.float() 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 find_bot_by_name(string name);
+entity find_bot_by_number(float number);
+#endif
+#include "waypoints.qh"
+#include "../_all.qh"
+
+#include "bot.qh"
+#include "navigation.qh"
+
+#include "../antilag.qh"
+
+#include "../../common/constants.qh"
+
+#include "../../warpzonelib/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)
navigation_testtracewalk = 0;
if (!self.wpisbox)
{
- tracebox(sv - PL_MIN_z * '0 0 1', PL_MIN, PL_MAX, sv, false, self);
+ tracebox(sv - PL_MIN.z * '0 0 1', PL_MIN, PL_MAX, sv, false, self);
if (!trace_startsolid)
{
//dprint("sv deviation", vtos(trace_endpos - sv), "\n");
}
if (!e.wpisbox)
{
- tracebox(ev - PL_MIN_z * '0 0 1', PL_MIN, PL_MAX, ev, false, e);
+ tracebox(ev - PL_MIN.z * '0 0 1', PL_MIN, PL_MAX, ev, false, e);
if (!trace_startsolid)
{
//dprint("ev deviation", vtos(trace_endpos - ev), "\n");
vector waypoint_fixorigin(vector position)
{
- tracebox(position + '0 0 1' * (1 - PL_MIN_z), PL_MIN, PL_MAX, position + '0 0 -512', MOVE_NOMONSTERS, world);
+ tracebox(position + '0 0 1' * (1 - PL_MIN.z), PL_MIN, PL_MAX, position + '0 0 -512', MOVE_NOMONSTERS, world);
if(trace_fraction < 1)
position = trace_endpos;
//traceline(position, position + '0 0 -512', MOVE_NOMONSTERS, world);
w = find(w, classname, "waypoint");
}
- waypoint_schedulerelink(p.fld = waypoint_spawn(v, v, f));
+ waypoint_schedulerelink(p.(fld) = waypoint_spawn(v, v, f));
return 1;
}
if(navigation_waypoint_will_link(w.origin, porg, p, walkfromwp, 1050))
{
bestdist = d;
- p.fld = w;
+ p.(fld) = w;
}
}
w = find(w, classname, "waypoint");
}
if(bestdist < maxdist)
{
- print("update chain to new nearest WP ", etos(p.fld), "\n");
+ print("update chain to new nearest WP ", etos(p.(fld)), "\n");
return 0;
}
// we know maxdist < 2100
// so wp -> porg is still valid
// all is good
- p.fld = wp;
+ p.(fld) = wp;
return 0;
}
setorigin(p, save);
if(w)
{
- p.fld = w;
+ p.(fld) = w;
return 0;
}
}
.entity botframe_autowaypoints_lastwp0, botframe_autowaypoints_lastwp1;
void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld)
{
- float r;
- r = botframe_autowaypoints_fix_from(p, walkfromwp, p.fld, fld);
+ float r = botframe_autowaypoints_fix_from(p, walkfromwp, p.(fld), fld);
if(r != -1)
return;
r = botframe_autowaypoints_fix_from(p, walkfromwp, world, fld);
strunzone(title);
}
-string GetMapname();
void CampaignPostInit()
{
// now some sanity checks
#include "cheats.qh"
+#include "_all.qh"
+
#include "g_damage.qh"
#include "race.qh"
-#include "t_teleporters.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/anglestransform.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/monsters/monsters.qh"
- #include "../common/weapons/weapons.qh"
- #include "weapons/tracing.qh"
- #include "autocvars.qh"
- #include "defs.qh"
- #include "../common/deathtypes.qh"
- #include "mutators/mutators_include.qh"
- #include "../csqcmodellib/sv_model.qh"
-#endif
+#include "../common/triggers/teleporters.qh"
+
+#include "mutators/mutators_include.qh"
+
+#include "weapons/tracing.qh"
+
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/util.qh"
+
+#include "../common/monsters/all.qh"
+
+#include "../common/weapons/all.qh"
+
+#include "../common/triggers/subs.qh"
+
+#include "../common/triggers/func/breakable.qh"
+
+#include "../csqcmodellib/sv_model.qh"
+
+#include "../warpzonelib/anglestransform.qh"
+#include "../warpzonelib/util_server.qh"
void CopyBody(float keepvelocity);
.float maycheat;
float gamestart_sv_cheats;
-const float CHIMPULSE_SPEEDRUN_INIT = 30;
-const float CHIMPULSE_GIVE_ALL = 99;
-const float CHIMPULSE_CLONE_MOVING = 140;
-const float CHIMPULSE_SPEEDRUN = 141;
-const float CHIMPULSE_CLONE_STANDING = 142;
-const float CHIMPULSE_TELEPORT = 143;
-const float CHIMPULSE_R00T = 148;
-const float CHRAME_DRAG = 8;
void CheatInit()
{
float CheatCommand(float argc);
float CheatFrame();
+const float CHIMPULSE_SPEEDRUN_INIT = 30;
+const float CHIMPULSE_GIVE_ALL = 99;
+const float CHIMPULSE_CLONE_MOVING = 140;
+const float CHIMPULSE_SPEEDRUN = 141;
+const float CHIMPULSE_CLONE_STANDING = 142;
+const float CHIMPULSE_TELEPORT = 143;
+const float CHIMPULSE_R00T = 148;
+
+const float CHRAME_DRAG = 8;
+
void Drag_MoveDrag(entity from, entity to); // call this from CopyBody
#endif
+#include "cl_client.qh"
+
#include "waypointsprites.qh"
+#include "anticheat.qh"
#include "cl_impulse.qh"
#include "cl_player.qh"
#include "ent_cs.qh"
-#include "g_subs.qh"
#include "ipban.qh"
#include "miscfunctions.qh"
#include "portals.qh"
#include "teamplay.qh"
#include "playerdemo.qh"
-#include "secret.qh"
+#include "spawnpoints.qh"
+#include "g_damage.qh"
+#include "g_hook.qh"
+#include "command/common.qh"
+#include "cheats.qh"
+#include "g_world.qh"
+#include "race.qh"
+#include "antilag.qh"
+#include "campaign.qh"
+#include "command/common.qh"
#include "bot/bot.qh"
#include "bot/navigation.qh"
+#include "vehicles/vehicle.qh"
+
#include "weapons/hitplot.qh"
#include "weapons/weaponsystem.qh"
#include "../common/net_notice.qh"
+#include "../common/physics.qh"
+
+#include "../common/triggers/subs.qh"
+#include "../common/triggers/triggers.qh"
+#include "../common/triggers/trigger/secret.qh"
+
+#include "../common/items/inventory.qh"
#include "../common/monsters/sv_monsters.qh"
#include "../warpzonelib/server.qh"
-float c1, c2, c3, c4;
void send_CSQC_teamnagger() {
WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
defaultskin = 0;
chmdl = false;
- if(autocvar_sv_defaultcharacter == 1)
+ if(autocvar_sv_defaultcharacter)
{
if(teamplay)
{
if(IS_PLAYER(self))
{
entity spot, oldself;
- float j;
accuracy_resend(self);
self.respawn_flags = 0;
self.respawn_time = 0;
self.stat_respawn_time = 0;
- self.scale = 0;
+ self.scale = autocvar_sv_player_scale;
self.fade_time = 0;
self.pain_frame = 0;
self.pain_finished = 0;
target_voicescript_clear(self);
// reset fields the weapons may use
- for (j = WEP_FIRST; j <= WEP_LAST; ++j)
+ for (int j = WEP_FIRST; j <= WEP_LAST; ++j)
{
WEP_ACTION(j, WR_RESETPLAYER);
// all weapons must be fully loaded when we spawn
entity e = get_weaponinfo(j);
- if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
+ if (e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
self.(weapon_load[j]) = e.reloading_ammo;
}
.float ebouncefactor, ebouncestop; // electro's values
// TODO do we need all these fields, or should we stop autodetecting runtime
// changes and just have a console command to update this?
-float ClientInit_SendEntity(entity to, float sf)
+float ClientInit_SendEntity(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_INIT);
WriteByte(MSG_ENTITY, g_nexball_meter_period * 32);
PlayerScore_Attach(self);
ClientData_Attach();
accuracy_init(self);
+ Inventory_new(self);
bot_clientconnect();
bot_relinkplayerlist();
accuracy_free(self);
+ Inventory_delete(self);
ClientData_Detach();
PlayerScore_Detach(self);
void GetPressedKeys(void) {
MUTATOR_CALLHOOK(GetPressedKeys);
- if (self.movement.x > 0) // get if movement keys are pressed
- { // forward key pressed
- self.pressedkeys |= KEY_FORWARD;
- self.pressedkeys &= ~KEY_BACKWARD;
- }
- else if (self.movement.x < 0)
- { // backward key pressed
- self.pressedkeys |= KEY_BACKWARD;
- self.pressedkeys &= ~KEY_FORWARD;
- }
- else
- { // no x input
- self.pressedkeys &= ~KEY_FORWARD;
- self.pressedkeys &= ~KEY_BACKWARD;
- }
-
- if (self.movement.y > 0)
- { // right key pressed
- self.pressedkeys |= KEY_RIGHT;
- self.pressedkeys &= ~KEY_LEFT;
- }
- else if (self.movement.y < 0)
- { // left key pressed
- self.pressedkeys |= KEY_LEFT;
- self.pressedkeys &= ~KEY_RIGHT;
- }
- else
- { // no y input
- self.pressedkeys &= ~KEY_RIGHT;
- self.pressedkeys &= ~KEY_LEFT;
- }
-
- if (self.BUTTON_JUMP) // get if jump and crouch keys are pressed
- self.pressedkeys |= KEY_JUMP;
- else
- self.pressedkeys &= ~KEY_JUMP;
- if (self.BUTTON_CROUCH)
- self.pressedkeys |= KEY_CROUCH;
- else
- self.pressedkeys &= ~KEY_CROUCH;
-
- if (self.BUTTON_ATCK)
- self.pressedkeys |= KEY_ATCK;
- else
- self.pressedkeys &= ~KEY_ATCK;
- if (self.BUTTON_ATCK2)
- self.pressedkeys |= KEY_ATCK2;
- else
- self.pressedkeys &= ~KEY_ATCK2;
+ #define X(var,bit,flag) (flag ? var |= bit : var &= ~bit)
+ X(self.pressedkeys, KEY_FORWARD, self.movement_x > 0);
+ X(self.pressedkeys, KEY_BACKWARD, self.movement_x < 0);
+ X(self.pressedkeys, KEY_RIGHT, self.movement_y > 0);
+ X(self.pressedkeys, KEY_LEFT, self.movement_y < 0);
+
+ X(self.pressedkeys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(self));
+ X(self.pressedkeys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(self));
+ X(self.pressedkeys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(self));
+ X(self.pressedkeys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(self));
+ #undef X
}
/*
if (!self.crouch)
{
self.crouch = true;
- self.view_ofs = PL_CROUCH_VIEW_OFS;
- setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX);
+ self.view_ofs = self.stat_pl_crouch_view_ofs;
+ setsize (self, self.stat_pl_crouch_min, self.stat_pl_crouch_max);
// setanim(self, self.anim_duck, false, true, true); // this anim is BROKEN anyway
}
}
{
if (self.crouch)
{
- tracebox(self.origin, PL_MIN, PL_MAX, self.origin, false, self);
+ tracebox(self.origin, self.stat_pl_min, self.stat_pl_max, self.origin, false, self);
if (!trace_startsolid)
{
self.crouch = false;
- self.view_ofs = PL_VIEW_OFS;
- setsize (self, PL_MIN, PL_MAX);
+ self.view_ofs = self.stat_pl_view_ofs;
+ setsize (self, self.stat_pl_min, self.stat_pl_max);
}
}
}
--- /dev/null
+#ifndef CL_CLIENT_H
+#define CL_CLIENT_H
+float c1, c2, c3, c4;
+
+void play_countdown(float finished, string samp);
+
+float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit);
+
+float Spectate(entity pl);
+
+void CTS_ClientKill (entity e);
+
+#endif
+#include "_all.qh"
#include "round_handler.qh"
#include "bot/waypoints.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"
+#include "vehicles/vehicle.qh"
+#include "waypointsprites.qh"
-#include "../common/weapons/weapons.qh"
+#include "../common/weapons/all.qh"
/*
* Impulse map:
if(self.deadflag == DEAD_NO)
{
// custom order weapon cycling
- i = imp % 10;
+ int i = imp % 10;
m = (imp - (210 + i)); // <0 for prev, =0 for best, >0 for next
W_CycleWeapon(self.(cvar_cl_weaponpriorities[i]), m);
}
+++ /dev/null
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/mathlib.qh"
- #include "../warpzonelib/server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/animdecide.qh"
- #include "../common/monsters/sv_monsters.qh"
- #include "../common/weapons/weapons.qh"
- #include "t_items.qh"
- #include "autocvars.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "mutators/mutators_include.qh"
- #include "../common/mapinfo.qh"
- #include "../csqcmodellib/sv_model.qh"
- #include "anticheat.qh"
- #include "cheats.qh"
- #include "g_hook.qh"
- #include "race.qh"
- #include "playerdemo.qh"
-#endif
-
-.float race_penalty;
-.float restart_jump;
-
-.float ladder_time;
-.entity ladder_entity;
-.float gravity;
-.float swamp_slowdown;
-.int lastflags;
-.float lastground;
-.float wasFlying;
-.float spectatorspeed;
-
-/*
-=============
-PlayerJump
-
-When you press the jump key
-returns true if handled
-=============
-*/
-float PlayerJump (void)
-{
- if(self.frozen)
- return true; // no jumping in freezetag when frozen
-
- if(self.player_blocked)
- return true; // no jumping while blocked
-
- float doublejump = false;
- float mjumpheight = autocvar_sv_jumpvelocity;
-
- player_multijump = doublejump;
- player_jumpheight = mjumpheight;
- if(MUTATOR_CALLHOOK(PlayerJump))
- return true;
-
- doublejump = player_multijump;
- mjumpheight = player_jumpheight;
-
- if (autocvar_sv_doublejump)
- {
- tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
- if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
- {
- doublejump = true;
-
- // we MUST clip velocity here!
- float f;
- f = self.velocity * trace_plane_normal;
- if(f < 0)
- self.velocity -= f * trace_plane_normal;
- }
- }
-
- if (self.waterlevel >= WATERLEVEL_SWIMMING)
- {
- self.velocity_z = self.stat_sv_maxspeed * 0.7;
- return true;
- }
-
- if (!doublejump)
- if (!(self.flags & FL_ONGROUND))
- return !(self.flags & FL_JUMPRELEASED);
-
- if(self.cvar_cl_movement_track_canjump)
- if (!(self.flags & FL_JUMPRELEASED))
- return true;
-
- // sv_jumpspeedcap_min/sv_jumpspeedcap_max act as baseline
- // velocity bounds. Final velocity is bound between (jumpheight *
- // min + jumpheight) and (jumpheight * max + jumpheight);
-
- if(autocvar_sv_jumpspeedcap_min != "")
- {
- float minjumpspeed;
-
- minjumpspeed = mjumpheight * stof(autocvar_sv_jumpspeedcap_min);
-
- if (self.velocity.z < minjumpspeed)
- mjumpheight += minjumpspeed - self.velocity.z;
- }
-
- if(autocvar_sv_jumpspeedcap_max != "")
- {
- // don't do jump speedcaps on ramps to preserve old xonotic ramjump style
- tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
-
- if(!(trace_fraction < 1 && trace_plane_normal.z < 0.98 && autocvar_sv_jumpspeedcap_max_disable_on_ramps))
- {
- float maxjumpspeed;
-
- maxjumpspeed = mjumpheight * stof(autocvar_sv_jumpspeedcap_max);
-
- if (self.velocity.z > maxjumpspeed)
- mjumpheight -= self.velocity.z - maxjumpspeed;
- }
- }
-
- if(!(self.lastflags & FL_ONGROUND))
- {
- if(autocvar_speedmeter)
- dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
- if(self.lastground < time - 0.3)
- {
- self.velocity_x *= (1 - autocvar_sv_friction_on_land);
- self.velocity_y *= (1 - autocvar_sv_friction_on_land);
- }
- if(self.jumppadcount > 1)
- dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
- self.jumppadcount = 0;
- }
-
- self.velocity_z = self.velocity.z + mjumpheight;
- self.oldvelocity_z = self.velocity.z;
-
- self.flags &= ~FL_ONGROUND;
- self.flags &= ~FL_JUMPRELEASED;
-
- animdecide_setaction(self, ANIMACTION_JUMP, true);
-
- if(autocvar_g_jump_grunt)
- PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
-
- self.restart_jump = -1; // restart jump anim next time
- // value -1 is used to not use the teleport bit (workaround for tiny hitch when re-jumping)
- return true;
-}
-void CheckWaterJump()
-{
- vector start, end;
-
-// check for a jump-out-of-water
- makevectors (self.angles);
- start = self.origin;
- start.z = start.z + 8;
- v_forward.z = 0;
- normalize(v_forward);
- end = start + v_forward*24;
- traceline (start, end, true, self);
- if (trace_fraction < 1)
- { // solid at waist
- start.z = start.z + self.maxs.z - 8;
- end = start + v_forward*24;
- self.movedir = trace_plane_normal * -50;
- traceline (start, end, true, self);
- if (trace_fraction == 1)
- { // open at eye level
- self.flags |= FL_WATERJUMP;
- self.velocity_z = 225;
- self.flags &= ~FL_JUMPRELEASED;
- self.teleport_time = time + 2; // safety net
- return;
- }
- }
-}
-
-.float jetpack_stopped;
-// Hack: shouldn't need to know about this
-.float multijump_count;
-void CheckPlayerJump()
-{
- float was_flying = self.items & IT_USING_JETPACK;
-
- if (self.cvar_cl_jetpack_jump < 2)
- self.items &= ~IT_USING_JETPACK;
-
- if (self.BUTTON_JUMP || self.BUTTON_JETPACK)
- {
- float air_jump = !PlayerJump() || self.multijump_count > 0; // PlayerJump() has important side effects
- float activate = self.cvar_cl_jetpack_jump && air_jump && self.BUTTON_JUMP || self.BUTTON_JETPACK;
- float has_fuel = !autocvar_g_jetpack_fuel || self.ammo_fuel || self.items & IT_UNLIMITED_WEAPON_AMMO;
- if (!(self.items & IT_JETPACK)) { }
- else if (self.jetpack_stopped) { }
- else if (!has_fuel)
- {
- if (was_flying) // TODO: ran out of fuel message
- Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
- else if (activate)
- Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
- self.jetpack_stopped = true;
- self.items &= ~IT_USING_JETPACK;
- }
- else if (activate && !self.frozen)
- self.items |= IT_USING_JETPACK;
- }
- else
- {
- self.jetpack_stopped = false;
- self.items &= ~IT_USING_JETPACK;
- }
- if (!self.BUTTON_JUMP)
- self.flags |= FL_JUMPRELEASED;
-
- if (self.waterlevel == WATERLEVEL_SWIMMING)
- CheckWaterJump ();
-}
-
-float racecar_angle(float forward, float down)
-{
- float ret, angle_mult;
-
- if(forward < 0)
- {
- forward = -forward;
- down = -down;
- }
-
- ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
-
- angle_mult = forward / (800 + forward);
-
- if(ret > 180)
- return ret * angle_mult + 360 * (1 - angle_mult);
- else
- return ret * angle_mult;
-}
-
-void RaceCarPhysics()
-{
- // using this move type for "big rigs"
- // the engine does not push the entity!
-
- float accel, steer, f, myspeed, steerfactor;
- vector angles_save, rigvel;
-
- angles_save = self.angles;
- accel = bound(-1, self.movement.x / self.stat_sv_maxspeed, 1);
- steer = bound(-1, self.movement.y / self.stat_sv_maxspeed, 1);
-
- if(g_bugrigs_reverse_speeding)
- {
- if(accel < 0)
- {
- // back accel is DIGITAL
- // to prevent speedhack
- if(accel < -0.5)
- accel = -1;
- else
- accel = 0;
- }
- }
-
- self.angles_x = 0;
- self.angles_z = 0;
- makevectors(self.angles); // new forward direction!
-
- if(self.flags & FL_ONGROUND || g_bugrigs_air_steering)
- {
- float upspeed, accelfactor;
-
- myspeed = self.velocity * v_forward;
- upspeed = self.velocity * v_up;
-
- // responsiveness factor for steering and acceleration
- f = 1 / (1 + pow(max(-myspeed, myspeed) / g_bugrigs_speed_ref, g_bugrigs_speed_pow));
- //MAXIMA: f(v) := 1 / (1 + (v / g_bugrigs_speed_ref) ^ g_bugrigs_speed_pow);
-
- if(myspeed < 0 && g_bugrigs_reverse_spinning)
- steerfactor = -myspeed * g_bugrigs_steer;
- else
- steerfactor = -myspeed * f * g_bugrigs_steer;
-
- if(myspeed < 0 && g_bugrigs_reverse_speeding)
- accelfactor = g_bugrigs_accel;
- else
- accelfactor = f * g_bugrigs_accel;
- //MAXIMA: accel(v) := f(v) * g_bugrigs_accel;
-
- if(accel < 0)
- {
- if(myspeed > 0)
- {
- myspeed = max(0, myspeed - frametime * (g_bugrigs_friction_floor - g_bugrigs_friction_brake * accel));
- }
- else
- {
- if(!g_bugrigs_reverse_speeding)
- myspeed = min(0, myspeed + frametime * g_bugrigs_friction_floor);
- }
- }
- else
- {
- if(myspeed >= 0)
- {
- myspeed = max(0, myspeed - frametime * g_bugrigs_friction_floor);
- }
- else
- {
- if(g_bugrigs_reverse_stopping)
- myspeed = 0;
- else
- myspeed = min(0, myspeed + frametime * (g_bugrigs_friction_floor + g_bugrigs_friction_brake * accel));
- }
- }
- // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
- //MAXIMA: friction(v) := g_bugrigs_friction_floor;
-
- self.angles_y += steer * frametime * steerfactor; // apply steering
- makevectors(self.angles); // new forward direction!
-
- myspeed += accel * accelfactor * frametime;
-
- rigvel = myspeed * v_forward + '0 0 1' * upspeed;
- }
- else
- {
- myspeed = vlen(self.velocity);
-
- // responsiveness factor for steering and acceleration
- f = 1 / (1 + pow(max(0, myspeed / g_bugrigs_speed_ref), g_bugrigs_speed_pow));
- steerfactor = -myspeed * f;
- self.angles_y += steer * frametime * steerfactor; // apply steering
-
- rigvel = self.velocity;
- makevectors(self.angles); // new forward direction!
- }
-
- rigvel = rigvel * max(0, 1 - vlen(rigvel) * g_bugrigs_friction_air * frametime);
- //MAXIMA: airfriction(v) := v * v * g_bugrigs_friction_air;
- //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
- //MAXIMA: solve(total_acceleration(v) = 0, v);
-
- if(g_bugrigs_planar_movement)
- {
- vector rigvel_xy, neworigin, up;
- float mt;
-
- rigvel.z -= frametime * autocvar_sv_gravity; // 4x gravity plays better
- rigvel_xy = vec2(rigvel);
-
- if(g_bugrigs_planar_movement_car_jumping)
- mt = MOVE_NORMAL;
- else
- mt = MOVE_NOMONSTERS;
-
- tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 1024', mt, self);
- up = trace_endpos - self.origin;
-
- // BUG RIGS: align the move to the surface instead of doing collision testing
- // can we move?
- tracebox(trace_endpos, self.mins, self.maxs, trace_endpos + rigvel_xy * frametime, mt, self);
-
- // align to surface
- tracebox(trace_endpos, self.mins, self.maxs, trace_endpos - up + '0 0 1' * rigvel.z * frametime, mt, self);
-
- if(trace_fraction < 0.5)
- {
- trace_fraction = 1;
- neworigin = self.origin;
- }
- else
- neworigin = trace_endpos;
-
- if(trace_fraction < 1)
- {
- // now set angles_x so that the car points parallel to the surface
- self.angles = vectoangles(
- '1 0 0' * v_forward.x * trace_plane_normal.z
- +
- '0 1 0' * v_forward.y * trace_plane_normal.z
- +
- '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y)
- );
- self.flags |= FL_ONGROUND;
- }
- else
- {
- // now set angles_x so that the car points forward, but is tilted in velocity direction
- self.flags &= ~FL_ONGROUND;
- }
-
- self.velocity = (neworigin - self.origin) * (1.0 / frametime);
- self.movetype = MOVETYPE_NOCLIP;
- }
- else
- {
- rigvel.z -= frametime * autocvar_sv_gravity; // 4x gravity plays better
- self.velocity = rigvel;
- self.movetype = MOVETYPE_FLY;
- }
-
- trace_fraction = 1;
- tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 4', MOVE_NORMAL, self);
- if(trace_fraction != 1)
- {
- self.angles = vectoangles2(
- '1 0 0' * v_forward.x * trace_plane_normal.z
- +
- '0 1 0' * v_forward.y * trace_plane_normal.z
- +
- '0 0 1' * -(v_forward.x * trace_plane_normal.x + v_forward.y * trace_plane_normal.y),
- trace_plane_normal
- );
- }
- else
- {
- vector vel_local;
-
- vel_local.x = v_forward * self.velocity;
- vel_local.y = v_right * self.velocity;
- vel_local.z = v_up * self.velocity;
-
- self.angles_x = racecar_angle(vel_local.x, vel_local.z);
- self.angles_z = racecar_angle(-vel_local.y, vel_local.z);
- }
-
- // smooth the angles
- vector vf1, vu1, smoothangles;
- makevectors(self.angles);
- f = bound(0, frametime * g_bugrigs_angle_smoothing, 1);
- if(f == 0)
- f = 1;
- vf1 = v_forward * f;
- vu1 = v_up * f;
- makevectors(angles_save);
- vf1 = vf1 + v_forward * (1 - f);
- vu1 = vu1 + v_up * (1 - f);
- smoothangles = vectoangles2(vf1, vu1);
- self.angles_x = -smoothangles.x;
- self.angles_z = smoothangles.z;
-}
-
-float IsMoveInDirection(vector mv, float angle) // key mix factor
-{
- if(mv.x == 0 && mv.y == 0)
- return 0; // avoid division by zero
- angle -= RAD2DEG * atan2(mv.y, mv.x);
- angle = remainder(angle, 360) / 45;
- if(angle > 1)
- return 0;
- if(angle < -1)
- return 0;
- return 1 - fabs(angle);
-}
-
-float GeomLerp(float a, float lerp, float b)
-{
- if(a == 0)
- {
- if(lerp < 1)
- return 0;
- else
- return b;
- }
- if(b == 0)
- {
- if(lerp > 0)
- return 0;
- else
- return a;
- }
- return a * pow(fabs(b / a), lerp);
-}
-
-void CPM_PM_Aircontrol(vector wishdir, float wishspeed)
-{
- float zspeed, xyspeed, dot, k;
-
-#if 0
- // this doesn't play well with analog input
- if(self.movement_x == 0 || self.movement.y != 0)
- return; // can't control movement if not moving forward or backward
- k = 32;
-#else
- k = 32 * (2 * IsMoveInDirection(self.movement, 0) - 1);
- if(k <= 0)
- return;
-#endif
-
- k *= bound(0, wishspeed / autocvar_sv_maxairspeed, 1);
-
- zspeed = self.velocity.z;
- self.velocity_z = 0;
- xyspeed = vlen(self.velocity); self.velocity = normalize(self.velocity);
-
- dot = self.velocity * wishdir;
-
- if(dot > 0) // we can't change direction while slowing down
- {
- k *= pow(dot, autocvar_sv_aircontrol_power)*frametime;
- xyspeed = max(0, xyspeed - autocvar_sv_aircontrol_penalty * sqrt(max(0, 1 - dot*dot)) * k/32);
- k *= autocvar_sv_aircontrol;
- self.velocity = normalize(self.velocity * xyspeed + wishdir * k);
- }
-
- self.velocity = self.velocity * xyspeed;
- self.velocity_z = zspeed;
-}
-
-float AdjustAirAccelQW(float accelqw, float factor)
-{
- return copysign(bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1), accelqw);
-}
-
-// example config for alternate speed clamping:
-// sv_airaccel_qw 0.8
-// sv_airaccel_sideways_friction 0
-// prvm_globalset server speedclamp_mode 1
-// (or 2)
-void PM_Accelerate(vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit)
-{
- float vel_straight;
- float velZ;
- vector vel_perpend;
- float step;
-
- vector vel_xy;
- float vel_xy_current;
- float vel_xy_backward, vel_xy_forward;
- float speedclamp;
-
- if(stretchfactor > 0)
- speedclamp = stretchfactor;
- else if(accelqw < 0)
- speedclamp = 1; // full clamping, no stretch
- else
- speedclamp = -1; // no clamping
-
- if(accelqw < 0)
- accelqw = -accelqw;
-
- if(autocvar_sv_gameplayfix_q2airaccelerate)
- wishspeed0 = wishspeed;
-
- vel_straight = self.velocity * wishdir;
- velZ = self.velocity.z;
- vel_xy = vec2(self.velocity);
- vel_perpend = vel_xy - vel_straight * wishdir;
-
- step = accel * frametime * wishspeed0;
-
- vel_xy_current = vlen(vel_xy);
- if(speedlimit)
- accelqw = AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed));
- vel_xy_forward = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
- vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw);
- if(vel_xy_backward < 0)
- vel_xy_backward = 0; // not that it REALLY occurs that this would cause wrong behaviour afterwards
-
- vel_straight = vel_straight + bound(0, wishspeed - vel_straight, step) * accelqw + step * (1 - accelqw);
-
- 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, fminimum;
- f = max(0, 1 + frametime * wishspeed * sidefric);
- fminimum = (vel_xy_backward*vel_xy_backward - vel_straight*vel_straight) / (vel_perpend*vel_perpend);
- // this cannot be > 1
- if(fminimum <= 0)
- vel_perpend = vel_perpend * max(0, f);
- else
- {
- fminimum = sqrt(fminimum);
- vel_perpend = vel_perpend * max(fminimum, f);
- }
- }
- else
- vel_perpend = vel_perpend * max(0, 1 - frametime * wishspeed * sidefric);
-
- vel_xy = vel_straight * wishdir + vel_perpend;
-
- if(speedclamp >= 0)
- {
- float vel_xy_preclamp;
- vel_xy_preclamp = vlen(vel_xy);
- if(vel_xy_preclamp > 0) // prevent division by zero
- {
- vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp;
- if(vel_xy_current < vel_xy_preclamp)
- vel_xy = vel_xy * (vel_xy_current / vel_xy_preclamp);
- }
- }
-
- self.velocity = vel_xy + velZ * '0 0 1';
-}
-
-void PM_AirAccelerate(vector wishdir, float wishspeed)
-{
- vector curvel, wishvel, acceldir, curdir;
- float addspeed, accelspeed, curspeed, f;
- float dot;
-
- if(wishspeed == 0)
- return;
-
- curvel = self.velocity;
- curvel.z = 0;
- curspeed = vlen(curvel);
-
- if(wishspeed > curspeed * 1.01)
- {
- wishspeed = min(wishspeed, curspeed + autocvar_sv_warsowbunny_airforwardaccel * self.stat_sv_maxspeed * frametime);
- }
- else
- {
- f = max(0, (autocvar_sv_warsowbunny_topspeed - curspeed) / (autocvar_sv_warsowbunny_topspeed - self.stat_sv_maxspeed));
- wishspeed = max(curspeed, self.stat_sv_maxspeed) + autocvar_sv_warsowbunny_accel * f * self.stat_sv_maxspeed * frametime;
- }
- wishvel = wishdir * wishspeed;
- acceldir = wishvel - curvel;
- addspeed = vlen(acceldir);
- acceldir = normalize(acceldir);
-
- accelspeed = min(addspeed, autocvar_sv_warsowbunny_turnaccel * self.stat_sv_maxspeed * frametime);
-
- if(autocvar_sv_warsowbunny_backtosideratio < 1)
- {
- curdir = normalize(curvel);
- dot = acceldir * curdir;
- if(dot < 0)
- acceldir = acceldir - (1 - autocvar_sv_warsowbunny_backtosideratio) * dot * curdir;
- }
-
- self.velocity += accelspeed * acceldir;
-}
-
-.vector movement_old;
-.float buttons_old;
-.vector v_angle_old;
-.string lastclassname;
-
-.float() PlayerPhysplug;
-
-string specialcommand = "xwxwxsxsxaxdxaxdx1x ";
-.float specialcommand_pos;
-void SpecialCommand()
-{
-#ifdef TETRIS
- TetrisImpulse();
-#else
- if(!CheatImpulse(99))
- print("A hollow voice says \"Plugh\".\n");
-#endif
-}
-
-float speedaward_speed;
-string speedaward_holder;
-string speedaward_uid;
-void race_send_speedaward(float msg)
-{
- // send the best speed of the round
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
- WriteByte(msg, RACE_NET_SPEED_AWARD);
- WriteInt24_t(msg, floor(speedaward_speed+0.5));
- WriteString(msg, speedaward_holder);
-}
-
-float speedaward_alltimebest;
-string speedaward_alltimebest_holder;
-string speedaward_alltimebest_uid;
-void race_send_speedaward_alltimebest(float msg)
-{
- // send the best speed
- WriteByte(msg, SVC_TEMPENTITY);
- WriteByte(msg, TE_CSQC_RACE);
- WriteByte(msg, RACE_NET_SPEED_AWARD_BEST);
- WriteInt24_t(msg, floor(speedaward_alltimebest+0.5));
- WriteString(msg, speedaward_alltimebest_holder);
-}
-
-string GetMapname(void);
-float speedaward_lastupdate;
-float speedaward_lastsent;
-void SV_PlayerPhysics()
-{
- vector wishvel, wishdir, v;
- float wishspeed, f, maxspd_mod, spd, maxairspd, airaccel, swampspd_mod, buttons;
- string temps;
- int buttons_prev;
- float not_allowed_to_move;
- string c;
-
- WarpZone_PlayerPhysics_FixVAngle();
-
- maxspd_mod = 1;
- if(self.ballcarried)
- if(g_keepaway)
- maxspd_mod *= autocvar_g_keepaway_ballcarrier_highspeed;
-
- maxspd_mod *= autocvar_g_movement_highspeed;
-
- // fix physics stats for g_movement_highspeed
- // TODO maybe rather use maxairspeed? needs testing
- self.stat_sv_airaccel_qw = AdjustAirAccelQW(autocvar_sv_airaccel_qw, maxspd_mod);
- if(autocvar_sv_airstrafeaccel_qw)
- self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(autocvar_sv_airstrafeaccel_qw, maxspd_mod);
- else
- self.stat_sv_airstrafeaccel_qw = 0;
- self.stat_sv_airspeedlimit_nonqw = autocvar_sv_airspeedlimit_nonqw * maxspd_mod;
- self.stat_sv_maxspeed = autocvar_sv_maxspeed * maxspd_mod; // also slow walking
-
- if(self.PlayerPhysplug)
- if(self.PlayerPhysplug())
- return;
-
- self.race_movetime_frac += frametime;
- f = floor(self.race_movetime_frac);
- self.race_movetime_frac -= f;
- self.race_movetime_count += f;
- self.race_movetime = self.race_movetime_frac + self.race_movetime_count;
-
- anticheat_physics();
-
- buttons = self.BUTTON_ATCK + 2 * self.BUTTON_JUMP + 4 * self.BUTTON_ATCK2 + 8 * self.BUTTON_ZOOM + 16 * self.BUTTON_CROUCH + 32 * self.BUTTON_HOOK + 64 * self.BUTTON_USE + 128 * (self.movement.x < 0) + 256 * (self.movement.x > 0) + 512 * (self.movement.y < 0) + 1024 * (self.movement.y > 0);
-
- if(!buttons)
- c = "x";
- else if(buttons == 1)
- c = "1";
- else if(buttons == 2)
- c = " ";
- else if(buttons == 128)
- c = "s";
- else if(buttons == 256)
- c = "w";
- else if(buttons == 512)
- c = "a";
- else if(buttons == 1024)
- c = "d";
- else
- c = "?";
-
- if(c == substring(specialcommand, self.specialcommand_pos, 1))
- {
- self.specialcommand_pos += 1;
- if(self.specialcommand_pos >= strlen(specialcommand))
- {
- self.specialcommand_pos = 0;
- SpecialCommand();
- return;
- }
- }
- else if(self.specialcommand_pos && (c != substring(specialcommand, self.specialcommand_pos - 1, 1)))
- self.specialcommand_pos = 0;
-
- if(sv_maxidle > 0)
- {
- if(buttons != self.buttons_old || self.movement != self.movement_old || self.v_angle != self.v_angle_old)
- self.parm_idlesince = time;
- }
- buttons_prev = self.buttons_old;
- self.buttons_old = buttons;
- self.movement_old = self.movement;
- self.v_angle_old = self.v_angle;
-
- if(time < self.nickspamtime)
- if(self.nickspamcount >= autocvar_g_nick_flood_penalty_yellow)
- {
- // slight annoyance for nick change scripts
- self.movement = -1 * self.movement;
- self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = self.BUTTON_ZOOM = self.BUTTON_CROUCH = self.BUTTON_HOOK = self.BUTTON_USE = 0;
-
- if(self.nickspamcount >= autocvar_g_nick_flood_penalty_red) // if you are persistent and the slight annoyance above does not stop you, I'll show you!
- {
- self.angles_x = random() * 360;
- self.angles_y = random() * 360;
- // at least I'm not forcing retardedview by also assigning to angles_z
- self.fixangle = true;
- }
- }
-
- if (self.punchangle != '0 0 0')
- {
- f = vlen(self.punchangle) - 10 * frametime;
- if (f > 0)
- self.punchangle = normalize(self.punchangle) * f;
- else
- self.punchangle = '0 0 0';
- }
-
- if (self.punchvector != '0 0 0')
- {
- f = vlen(self.punchvector) - 30 * frametime;
- if (f > 0)
- self.punchvector = normalize(self.punchvector) * f;
- else
- self.punchvector = '0 0 0';
- }
-
- if (IS_BOT_CLIENT(self))
- {
- if(playerdemo_read())
- return;
- bot_think();
- }
-
- if(IS_PLAYER(self))
- {
- if(self.race_penalty)
- if(time > self.race_penalty)
- self.race_penalty = 0;
-
- not_allowed_to_move = 0;
- if(self.race_penalty)
- not_allowed_to_move = 1;
- if(time < game_starttime)
- not_allowed_to_move = 1;
-
- if(not_allowed_to_move)
- {
- self.velocity = '0 0 0';
- self.movetype = MOVETYPE_NONE;
- self.disableclientprediction = 2;
- }
- else if(self.disableclientprediction == 2)
- {
- if(self.movetype == MOVETYPE_NONE)
- self.movetype = MOVETYPE_WALK;
- self.disableclientprediction = 0;
- }
- }
-
- if (self.movetype == MOVETYPE_NONE)
- return;
-
- // when we get here, disableclientprediction cannot be 2
- self.disableclientprediction = 0;
- if(time < self.ladder_time)
- self.disableclientprediction = 1;
-
- if(time < self.spider_slowness)
- {
- self.stat_sv_maxspeed *= 0.5; // half speed while slow from spider
- self.stat_sv_airspeedlimit_nonqw *= 0.5;
- }
-
- if(self.frozen)
- {
- if(autocvar_sv_dodging_frozen && IS_REAL_CLIENT(self))
- {
- self.movement_x = bound(-5, self.movement.x, 5);
- self.movement_y = bound(-5, self.movement.y, 5);
- self.movement_z = bound(-5, self.movement.z, 5);
- }
- else
- self.movement = '0 0 0';
- self.disableclientprediction = 1;
-
- vector midpoint = ((self.absmin + self.absmax) * 0.5);
- if(pointcontents(midpoint) == CONTENT_WATER)
- {
- self.velocity = self.velocity * 0.5;
-
- if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
- { self.velocity_z = 200; }
- }
- }
-
- MUTATOR_CALLHOOK(PlayerPhysics);
-
- if(self.player_blocked)
- {
- self.movement = '0 0 0';
- self.disableclientprediction = 1;
- }
-
- maxspd_mod = 1;
-
- swampspd_mod = 1;
- if(self.in_swamp) {
- swampspd_mod = self.swamp_slowdown; //cvar("g_balance_swamp_moverate");
- }
-
- // conveyors: first fix velocity
- if(self.conveyor.state)
- self.velocity -= self.conveyor.movedir;
-
- if (!IS_PLAYER(self))
- {
- maxspd_mod = autocvar_sv_spectator_speed_multiplier;
- if(!self.spectatorspeed)
- self.spectatorspeed = maxspd_mod;
- if(self.impulse && self.impulse <= 19 || (self.impulse >= 200 && self.impulse <= 209) || (self.impulse >= 220 && self.impulse <= 229))
- {
- if(self.lastclassname != "player")
- {
- if(self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || (self.impulse >= 200 && self.impulse <= 209))
- self.spectatorspeed = bound(1, self.spectatorspeed + 0.5, 5);
- else if(self.impulse == 11)
- self.spectatorspeed = maxspd_mod;
- else if(self.impulse == 12 || self.impulse == 16 || self.impulse == 19 || (self.impulse >= 220 && self.impulse <= 229))
- self.spectatorspeed = bound(1, self.spectatorspeed - 0.5, 5);
- else if(self.impulse >= 1 && self.impulse <= 9)
- self.spectatorspeed = 1 + 0.5 * (self.impulse - 1);
- } // otherwise just clear
- self.impulse = 0;
- }
- maxspd_mod = self.spectatorspeed;
- }
-
- spd = max(self.stat_sv_maxspeed, autocvar_sv_maxairspeed) * maxspd_mod * swampspd_mod;
- if(self.speed != spd)
- {
- self.speed = spd;
- temps = ftos(spd);
- stuffcmd(self, strcat("cl_forwardspeed ", temps, "\n"));
- stuffcmd(self, strcat("cl_backspeed ", temps, "\n"));
- stuffcmd(self, strcat("cl_sidespeed ", temps, "\n"));
- stuffcmd(self, strcat("cl_upspeed ", temps, "\n"));
- }
-
- maxspd_mod *= swampspd_mod; // only one common speed modder please!
- swampspd_mod = 1;
-
- // if dead, behave differently
- if (self.deadflag)
- goto end;
-
- if (!self.fixangle && !g_bugrigs)
- {
- self.angles_x = 0;
- self.angles_y = self.v_angle.y;
- self.angles_z = 0;
- }
-
- if(self.flags & FL_ONGROUND)
- if(IS_PLAYER(self)) // no fall sounds for observers thank you very much
- if(self.wasFlying)
- {
- self.wasFlying = 0;
-
- if(self.waterlevel < WATERLEVEL_SWIMMING)
- if(time >= self.ladder_time)
- if (!self.hook)
- {
- self.nextstep = time + 0.3 + random() * 0.1;
- trace_dphitq3surfaceflags = 0;
- tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
- if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
- {
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
- GlobalSound(globalsound_metalfall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
- else
- GlobalSound(globalsound_fall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
- }
- }
- }
-
- if(IsFlying(self))
- self.wasFlying = 1;
-
- if(IS_PLAYER(self))
- CheckPlayerJump();
-
- if (self.flags & FL_WATERJUMP )
- {
- self.velocity_x = self.movedir.x;
- self.velocity_y = self.movedir.y;
- if (time > self.teleport_time || self.waterlevel == WATERLEVEL_NONE)
- {
- self.flags &= ~FL_WATERJUMP;
- self.teleport_time = 0;
- }
- }
- else if (g_bugrigs && IS_PLAYER(self))
- {
- RaceCarPhysics();
- }
- else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY)
- {
- // noclipping or flying
- self.flags &= ~FL_ONGROUND;
-
- self.velocity = self.velocity * (1 - frametime * autocvar_sv_friction);
- makevectors(self.v_angle);
- //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
- wishvel = v_forward * self.movement.x + v_right * self.movement.y + '0 0 1' * self.movement.z;
- // acceleration
- wishdir = normalize(wishvel);
- wishspeed = vlen(wishvel);
- if (wishspeed > self.stat_sv_maxspeed*maxspd_mod)
- wishspeed = self.stat_sv_maxspeed*maxspd_mod;
- if (time >= self.teleport_time)
- PM_Accelerate(wishdir, wishspeed, wishspeed, autocvar_sv_accelerate*maxspd_mod, 1, 0, 0, 0);
- }
- else if (self.waterlevel >= WATERLEVEL_SWIMMING)
- {
- // swimming
- self.flags &= ~FL_ONGROUND;
-
- makevectors(self.v_angle);
- //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
- wishvel = v_forward * self.movement.x + v_right * self.movement.y + '0 0 1' * self.movement.z;
- if (wishvel == '0 0 0')
- wishvel = '0 0 -60'; // drift towards bottom
-
- wishdir = normalize(wishvel);
- wishspeed = vlen(wishvel);
- if (wishspeed > self.stat_sv_maxspeed*maxspd_mod)
- wishspeed = self.stat_sv_maxspeed*maxspd_mod;
- wishspeed = wishspeed * 0.7;
-
- // water friction
- self.velocity = self.velocity * (1 - frametime * autocvar_sv_friction);
-
- // water acceleration
- PM_Accelerate(wishdir, wishspeed, wishspeed, autocvar_sv_accelerate*maxspd_mod, 1, 0, 0, 0);
- }
- else if (time < self.ladder_time)
- {
- // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water
- self.flags &= ~FL_ONGROUND;
-
- float g;
- g = autocvar_sv_gravity * frametime;
- if(self.gravity)
- g *= self.gravity;
- if(autocvar_sv_gameplayfix_gravityunaffectedbyticrate)
- {
- g *= 0.5;
- self.velocity_z += g;
- }
-
- self.velocity = self.velocity * (1 - frametime * autocvar_sv_friction);
- makevectors(self.v_angle);
- //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
- wishvel = v_forward * self.movement.x + v_right * self.movement.y + '0 0 1' * self.movement.z;
- self.velocity_z += g;
- if (self.ladder_entity.classname == "func_water")
- {
- f = vlen(wishvel);
- if (f > self.ladder_entity.speed)
- wishvel = wishvel * (self.ladder_entity.speed / f);
-
- self.watertype = self.ladder_entity.skin;
- f = self.ladder_entity.origin.z + self.ladder_entity.maxs.z;
- if ((self.origin.z + self.view_ofs.z) < f)
- self.waterlevel = WATERLEVEL_SUBMERGED;
- else if ((self.origin.z + (self.mins.z + self.maxs.z) * 0.5) < f)
- self.waterlevel = WATERLEVEL_SWIMMING;
- else if ((self.origin.z + self.mins.z + 1) < f)
- self.waterlevel = WATERLEVEL_WETFEET;
- else
- {
- self.waterlevel = WATERLEVEL_NONE;
- self.watertype = CONTENT_EMPTY;
- }
- }
- // acceleration
- wishdir = normalize(wishvel);
- wishspeed = vlen(wishvel);
- if (wishspeed > self.stat_sv_maxspeed*maxspd_mod)
- wishspeed = self.stat_sv_maxspeed*maxspd_mod;
- if (time >= self.teleport_time)
- {
- // water acceleration
- PM_Accelerate(wishdir, wishspeed, wishspeed, autocvar_sv_accelerate*maxspd_mod, 1, 0, 0, 0);
- }
- }
- else if (self.items & IT_USING_JETPACK)
- {
- //makevectors(self.v_angle_y * '0 1 0');
- makevectors(self.v_angle);
- wishvel = v_forward * self.movement.x + v_right * self.movement.y;
- // add remaining speed as Z component
- maxairspd = autocvar_sv_maxairspeed*max(1, maxspd_mod);
- // fix speedhacks :P
- wishvel = normalize(wishvel) * min(vlen(wishvel) / maxairspd, 1);
- // add the unused velocity as up component
- wishvel.z = 0;
-
- // if(self.BUTTON_JUMP)
- wishvel.z = sqrt(max(0, 1 - wishvel * wishvel));
-
- // it is now normalized, so...
- float a_side, a_up, a_add, a_diff;
- a_side = autocvar_g_jetpack_acceleration_side;
- a_up = autocvar_g_jetpack_acceleration_up;
- a_add = autocvar_g_jetpack_antigravity * autocvar_sv_gravity;
-
- wishvel.x *= a_side;
- wishvel.y *= a_side;
- wishvel.z *= a_up;
- wishvel.z += a_add;
-
- float best;
- best = 0;
- //////////////////////////////////////////////////////////////////////////////////////
- // finding the maximum over all vectors of above form
- // with wishvel having an absolute value of 1
- //////////////////////////////////////////////////////////////////////////////////////
- // we're finding the maximum over
- // f(a_side, a_up, a_add, z) := a_side * (1 - z^2) + (a_add + a_up * z)^2;
- // for z in the range from -1 to 1
- //////////////////////////////////////////////////////////////////////////////////////
- // maximum is EITHER attained at the single extreme point:
- a_diff = a_side * a_side - a_up * a_up;
- if(a_diff != 0)
- {
- f = a_add * a_up / a_diff; // this is the zero of diff(f(a_side, a_up, a_add, z), z)
- if(f > -1 && f < 1) // can it be attained?
- {
- best = (a_diff + a_add * a_add) * (a_diff + a_up * a_up) / a_diff;
- //print("middle\n");
- }
- }
- // OR attained at z = 1:
- f = (a_up + a_add) * (a_up + a_add);
- if(f > best)
- {
- best = f;
- //print("top\n");
- }
- // OR attained at z = -1:
- f = (a_up - a_add) * (a_up - a_add);
- if(f > best)
- {
- best = f;
- //print("bottom\n");
- }
- best = sqrt(best);
- //////////////////////////////////////////////////////////////////////////////////////
-
- //print("best possible acceleration: ", ftos(best), "\n");
-
- float fxy, fz;
- fxy = bound(0, 1 - (self.velocity * normalize(wishvel.x * '1 0 0' + wishvel.y * '0 1 0')) / autocvar_g_jetpack_maxspeed_side, 1);
- if(wishvel.z - autocvar_sv_gravity > 0)
- fz = bound(0, 1 - self.velocity.z / autocvar_g_jetpack_maxspeed_up, 1);
- else
- fz = bound(0, 1 + self.velocity.z / autocvar_g_jetpack_maxspeed_up, 1);
-
- wishvel.x *= fxy;
- wishvel.y *= fxy;
- wishvel.z = (wishvel.z - autocvar_sv_gravity) * fz + autocvar_sv_gravity;
-
- float fvel;
- fvel = min(1, vlen(wishvel) / best);
- if(autocvar_g_jetpack_fuel && !(self.items & IT_UNLIMITED_WEAPON_AMMO))
- f = min(1, self.ammo_fuel / (autocvar_g_jetpack_fuel * frametime * fvel));
- else
- f = 1;
-
- //print("this acceleration: ", ftos(vlen(wishvel) * f), "\n");
-
- if (f > 0 && wishvel != '0 0 0')
- {
- self.velocity = self.velocity + wishvel * f * frametime;
- if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
- self.ammo_fuel -= autocvar_g_jetpack_fuel * frametime * fvel * f;
- self.flags &= ~FL_ONGROUND;
- self.items |= IT_USING_JETPACK;
-
- // jetpack also inhibits health regeneration, but only for 1 second
- self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen);
- }
- }
- else if (self.flags & FL_ONGROUND)
- {
- // we get here if we ran out of ammo
- if((self.items & IT_JETPACK) && self.BUTTON_HOOK && !(buttons_prev & 32) && self.ammo_fuel < 0.01)
- Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
-
- // walking
- makevectors(self.v_angle.y * '0 1 0');
- wishvel = v_forward * self.movement.x + v_right * self.movement.y;
-
- if(!(self.lastflags & FL_ONGROUND))
- {
- if(autocvar_speedmeter)
- dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
- if(self.lastground < time - 0.3)
- self.velocity = self.velocity * (1 - autocvar_sv_friction_on_land);
- if(self.jumppadcount > 1)
- dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
- self.jumppadcount = 0;
- }
-
- v = self.velocity;
- v.z = 0;
- f = vlen(v);
- if(f > 0)
- {
- if (f < autocvar_sv_stopspeed)
- f = 1 - frametime * (autocvar_sv_stopspeed / f) * autocvar_sv_friction;
- else
- f = 1 - frametime * autocvar_sv_friction;
- if (f > 0)
- self.velocity = self.velocity * f;
- else
- self.velocity = '0 0 0';
- /*
- Mathematical analysis time!
-
- Our goal is to invert this mess.
-
- For the two cases we get:
- v = v0 * (1 - frametime * (autocvar_sv_stopspeed / v0) * autocvar_sv_friction)
- = v0 - frametime * autocvar_sv_stopspeed * autocvar_sv_friction
- v0 = v + frametime * autocvar_sv_stopspeed * autocvar_sv_friction
- and
- v = v0 * (1 - frametime * autocvar_sv_friction)
- v0 = v / (1 - frametime * autocvar_sv_friction)
-
- These cases would be chosen ONLY if:
- v0 < autocvar_sv_stopspeed
- v + frametime * autocvar_sv_stopspeed * autocvar_sv_friction < autocvar_sv_stopspeed
- v < autocvar_sv_stopspeed * (1 - frametime * autocvar_sv_friction)
- and, respectively:
- v0 >= autocvar_sv_stopspeed
- v / (1 - frametime * autocvar_sv_friction) >= autocvar_sv_stopspeed
- v >= autocvar_sv_stopspeed * (1 - frametime * autocvar_sv_friction)
- */
- }
-
- // acceleration
- wishdir = normalize(wishvel);
- wishspeed = vlen(wishvel);
- if (wishspeed > self.stat_sv_maxspeed*maxspd_mod)
- wishspeed = self.stat_sv_maxspeed*maxspd_mod;
- if (self.crouch)
- wishspeed = wishspeed * 0.5;
- if (time >= self.teleport_time)
- PM_Accelerate(wishdir, wishspeed, wishspeed, autocvar_sv_accelerate*maxspd_mod, 1, 0, 0, 0);
- }
- else
- {
- float wishspeed0;
- // we get here if we ran out of ammo
- if((self.items & IT_JETPACK) && self.BUTTON_HOOK && !(buttons_prev & 32) && self.ammo_fuel < 0.01)
- Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
-
- if(maxspd_mod < 1)
- {
- maxairspd = autocvar_sv_maxairspeed*maxspd_mod;
- airaccel = autocvar_sv_airaccelerate*maxspd_mod;
- }
- else
- {
- maxairspd = autocvar_sv_maxairspeed;
- airaccel = autocvar_sv_airaccelerate;
- }
- // airborn
- makevectors(self.v_angle.y * '0 1 0');
- wishvel = v_forward * self.movement.x + v_right * self.movement.y;
- // acceleration
- wishdir = normalize(wishvel);
- wishspeed = wishspeed0 = vlen(wishvel);
- if (wishspeed0 > self.stat_sv_maxspeed*maxspd_mod)
- wishspeed0 = self.stat_sv_maxspeed*maxspd_mod;
- if (wishspeed > maxairspd)
- wishspeed = maxairspd;
- if (self.crouch)
- wishspeed = wishspeed * 0.5;
- if (time >= self.teleport_time)
- {
- float accelerating;
- float wishspeed2;
- float airaccelqw;
- float strafity;
-
- airaccelqw = self.stat_sv_airaccel_qw;
- accelerating = (self.velocity * wishdir > 0);
- wishspeed2 = wishspeed;
-
- // CPM
- if(autocvar_sv_airstopaccelerate)
- {
- vector curdir;
- curdir = self.velocity;
- curdir.z = 0;
- curdir = normalize(curdir);
- airaccel = airaccel + (autocvar_sv_airstopaccelerate*maxspd_mod - airaccel) * max(0, -(curdir * wishdir));
- }
- // note that for straight forward jumping:
- // step = accel * frametime * 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)
- strafity = IsMoveInDirection(self.movement, -90) + IsMoveInDirection(self.movement, +90); // if one is nonzero, other is always zero
- if(autocvar_sv_maxairstrafespeed)
- wishspeed = min(wishspeed, GeomLerp(autocvar_sv_maxairspeed*maxspd_mod, strafity, autocvar_sv_maxairstrafespeed*maxspd_mod));
- if(autocvar_sv_airstrafeaccelerate)
- airaccel = GeomLerp(airaccel, strafity, autocvar_sv_airstrafeaccelerate*maxspd_mod);
- if(self.stat_sv_airstrafeaccel_qw)
- airaccelqw = copysign(1-GeomLerp(1-fabs(self.stat_sv_airaccel_qw), strafity, 1-fabs(self.stat_sv_airstrafeaccel_qw)), ((strafity > 0.5) ? self.stat_sv_airstrafeaccel_qw : self.stat_sv_airaccel_qw));
- // !CPM
-
- if(autocvar_sv_warsowbunny_turnaccel && accelerating && self.movement_y == 0 && self.movement.x != 0)
- PM_AirAccelerate(wishdir, wishspeed);
- else
- PM_Accelerate(wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, autocvar_sv_airaccel_qw_stretchfactor, autocvar_sv_airaccel_sideways_friction / maxairspd, self.stat_sv_airspeedlimit_nonqw);
-
- if(autocvar_sv_aircontrol)
- CPM_PM_Aircontrol(wishdir, wishspeed2);
- }
- }
-
- if((g_cts || g_race) && !IS_OBSERVER(self))
- {
- if(vlen(self.velocity - self.velocity.z * '0 0 1') > speedaward_speed)
- {
- speedaward_speed = vlen(self.velocity - self.velocity.z * '0 0 1');
- speedaward_holder = self.netname;
- speedaward_uid = self.crypto_idfp;
- speedaward_lastupdate = time;
- }
- if(speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
- {
- string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
- race_send_speedaward(MSG_ALL);
- speedaward_lastsent = speedaward_speed;
- if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
- {
- speedaward_alltimebest = speedaward_speed;
- speedaward_alltimebest_holder = speedaward_holder;
- speedaward_alltimebest_uid = speedaward_uid;
- db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
- db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
- race_send_speedaward_alltimebest(MSG_ALL);
- }
- }
- }
-
- // WEAPONTODO
- float xyspeed;
- xyspeed = vlen('1 0 0' * self.velocity.x + '0 1 0' * self.velocity.y);
- if(self.weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed))
- {
- // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed
- xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed));
- f = (xyspeed - WEP_CVAR(vortex, charge_minspeed)) / (WEP_CVAR(vortex, charge_maxspeed) - WEP_CVAR(vortex, charge_minspeed));
- // add the extra charge
- self.vortex_charge = min(1, self.vortex_charge + WEP_CVAR(vortex, charge_velocity_rate) * f * frametime);
- }
-:end
- if(self.flags & FL_ONGROUND)
- self.lastground = time;
-
- // conveyors: then break velocity again
- if(self.conveyor.state)
- self.velocity += self.conveyor.movedir;
-
- self.lastflags = self.flags;
- self.lastclassname = self.classname;
-}
#include "cl_player.qh"
-#include "g_triggers.qh"
+#include "_all.qh"
+
+#include "bot/bot.qh"
+#include "cheats.qh"
+#include "g_damage.qh"
+#include "g_subs.qh"
#include "g_violence.qh"
#include "miscfunctions.qh"
+#include "portals.qh"
+#include "teamplay.qh"
+#include "waypointsprites.qh"
+#include "weapons/throwing.qh"
+#include "command/common.qh"
+#include "../common/animdecide.qh"
+#include "../common/csqcmodel_settings.qh"
+#include "../common/deathtypes.qh"
+#include "../common/triggers/subs.qh"
+#include "../common/playerstats.qh"
+#include "../csqcmodellib/sv_model.qh"
#include "weapons/weaponstats.qh"
+#include "../common/animdecide.qh"
+
void CopyBody_Think(void)
{
if(self.CopyBody_nextthink && time > self.CopyBody_nextthink)
}
}
-void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
float take, save;
vector v;
flood = 2;
}
- if(time >= source.flood_field)
+ if (time >= source.(flood_field))
{
- source.flood_field = max(time - flood_burst * flood_spl, source.flood_field) + lines * flood_spl;
+ source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + lines * flood_spl;
}
else
{
}
else
{
- if(time >= source.flood_field)
- source.flood_field = max(time - flood_burst * flood_spl, source.flood_field) + flood_spl;
+ if (time >= source.(flood_field))
+ source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + flood_spl;
else
flood = 1;
}
if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
- source.flood_field = flood = 0;
+ source.(flood_field) = flood = 0;
}
if(flood == 2) // cannot happen for empty msgstr
}
else if(flood == 1)
{
- if(autocvar_g_chat_flood_notify_flooder)
+ if (autocvar_g_chat_flood_notify_flooder)
{
- sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.flood_field - time), "^3 seconds\n"));
+ sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.(flood_field) - time), "^3 seconds\n"));
ret = 0;
}
else
field = GetVoiceMessageSampleField(argv(0));
if(GetPlayerSoundSampleField_notFound)
continue;
- if(self.field)
- strunzone(self.field);
- self.field = strzone(strcat(argv(1), " ", argv(2)));
+ if (self.(field))
+ strunzone(self.(field));
+ self.(field) = strzone(strcat(argv(1), " ", argv(2)));
}
fclose(fh);
return 1;
void PlayerSound(.string samplefield, float chan, float voicetype)
{
- GlobalSound(self.samplefield, chan, voicetype);
+ GlobalSound(self.(samplefield), chan, voicetype);
}
void VoiceMessage(string type, string msg)
flood = Say(self, ownteam, world, msg, 1);
- if(IS_SPEC(self) || IS_OBSERVER(self) || flood < 0)
- FakeGlobalSound(self.sample, CH_VOICE, voicetype);
+ if (IS_SPEC(self) || IS_OBSERVER(self) || flood < 0)
+ FakeGlobalSound(self.(sample), CH_VOICE, voicetype);
else if (flood > 0)
- GlobalSound(self.sample, CH_VOICE, voicetype);
+ GlobalSound(self.(sample), CH_VOICE, voicetype);
}
void MoveToTeam(entity client, float team_colour, float type)
void player_anim (void);
-void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
+void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
// g_<gametype>_str:
// If 0, default is used.
--- /dev/null
+#include "../../common/command/all.qc"
+
+#include "sv_cmd.qc"
+
+#include "banning.qc"
+#include "cmd.qc"
+#include "common.qc"
+#include "getreplies.qc"
+#include "radarmap.qc"
+#include "vote.qc"
--- /dev/null
+#ifndef SERVER_COMMANDS_ALL_H
+#define SERVER_COMMANDS_ALL_H
+
+#include "../../common/command/commands.qh"
+
+#include "sv_cmd.qh"
+
+#include "banning.qh"
+#include "cmd.qh"
+#include "common.qh"
+#include "getreplies.qh"
+#include "radarmap.qh"
+#include "vote.qh"
+
+#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/util.qh"
- #include "../../common/command/shared_defs.qh"
- #include "../autocvars.qh"
- #include "common.qh"
- #include "banning.qh"
- #include "../ipban.qh"
-#endif
+#include "../../common/command/command.qh"
+#include "banning.qh"
+#include "../_all.qh"
+
+#include "common.qh"
+
+#include "../cl_player.qh"
+#include "../ipban.qh"
+
+#include "../../common/util.qh"
+
// =====================================================
// Banning and kicking command code, written by Samual
// Last updated: December 29th, 2011
// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
void BanCommand_macro_write_aliases(float fh);
+
+void BanCommand_macro_help();
+float BanCommand_macro_usage(float argc);
+
#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../common/constants.qh"
- #include "../../common/teams.qh"
- #include "../../common/util.qh"
- #include "../../common/command/shared_defs.qh"
- #include "../../common/monsters/monsters.qh"
- #include "../../common/monsters/sv_monsters.qh"
- #include "../../common/monsters/spawn.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
- #include "../../common/notifications.qh"
- #include "../../common/deathtypes.qh"
- #include "../mutators/mutators_include.qh"
- #include "../vehicles/vehicles_def.qh"
- #include "../campaign.qh"
- #include "../../common/mapinfo.qh"
- #include "common.qh"
- #include "vote.qh"
- #include "cmd.qh"
- #include "../cheats.qh"
- #include "../scores.qh"
- #include "../ipban.qh"
+#include "../../common/command/command.qh"
+#include "cmd.qh"
+#include "../_all.qh"
+
+#include "common.qh"
+#include "vote.qh"
+
+#include "../campaign.qh"
+#include "../cheats.qh"
+#include "../cl_player.qh"
+#include "../ipban.qh"
+#include "../mapvoting.qh"
+#include "../scores.qh"
+#include "../teamplay.qh"
+
+#include "../mutators/mutators_include.qh"
+
+#ifdef SVQC
+ #include "../vehicles/vehicle.qh"
#endif
+#include "../../common/constants.qh"
+#include "../../common/deathtypes.qh"
+#include "../../common/mapinfo.qh"
+#include "../../common/notifications.qh"
+#include "../../common/teams.qh"
+#include "../../common/util.qh"
+
+#include "../../common/monsters/all.qh"
+#include "../../common/monsters/spawn.qh"
+#include "../../common/monsters/sv_monsters.qh"
+
+#include "../../warpzonelib/common.qh"
+
+void ClientKill_TeamChange (float targetteam); // 0 = don't change, -1 = auto, -2 = spec
+
// =========================================================
// Server side networked commands code, reworked by Samual
// Last updated: December 28th, 2011
}
}
+void ClientCommand_physics(float request, float argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ string command = strtolower(argv(1));
+
+ if(!autocvar_g_physics_clientselect)
+ {
+ sprint(self, "Client physics selection is currently disabled.\n");
+ return;
+ }
+
+ if(command == "list" || command == "help")
+ {
+ sprint(self, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
+ return;
+ }
+
+ if(Physics_Valid(command) || command == "default")
+ {
+ stuffcmd(self, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
+ sprint(self, strcat("^2Physics set successfully changed to ^3", command, "\n"));
+ return;
+ }
+ }
+
+ default:
+ sprint(self, strcat("Current physics set: ^3", self.cvar_cl_physics, "\n"));
+ case CMD_REQUEST_USAGE:
+ {
+ sprint(self, "\nUsage:^3 cmd physics <physics>\n");
+ sprint(self, " See 'cmd physics list' for available physics sets.\n");
+ sprint(self, " Argument 'default' resets to standard physics.\n");
+ return;
+ }
+ }
+}
+
void ClientCommand_ready(float request) // todo: anti-spam for toggling readyness
{
switch(request)
CLIENT_COMMAND("mobedit", ClientCommand_mobedit(request, arguments), "Edit your monster's properties") \
CLIENT_COMMAND("mobkill", ClientCommand_mobkill(request), "Kills your monster") \
CLIENT_COMMAND("mobspawn", ClientCommand_mobspawn(request, arguments), "Spawn monsters infront of yourself") \
+ CLIENT_COMMAND("physics", ClientCommand_physics(request, arguments), "Change physics set") \
CLIENT_COMMAND("ready", ClientCommand_ready(request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
CLIENT_COMMAND("say", ClientCommand_say(request, arguments, command), "Print a message to chat to all players") \
CLIENT_COMMAND("say_team", ClientCommand_say_team(request, arguments, command), "Print a message to chat to all team mates") \
+#include "../../common/command/command.qh"
#include "common.qh"
+#include "../_all.qh"
+#include "../scores.qh"
+
+#include "../../common/notifications.qh"
#include "../../common/counting.qh"
#include "vote.qh"
#include "../../common/command/generic.qh"
-#include "../../common/command/shared_defs.qh"
+#include "../../common/command/command.qh"
// ============================================================
// Shared declarations for server commands, written by Samual
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/counting.qh"
- #include "../../common/monsters/monsters.qh"
- #include "../defs.qh"
- #include "../../common/mapinfo.qh"
- #include "getreplies.qh"
- #include "../race.qh"
-#endif
+#include "../../common/command/command.qh"
+#include "getreplies.qh"
+#include "../_all.qh"
+
+#include "../race.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/counting.qh"
+#include "../../common/mapinfo.qh"
+#include "../../common/util.qh"
+
+#include "../../common/monsters/all.qh"
// =========================================================
// Reply messages for common commands, re-worked by Samual
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/util.qh"
- #include "../defs.qh"
- #include "radarmap.qh"
- #include "../../csqcmodellib/sv_model.qh"
-#endif
+#include "../../common/command/command.qh"
+#include "radarmap.qh"
+#include "../_all.qh"
+
+#include "../g_world.qh"
+
+#include "../../common/util.qh"
+
+#include "../../csqcmodellib/sv_model.qh"
// ===============================================
// Generates radar map images for use in the HUD
{
sharpen_buffer[x + 2 * RADAR_WIDTH_MAX] = v;
}
-float sharpen_getpixel(float x, float y)
+float sharpen_getpixel(int x, int y)
{
if(x < 0)
return 0;
string doublehex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFFFF";
// FF is contained twice, to map 256 to FF too
// removes the need to bound()
+
+float RadarMap_Make(float argc);
+
+
#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/mathlib.qh"
- #include "../../common/constants.qh"
- #include "../../common/teams.qh"
- #include "../../common/util.qh"
- #include "../../common/command/shared_defs.qh"
- #include "../../common/monsters/sv_monsters.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
- #include "../../common/notifications.qh"
- #include "../mutators/mutators_include.qh"
- #include "../../common/mapinfo.qh"
- #include "common.qh"
- #include "cmd.qh"
- #include "sv_cmd.qh"
- #include "../anticheat.qh"
- #include "../playerdemo.qh"
-#endif
+#include "../../common/command/command.qh"
+#include "sv_cmd.qh"
+#include "../_all.qh"
+
+#include "banning.qh"
+#include "cmd.qh"
+#include "common.qh"
+#include "getreplies.qh"
+#include "radarmap.qh"
+
+#include "../anticheat.qh"
+#include "../campaign.qh"
+#include "../cl_client.qh"
+#include "../cl_player.qh"
+#include "../g_world.qh"
+#include "../ipban.qh"
+#include "../playerdemo.qh"
+#include "../teamplay.qh"
+
+#include "../bot/bot.qh"
+#include "../bot/navigation.qh"
+#include "../bot/scripting.qh"
+
+#include "../mutators/mutators_include.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/mapinfo.qh"
+#include "../../common/notifications.qh"
+#include "../../common/teams.qh"
+#include "../../common/util.qh"
+
+#include "../../common/monsters/sv_monsters.qh"
+
+#include "../../warpzonelib/mathlib.qh"
+
+void PutObserverInServer (void);
// =====================================================
// Server side game commands code, reworked by Samual
void changematchtime(float delta, float mi, float ma)
{
float cur;
- float new;
+ float update;
float lim;
if(delta == 0)
if(lim == 0)
return; // cannot increase any further
else if(lim < ma)
- new = min(ma, lim + delta);
+ update = min(ma, lim + delta);
else // already above maximum: FAIL
return;
}
else
{
if(lim == 0) // infinite: try reducing to max, if we are allowed to
- new = max(mi, ma);
+ update = max(mi, ma);
else if(lim > mi) // above minimum: decrease
- new = max(mi, lim + delta);
+ update = max(mi, lim + delta);
else // already below minimum: FAIL
return;
}
- cvar_set("timelimit", ftos(new / 60));
+ cvar_set("timelimit", ftos(update / 60));
}
{
entity tmp_player;
int i;
- float x, z, t_teams, t_players, team_color;
+ float x, t_teams, t_players, team_color;
// count the total amount of players and total amount of teams
t_players = 0;
t_teams = 0;
- FOR_EACH_PLAYER(tmp_player)
+ FOR_EACH_CLIENT(tmp_player)
+ if(IS_PLAYER(tmp_player) || tmp_player.caplayer)
{
CheckAllowedTeams(tmp_player);
}
// build a list of the players in a random order
- FOR_EACH_PLAYER(tmp_player)
+ FOR_EACH_CLIENT(tmp_player)
+ if(IS_PLAYER(tmp_player) || tmp_player.caplayer)
{
for (;;)
{
}
// finally, from the list made earlier, re-join the players in different order.
- for(i = 1; i <= t_teams; ++i)
+ for (int i = 1; i <= t_teams; ++i)
{
// find out how many players to assign to this team
x = (t_players / t_teams);
team_color = Team_NumberToTeam(i);
// sort through the random list of players made earlier
- for(z = 1; z <= maxclients; ++z)
+ for (int z = 1; z <= maxclients; ++z)
{
if (!(shuffleteams_teams[i] >= x))
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/command/shared_defs.qh"
- #include "../autocvars.qh"
- #include "../constants.qh"
- #include "../defs.qh"
- #include "../../common/notifications.qh"
- #include "../mutators/mutators_include.qh"
- #include "../../common/mapinfo.qh"
- #include "common.qh"
- #include "vote.qh"
- #include "../../common/playerstats.qh"
- #include "../scores.qh"
- #include "../race.qh"
- #include "../round_handler.qh"
-#endif
+#include "../../common/command/command.qh"
+#include "vote.qh"
+#include "../_all.qh"
+
+#include "common.qh"
+
+#include "../g_damage.qh"
+#include "../g_world.qh"
+#include "../race.qh"
+#include "../round_handler.qh"
+#include "../scores.qh"
+
+#include "../mutators/mutators_include.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/mapinfo.qh"
+#include "../../common/notifications.qh"
+#include "../../common/playerstats.qh"
+#include "../../common/util.qh"
// =============================================
// Server side voting code, reworked by Samual
nagger.SendFlags |= 1;
}
+// If the vote_caller is still here, return their name, otherwise vote_caller_name
+string OriginalCallerName()
+{
+ if (IS_REAL_CLIENT(vote_caller))
+ return vote_caller.netname;
+ return vote_caller_name;
+}
// =======================
// Game logic for voting
{
strunzone(vote_called_command);
strunzone(vote_called_display);
+ strunzone(vote_caller_name);
}
vote_called = VOTE_NULL;
vote_caller = world;
+ vote_caller_name = string_null;
vote_endtime = 0;
vote_called_command = string_null;
void VoteStop(entity stopper)
{
- bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", GetCallerName(vote_caller), "^2's vote\n");
+ bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", OriginalCallerName(), "^2's vote\n");
if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid))); }
// Don't force them to wait for next vote, this way they can e.g. correct their vote.
void VoteAccept()
{
- bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
+ bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
if((vote_called == VOTE_MASTER) && vote_caller)
vote_caller.vote_master = 1;
void VoteReject()
{
- bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 was rejected\n");
+ bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ", vote_called_display, "^2 was rejected\n");
VoteReset();
Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
}
void VoteTimeout()
{
- bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 timed out\n");
+ bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ", vote_called_display, "^2 timed out\n");
VoteReset();
Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
}
else // everything went okay, continue with calling the vote
{
vote_caller = caller; // remember who called the vote
+ vote_caller_name = strzone(GetCallerName(vote_caller));
vote_called = VOTE_NORMAL;
vote_called_command = strzone(vote_parsed_command);
vote_called_display = strzone(vote_parsed_display);
FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone
- bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote for ", vote_called_display, "\n");
+ bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote for ", vote_called_display, "\n");
if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
Nagger_VoteChanged();
VoteCount(true); // needed if you are the only one
else // everything went okay, continue with creating vote
{
vote_caller = caller;
+ vote_caller_name = strzone(GetCallerName(vote_caller));
vote_called = VOTE_MASTER;
vote_called_command = strzone("XXX");
vote_called_display = strzone("^3master");
caller.vote_selection = VOTE_SELECT_ACCEPT;
caller.vote_waittime = time + autocvar_sv_vote_wait;
- bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote to become ^3master^2.\n");
+ bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote to become ^3master^2.\n");
if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
Nagger_VoteChanged();
VoteCount(true); // needed if you are the only one
case CMD_REQUEST_COMMAND:
{
if(vote_called)
- print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", GetCallerName(vote_caller), "^7."));
+ print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", OriginalCallerName(), "^7."));
else
print_to(caller, "^1No vote called.");
// global vote information declarations
entity vote_caller; // original caller of the current vote
+string vote_caller_name; // name of the vote caller
float vote_called; // stores status of current vote (See VOTE_*)
float vote_endtime; // time when the vote is finished
float vote_accept_count; // total amount of players who accept the vote (counted by VoteCount() function)
.float ready; // flag for if a player is ready
void reset_map(float dorespawn);
void ReadyCount();
+void ReadyRestart_force();
#endif
const int ASSAULT_VALUE_INACTIVE = 1000;
-const int DOOR_NOSPLASH = 256; // generic anti-splashdamage spawnflag
#endif
--- /dev/null
+#ifndef CSQCEFFECTS_H
+#define CSQCEFFECTS_H
+void te_csqc_lightningarc(vector from,vector to);
+#endif
#ifndef SERVER_DEFS_H
#define SERVER_DEFS_H
-#include "../common/weapons/weapons.qh"
+#include "../common/weapons/all.qh"
#define INDEPENDENT_ATTACK_FINISHED
float sv_clones;
float sv_foginterval;
-entity activator;
-
float player_count;
float currentbots;
float bots_would_leave;
// Fields
-.void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage;
+.void(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) event_damage;
//.string wad;
//.string map;
//.float worldtype;
-.float delay;
-.float wait;
-.float lip;
-//.float light_lev;
-.float speed;
-//.float style;
-//.float skill;
-.float sounds;
-.string platmovetype;
-.float platmovetype_start, platmovetype_end;
-
-.string killtarget;
-
-.vector pos1, pos2;
-.vector mangle;
+// Needed for dynamic clientwalls
+.float inactive; // Clientwall disappears when inactive
+.float alpha_max, alpha_min;
+.float fade_start, fade_end, fade_vertical_offset;
+.float default_solid; // Variable to store default self.solid for clientwalls
.float pain_finished; //Added by Supajoe
.float pain_frame; //"
.float invincible_finished;
.float superweapons_finished;
-.vector finaldest, finalangle; //plat.qc stuff
-.void() think1;
-.float state;
-.float t_length, t_width;
-
-.vector destvec; // for rain
-.vector destvec2; // for train
-.float cnt; // for rain
+.float cnt; // used in too many places
.float count;
//.float cnt2;
.float fade_time;
.float fade_rate;
-// player animation state
-.float animstate_startframe;
-.float animstate_numframes;
-.float animstate_framerate;
-.float animstate_starttime;
-.float animstate_endtime;
-.float animstate_override;
-.float animstate_looping;
-
// weapon animation vectors:
.vector anim_fire1;
.vector anim_fire2;
void weapon_defaultspawnfunc(float wpn);
-.vector dest1, dest2;
-
float gameover;
float intermission_running;
float intermission_exittime;
float alreadychangedlevel;
-// Keys player is holding
-.float itemkeys;
-// message delay for func_door locked by keys and key locks
-// this field is used on player entities
-.float key_door_messagetime;
-
-
.float version;
-//swamp
-.float in_swamp; // bool
-.entity swampslug; // Uses this to release from swamp ("untouch" fix)
-
// footstep interval
.float nextstep;
.entity flagcarried;
-.float playerid;
+.int playerid;
float playerid_last;
.float noalign; // if set to 1, the item or spawnpoint won't be dropped to the floor
.float version_nagtime;
-const int NUM_JUMPPADSUSED = 3;
-.float jumppadcount;
-.entity jumppadsused[NUM_JUMPPADSUSED];
-
string gamemode_name;
float startitem_failed;
.entity killindicator;
.float killindicator_teamchange;
-void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
float lockteams;
.float Version;
.int SendFlags;
-.float(entity to, float sendflags) SendEntity;
+.bool(entity to, int sendflags) SendEntity;
// player sounds, voice messages
// TODO implemented fall and falling
.float stat_game_starttime;
.float stat_round_starttime;
-.float stat_sv_airaccel_qw;
-.float stat_sv_airstrafeaccel_qw;
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_maxspeed;
-
void W_Porto_Remove (entity p);
.int projectiledeathtype;
// may be useful to all weapons
.float bulletcounter;
-void target_voicescript_next(entity pl);
-void target_voicescript_clear(entity pl);
-
-.string target2;
-.string target3;
-.string target4;
-.string curvetarget;
-.float target_random;
-.float trigger_reverse;
-
// Nexball
.entity ballcarried; // Also used for keepaway
.float metertime;
.float stat_leadlimit;
-float radar_showennemies;
+bool radar_showennemies;
#ifdef PROFILING
float client_cefc_accumulator;
#endif
.float weapon_load[WEP_MAXCOUNT];
-.float ammo_none; // used by the reloading system, must always be 0
+.int ammo_none; // used by the reloading system, must always be 0
.float clip_load;
.float old_clip_load;
.float clip_size;
.float vortex_chargepool_ammo;
.float hagar_load;
-.float grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
+.int grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
#define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_CORPSE; (e).dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE
// when doing this, hagar can go through clones
typedef vector(entity player, entity spot, vector current) spawn_evalfunc_t;
.spawn_evalfunc_t spawn_evalfunc;
-.entity conveyor;
-
string modname;
.float missile_flags;
.float elos;
.float ranks;
+.string cvar_cl_physics;
+
.float init_for_player_needed;
.void(entity) init_for_player;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/constants.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "mutators/mutators_include.qh"
-#endif
+#include "_all.qh"
+
+#include "defs.qh"
+#include "mutators/mutators_include.qh"
/**
* The point of these entities is to avoid the problems
+++ /dev/null
-#include "weapons/common.qh"
-
-.entity sprite;
-
-.float dmg;
-.float dmg_edge;
-.float dmg_radius;
-.float dmg_force;
-.float debrismovetype;
-.float debrissolid;
-.vector debrisvelocity;
-.vector debrisvelocityjitter;
-.vector debrisavelocityjitter;
-.float debristime;
-.float debristimejitter;
-.float debrisfadetime;
-.float debrisdamageforcescale;
-.float debrisskin;
-
-.string mdl_dead; // or "" to hide when broken
-.string debris; // space separated list of debris models
-// other fields:
-// mdl = particle effect name
-// count = particle effect multiplier
-// targetname = target to trigger to unbreak the model
-// target = targets to trigger when broken
-// health = amount of damage it can take
-// spawnflags:
-// 1 = start disabled (needs to be triggered to activate)
-// 2 = indicate damage
-// notes:
-// for mdl_dead to work, origin must be set (using a common/origin brush).
-// Otherwise mdl_dead will be displayed at the map origin, and nobody would
-// want that!
-
-void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
-
-//
-// func_breakable
-// - basically func_assault_destructible for general gameplay use
-//
-void LaunchDebris (string debrisname, vector force)
-{
- entity dbr = spawn();
- setorigin(dbr, self.absmin
- + '1 0 0' * random() * (self.absmax.x - self.absmin.x)
- + '0 1 0' * random() * (self.absmax.y - self.absmin.y)
- + '0 0 1' * random() * (self.absmax.z - self.absmin.z));
- setmodel (dbr, debrisname );
- dbr.skin = self.debrisskin;
- dbr.colormap = self.colormap; // inherit team colors
- dbr.owner = self; // do not be affected by our own explosion
- dbr.movetype = self.debrismovetype;
- dbr.solid = self.debrissolid;
- if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
- setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
- dbr.velocity_x = self.debrisvelocity.x + self.debrisvelocityjitter.x * crandom();
- dbr.velocity_y = self.debrisvelocity.y + self.debrisvelocityjitter.y * crandom();
- dbr.velocity_z = self.debrisvelocity.z + self.debrisvelocityjitter.z * crandom();
- self.velocity = self.velocity + force * self.debrisdamageforcescale;
- dbr.avelocity_x = random()*self.debrisavelocityjitter.x;
- dbr.avelocity_y = random()*self.debrisavelocityjitter.y;
- dbr.avelocity_z = random()*self.debrisavelocityjitter.z;
- dbr.damageforcescale = self.debrisdamageforcescale;
- if(dbr.damageforcescale)
- dbr.takedamage = DAMAGE_YES;
- SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);
-}
-
-void func_breakable_colormod()
-{
- float h;
- if (!(self.spawnflags & 2))
- return;
- h = self.health / self.max_health;
- if(h < 0.25)
- self.colormod = '1 0 0';
- else if(h <= 0.75)
- self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
- else
- self.colormod = '1 1 1';
-
- CSQCMODEL_AUTOUPDATE();
-}
-
-void func_breakable_look_destroyed()
-{
- float floorZ;
-
- if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
- self.dropped_origin = self.origin;
-
- if(self.mdl_dead == "")
- self.effects |= EF_NODRAW;
- else {
- if (self.origin == '0 0 0') { // probably no origin brush, so don't spawn in the middle of the map..
- floorZ = self.absmin.z;
- setorigin(self,((self.absmax+self.absmin)*.5));
- self.origin_z = floorZ;
- }
- setmodel(self, self.mdl_dead);
- self.effects &= ~EF_NODRAW;
- }
-
- CSQCMODEL_AUTOUPDATE();
-
- self.solid = SOLID_NOT;
-}
-
-void func_breakable_look_restore()
-{
- setmodel(self, self.mdl);
- self.effects &= ~EF_NODRAW;
-
- if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
- setorigin(self, self.dropped_origin);
-
- CSQCMODEL_AUTOUPDATE();
-
- self.solid = SOLID_BSP;
-}
-
-void func_breakable_behave_destroyed()
-{
- self.health = self.max_health;
- self.takedamage = DAMAGE_NO;
- self.bot_attack = false;
- self.event_damage = func_null;
- self.state = 1;
- func_breakable_colormod();
- if (self.noise1)
- stopsound (self, CH_TRIGGER_SINGLE);
-}
-
-void func_breakable_behave_restore()
-{
- self.health = self.max_health;
- if(self.sprite)
- {
- WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
- WaypointSprite_UpdateHealth(self.sprite, self.health);
- }
- self.takedamage = DAMAGE_AIM;
- self.bot_attack = true;
- self.event_damage = func_breakable_damage;
- self.state = 0;
- self.nextthink = 0; // cancel auto respawn
- func_breakable_colormod();
- if (self.noise1)
- sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
-}
-
-void func_breakable_init_for_player(entity player)
-{
- if (self.noise1 && self.state == 0 && clienttype(player) == CLIENTTYPE_REAL)
- {
- msg_entity = player;
- soundto (MSG_ONE, self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
- }
-}
-
-void func_breakable_destroyed()
-{
- func_breakable_look_destroyed();
- func_breakable_behave_destroyed();
-
- CSQCMODEL_AUTOUPDATE();
-}
-
-void func_breakable_restore()
-{
- func_breakable_look_restore();
- func_breakable_behave_restore();
-
- CSQCMODEL_AUTOUPDATE();
-}
-
-vector debrisforce; // global, set before calling this
-void func_breakable_destroy() {
- float n, i;
- string oldmsg;
-
- activator = self.owner;
- self.owner = world; // set by W_PrepareExplosionByDamage
-
- // now throw around the debris
- n = tokenize_console(self.debris);
- for(i = 0; i < n; ++i)
- LaunchDebris(argv(i), debrisforce);
-
- func_breakable_destroyed();
-
- if(self.noise)
- sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
-
- if(self.dmg)
- RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
-
- if(self.cnt)
- pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
-
- if(self.respawntime)
- {
- self.think = func_breakable_restore;
- self.nextthink = time + self.respawntime + crandom() * self.respawntimejitter;
- }
-
- oldmsg = self.message;
- self.message = "";
- SUB_UseTargets();
- self.message = oldmsg;
-}
-
-void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{
- if(self.state == 1)
- return;
- if(self.spawnflags & DOOR_NOSPLASH)
- if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
- return;
- if(self.team)
- if(attacker.team == self.team)
- return;
- self.health = self.health - damage;
- if(self.sprite)
- {
- WaypointSprite_Ping(self.sprite);
- WaypointSprite_UpdateHealth(self.sprite, self.health);
- }
- func_breakable_colormod();
-
- if(self.health <= 0)
- {
- debrisforce = force;
- W_PrepareExplosionByDamage(attacker, func_breakable_destroy);
- }
-}
-
-void func_breakable_reset()
-{
- self.team = self.team_saved;
- func_breakable_look_restore();
- if(self.spawnflags & 1)
- func_breakable_behave_destroyed();
- else
- func_breakable_behave_restore();
-
- CSQCMODEL_AUTOUPDATE();
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-void spawnfunc_func_breakable() {
- float n, i;
- if(!self.health)
- self.health = 100;
- self.max_health = self.health;
-
- // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
- if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;
- if(!self.debrissolid) self.debrissolid = SOLID_NOT;
- if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';
- if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';
- if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';
- if(!self.debristime) self.debristime = 3.5;
- if(!self.debristimejitter) self.debristime = 2.5;
-
- if(self.mdl != "")
- self.cnt = particleeffectnum(self.mdl);
- if(self.count == 0)
- self.count = 1;
-
- if(self.message == "")
- self.message = "got too close to an explosion";
- if(self.message2 == "")
- self.message2 = "was pushed into an explosion by";
- if(!self.dmg_radius)
- self.dmg_radius = 150;
- if(!self.dmg_force)
- self.dmg_force = 200;
-
- self.mdl = self.model;
- SetBrushEntityModel();
-
- self.use = func_breakable_restore;
-
- // precache all the models
- if (self.mdl_dead)
- precache_model(self.mdl_dead);
- n = tokenize_console(self.debris);
- for(i = 0; i < n; ++i)
- precache_model(argv(i));
- if(self.noise)
- precache_sound(self.noise);
- if(self.noise1)
- precache_sound(self.noise1);
-
- self.team_saved = self.team;
- self.dropped_origin = self.origin;
-
- self.reset = func_breakable_reset;
- func_breakable_reset();
-
- self.init_for_player_needed = 1;
- self.init_for_player = func_breakable_init_for_player;
-
- CSQCMODEL_AUTOINIT();
-}
-
-// for use in maps with a "model" key set
-void spawnfunc_misc_breakablemodel() {
- spawnfunc_func_breakable();
-}
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "constants.qh"
- #include "defs.qh"
-#endif
+#include "_all.qh"
-float Casing_SendEntity(entity to, float sf)
+#include "../common/util.qh"
+
+float Casing_SendEntity(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_CASING);
WriteByte(MSG_ENTITY, self.state); // actually type
#include "g_damage.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../warpzonelib/common.qh"
- #include "../common/constants.qh"
- #include "../common/buffs.qh"
- #include "../common/teams.qh"
- #include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
- #include "weapons/accuracy.qh"
- #include "weapons/csqcprojectile.qh"
- #include "weapons/selection.qh"
- #include "t_items.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "../common/deathtypes.qh"
- #include "mutators/mutators_include.qh"
- #include "tturrets/include/turrets_early.qh"
- #include "vehicles/vehicles_def.qh"
- #include "../csqcmodellib/sv_model.qh"
- #include "../common/playerstats.qh"
- #include "g_hook.qh"
- #include "scores.qh"
- #include "spawnpoints.qh"
-#endif
-
-float Damage_DamageInfo_SendEntity(entity to, float sf)
+#include "_all.qh"
+
+#include "g_hook.qh"
+#include "mutators/mutators_include.qh"
+#include "scores.qh"
+#include "waypointsprites.qh"
+#include "spawnpoints.qh"
+#include "tturrets/include/turrets_early.qh"
+#include "t_items.qh"
+#include "vehicles/vehicle.qh"
+#include "weapons/accuracy.qh"
+#include "weapons/csqcprojectile.qh"
+#include "weapons/selection.qh"
+#include "../common/buffs.qh"
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/notifications.qh"
+#include "../common/movetypes/movetypes.qh"
+#include "../common/playerstats.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
+#include "../common/weapons/all.qh"
+#include "../csqcmodellib/sv_model.qh"
+#include "../warpzonelib/common.qh"
+
+float Damage_DamageInfo_SendEntity(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
WriteShort(MSG_ENTITY, self.projectiledeathtype);
return true;
}
-void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, float deathtype, float bloodtype, entity dmgowner)
+void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner)
{
// TODO maybe call this from non-edgedamage too?
// TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info?
Net_LinkEntity(e, false, 0.2, Damage_DamageInfo_SendEntity);
}
-float IsFlying(entity a)
-{
- if(a.flags & FL_ONGROUND)
- return 0;
- if(a.waterlevel >= WATERLEVEL_SWIMMING)
- return 0;
- traceline(a.origin, a.origin - '0 0 48', MOVE_NORMAL, a);
- if(trace_fraction < 1)
- return 0;
- return 1;
-}
-
void UpdateFrags(entity player, float f)
{
PlayerTeamScore_AddScore(player, f);
}
-void GiveFrags (entity attacker, entity targ, float f, float deathtype)
+void GiveFrags (entity attacker, entity targ, float f, int deathtype)
{
// TODO route through PlayerScores instead
if(gameover) return;
return s;
}
-void LogDeath(string mode, float deathtype, entity killer, entity killed)
+void LogDeath(string mode, int deathtype, entity killer, entity killed)
{
string s;
if(!autocvar_sv_eventlog)
void Obituary_SpecialDeath(
entity notif_target,
float murder,
- float deathtype,
+ int deathtype,
string s1, string s2, string s3,
float f1, float f2, float f3)
{
float Obituary_WeaponDeath(
entity notif_target,
float murder,
- float deathtype,
+ int deathtype,
string s1, string s2, string s3,
float f1, float f2)
{
if(death_weapon)
{
w_deathtype = deathtype;
- float death_message = WEP_ACTION(death_weapon, ((murder) ? WR_KILLMESSAGE : WR_SUICIDEMESSAGE));
+ int death_message = WEP_ACTION(death_weapon, ((murder) ? WR_KILLMESSAGE : WR_SUICIDEMESSAGE));
w_deathtype = false;
- if(death_message)
+ if (death_message)
{
Send_Notification_WOCOVA(
NOTIF_ONE,
return false;
}
-void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
+void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
{
// Sanity check
if (!IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; }
targ.iceblock = world;
}
-void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
float mirrordamage;
float mirrorforce;
farcent.think = SUB_Remove;
}
else
+ {
self.velocity = self.velocity + farce;
+ self.move_velocity = self.velocity;
+ }
self.flags &= ~FL_ONGROUND;
+ self.move_flags &= ~FL_ONGROUND;
UpdateCSQCProjectile(self);
}
// apply damage
}
}
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float deathtype, entity directhitentity)
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, int deathtype, entity directhitentity)
// Returns total damage applies to creatures
{
entity targ;
return total_damage_to_creatures;
}
-float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, float deathtype, entity directhitentity)
+float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, entity directhitentity)
{
return RadiusDamageForSource (inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, directhitentity);
}
#include "../common/constants.qh"
#include "../common/teams.qh"
#include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
+ #include "../common/weapons/all.qh"
#include "weapons/accuracy.qh"
#include "weapons/csqcprojectile.qh"
#include "weapons/selection.qh"
#include "../common/deathtypes.qh"
#include "mutators/mutators_include.qh"
#include "tturrets/include/turrets_early.qh"
- #include "vehicles/vehicles_def.qh"
+ #include "vehicles/vehicle.qh"
#include "../csqcmodellib/sv_model.qh"
#include "../common/playerstats.qh"
#include "g_hook.qh"
.float dmg_force;
.float dmg_radius;
-float Damage_DamageInfo_SendEntity(entity to, float sf);
+float Damage_DamageInfo_SendEntity(entity to, int sf);
-void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, float deathtype, float bloodtype, entity dmgowner);
+void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner);
float checkrules_firstblood;
// NOTE: f=0 means still count as a (positive) kill, but count no frags for it
void W_SwitchWeapon_Force(entity e, float w);
entity GiveFrags_randomweapons;
-void GiveFrags (entity attacker, entity targ, float f, float deathtype);
+void GiveFrags (entity attacker, entity targ, float f, int deathtype);
string AppendItemcodes(string s, entity player);
-void LogDeath(string mode, float deathtype, entity killer, entity killed);
+void LogDeath(string mode, int deathtype, entity killer, entity killed);
void Obituary_SpecialDeath(
entity notif_target,
float murder,
- float deathtype,
+ int deathtype,
string s1, string s2, string s3,
float f1, float f2, float f3);
float Obituary_WeaponDeath(
entity notif_target,
float murder,
- float deathtype,
+ int deathtype,
string s1, string s2, string s3,
float f1, float f2);
-void Obituary(entity attacker, entity inflictor, entity targ, float deathtype);
+void Obituary(entity attacker, entity inflictor, entity targ, int deathtype);
void Ice_Think();
entity damage_inflictor;
entity damage_attacker;
-void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
float RadiusDamage_running;
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float deathtype, entity directhitentity);
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, int deathtype, entity directhitentity);
// Returns total damage applies to creatures
-float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, float deathtype, entity directhitentity);
+float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, entity directhitentity);
.float fire_damagepersec;
.float fire_endtime;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/common.qh"
- #include "../warpzonelib/server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "vehicles/vehicles_def.qh"
- #include "command/common.qh"
- #include "g_hook.qh"
- #include "round_handler.qh"
-#endif
+#include "g_hook.qh"
+#include "_all.qh"
+
+#include "weapons/common.qh"
+#include "weapons/weaponsystem.qh"
+#include "weapons/selection.qh"
+#include "weapons/tracing.qh"
+#include "cl_player.qh"
+#include "command/common.qh"
+#include "round_handler.qh"
+#include "vehicles/vehicle.qh"
+#include "../common/constants.qh"
+#include "../common/util.qh"
+#include "../common/weapons/all.qh"
+#include "../warpzonelib/common.qh"
+#include "../warpzonelib/server.qh"
/*============================================
}
.vector hook_start, hook_end;
-float GrapplingHookSend(entity to, float sf)
+float GrapplingHookSend(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_HOOK);
sf = sf & 0x7F;
void GrapplingHookThink()
{
- float spd, dist, minlength, pullspeed, ropestretch, ropeairfriction, rubberforce, newlength, rubberforce_overstretch, s;
+ float spd, dist, minlength, pullspeed, ropestretch, ropeairfriction, rubberforce, newlength, rubberforce_overstretch;
vector dir, org, end, v0, dv, v, myorg, vs;
if(self.realowner.hook != self) // how did that happen?
{
self.nextthink = time;
- s = self.realowner.cvar_cl_gunalign;
+ int s = self.realowner.cvar_cl_gunalign;
if(s != 1 && s != 2 && s != 4)
s = 3; // default value
--s;
//self.realowner.disableclientprediction = true;
}
-void GrapplingHook_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void GrapplingHook_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.health <= 0)
return;
{
entity missile;
vector org;
- float s;
vector vs;
if(forbidWeaponUse()) return;
makevectors(self.v_angle);
- s = self.cvar_cl_gunalign;
+ int s = self.cvar_cl_gunalign;
if(s != 1 && s != 2 && s != 4)
s = 3; // default value
--s;
+#include "_all.qh"
+
+void train_next();
+
const float LOOP = 1;
const float DNOSHADOW = 2;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/constants.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../csqcmodellib/sv_model.qh"
-#endif
+#include "_all.qh"
+
+#include "../common/triggers/subs.qh"
+
+#include "../client/bgmscript.qh"
+
+#include "../common/constants.qh"
+#include "../csqcmodellib/sv_model.qh"
.float modelscale;
void g_clientmodel_setcolormaptoactivator (void)
{
g_model_setcolormaptoactivator();
- self.SendFlags |= 1;
+ self.SendFlags |= (8 | 1);
+}
+
+void g_clientmodel_use(void)
+{
+ if (self.antiwall_flag == 1)
+ {
+ self.inactive = 1;
+ self.solid = SOLID_NOT;
+ }
+ else if (self.antiwall_flag == 2)
+ {
+ self.inactive = 0;
+ self.solid = self.default_solid;
+ }
+ g_clientmodel_setcolormaptoactivator();
}
void g_model_dropbyspawnflags()
self.SendFlags |= 2;
}
-float g_clientmodel_genericsendentity (entity to, float sf)
+float g_clientmodel_genericsendentity (entity to, int sf)
{
sf = sf & 0x0F;
if(self.angles != '0 0 0')
sf |= 0x10;
- if(self.solid && (self.mins != '0 0 0' || self.maxs != '0 0 0'))
+ if(self.mins != '0 0 0' || self.maxs != '0 0 0')
sf |= 0x20;
if(self.colormap != 0)
sf |= 0x40;
WriteCoord(MSG_ENTITY, self.movedir.z);
WriteByte(MSG_ENTITY, floor(self.lip * 255));
}
+ WriteShort(MSG_ENTITY, self.fade_start);
+ WriteShort(MSG_ENTITY, self.fade_end);
+ WriteShort(MSG_ENTITY, self.alpha_max);
+ WriteShort(MSG_ENTITY, self.alpha_min);
+ WriteShort(MSG_ENTITY, self.inactive);
+ WriteShort(MSG_ENTITY, self.fade_vertical_offset);
}
return true;
if(self.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) self.movetype = MOVETYPE_PHYSICS; \
if(!self.scale) self.scale = self.modelscale; \
SetBrushEntityModel(); \
- self.use = g_clientmodel_setcolormaptoactivator; \
+ self.use = g_clientmodel_use; \
InitializeEntity(self, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
if(!self.solid) self.solid = (sol); else if(self.solid < 0) self.solid = SOLID_NOT; \
if(!self.bgmscriptsustain) self.bgmscriptsustain = 1; else if(self.bgmscriptsustain < 0) self.bgmscriptsustain = 0; \
- Net_LinkEntity(self, true, 0, g_clientmodel_genericsendentity);
+ Net_LinkEntity(self, true, 0, g_clientmodel_genericsendentity); \
+ self.default_solid = sol;
// non-solid model entities:
void spawnfunc_misc_gamemodel() { self.angles_x = -self.angles.x; G_MODEL_INIT (SOLID_NOT) } // model entity
#include "g_subs.qh"
+#include "_all.qh"
-void SUB_NullThink(void) { }
+#include "antilag.qh"
+#include "command/common.qh"
+#include "../warpzonelib/common.qh"
void spawnfunc_info_null (void)
{
//print(ftos(time), " -> ", ftos(e.frame), "\n");
}
-/*
-==================
-SUB_Remove
-
-Remove self
-==================
-*/
-void SUB_Remove (void)
-{
- remove (self);
-}
-
-/*
-==================
-SUB_Friction
-
-Applies some friction to self
-==================
-*/
-void SUB_Friction (void)
-{
- self.nextthink = time;
- if(self.flags & FL_ONGROUND)
- self.velocity = self.velocity * (1 - frametime * self.friction);
-}
-
-/*
-==================
-SUB_VanishOrRemove
-
-Makes client invisible or removes non-client
-==================
-*/
-void SUB_VanishOrRemove (entity ent)
-{
- if (IS_CLIENT(ent))
- {
- // vanish
- ent.alpha = -1;
- ent.effects = 0;
- ent.glow_size = 0;
- ent.pflags = 0;
- }
- else
- {
- // remove
- remove (ent);
- }
-}
-
-void SUB_SetFade_Think (void)
-{
- if(self.alpha == 0)
- self.alpha = 1;
- self.think = SUB_SetFade_Think;
- self.nextthink = time;
- self.alpha -= frametime * self.fade_rate;
- if (self.alpha < 0.01)
- SUB_VanishOrRemove(self);
- else
- self.nextthink = time;
-}
-
-/*
-==================
-SUB_SetFade
-
-Fade 'ent' out when time >= 'when'
-==================
-*/
-void SUB_SetFade (entity ent, float when, float fadetime)
-{
- ent.fade_rate = 1/fadetime;
- ent.think = SUB_SetFade_Think;
- ent.nextthink = when;
-}
-
-/*
-=============
-SUB_CalcMove
-
-calculate self.velocity and self.nextthink to reach dest from
-self.origin traveling at speed
-===============
-*/
-void SUB_CalcMoveDone (void)
-{
- // After moving, set origin to exact final destination
-
- setorigin (self, self.finaldest);
- self.velocity = '0 0 0';
- self.nextthink = -1;
- if (self.think1)
- self.think1 ();
-}
-
-void SUB_CalcMove_controller_think (void)
-{
- entity oldself;
- float traveltime;
- float phasepos;
- float nexttick;
- vector delta;
- vector delta2;
- vector veloc;
- vector angloc;
- vector nextpos;
- delta = self.destvec;
- delta2 = self.destvec2;
- if(time < self.animstate_endtime) {
- nexttick = time + sys_frametime;
-
- traveltime = self.animstate_endtime - self.animstate_starttime;
- phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
- phasepos = cubic_speedfunc(self.platmovetype_start, self.platmovetype_end, phasepos);
- nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
- // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
-
- if(self.owner.platmovetype_turn)
- {
- vector destangle;
- destangle = delta + 2 * delta2 * phasepos;
- destangle = vectoangles(destangle);
- destangle.x = -destangle.x; // flip up / down orientation
-
- // take the shortest distance for the angles
- self.owner.angles_x -= 360 * floor((self.owner.angles.x - destangle.x) / 360 + 0.5);
- self.owner.angles_y -= 360 * floor((self.owner.angles.y - destangle.y) / 360 + 0.5);
- self.owner.angles_z -= 360 * floor((self.owner.angles.z - destangle.z) / 360 + 0.5);
- angloc = destangle - self.owner.angles;
- angloc = angloc * (1 / sys_frametime); // so it arrives for the next frame
- self.owner.avelocity = angloc;
- }
- if(nexttick < self.animstate_endtime)
- veloc = nextpos - self.owner.origin;
- else
- veloc = self.finaldest - self.owner.origin;
- veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
-
- self.owner.velocity = veloc;
- self.nextthink = nexttick;
- } else {
- // derivative: delta + 2 * delta2 (e.g. for angle positioning)
- oldself = self;
- self.owner.think = self.think1;
- self = self.owner;
- remove(oldself);
- self.think();
- }
-}
-
-void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest)
-{
- // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t
- // 2 * control * t - 2 * control * t * t + dest * t * t
- // 2 * control * t + (dest - 2 * control) * t * t
-
- controller.origin = org; // starting point
- control -= org;
- dest -= org;
-
- controller.destvec = 2 * control; // control point
- controller.destvec2 = dest - 2 * control; // quadratic part required to reach end point
- // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (dest - control)
-}
-
-void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest)
-{
- // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t
- // 2 * control * t - 2 * control * t * t + dest * t * t
- // 2 * control * t + (dest - 2 * control) * t * t
-
- controller.origin = org; // starting point
- dest -= org;
-
- controller.destvec = dest; // end point
- controller.destvec2 = '0 0 0';
-}
-
-void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
-{
- float traveltime;
- entity controller;
-
- if (!tspeed)
- objerror ("No speed is defined!");
-
- self.think1 = func;
- self.finaldest = tdest;
- self.think = SUB_CalcMoveDone;
-
- switch(tspeedtype)
- {
- default:
- case TSPEED_START:
- traveltime = 2 * vlen(tcontrol - self.origin) / tspeed;
- break;
- case TSPEED_END:
- traveltime = 2 * vlen(tcontrol - tdest) / tspeed;
- break;
- case TSPEED_LINEAR:
- traveltime = vlen(tdest - self.origin) / tspeed;
- break;
- case TSPEED_TIME:
- traveltime = tspeed;
- break;
- }
-
- if (traveltime < 0.1) // useless anim
- {
- self.velocity = '0 0 0';
- self.nextthink = self.ltime + 0.1;
- return;
- }
-
- controller = spawn();
- controller.classname = "SUB_CalcMove_controller";
- controller.owner = self;
- controller.platmovetype = self.platmovetype;
- controller.platmovetype_start = self.platmovetype_start;
- controller.platmovetype_end = self.platmovetype_end;
- SUB_CalcMove_controller_setbezier(controller, self.origin, tcontrol, tdest);
- controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
- controller.animstate_starttime = time;
- controller.animstate_endtime = time + traveltime;
- controller.think = SUB_CalcMove_controller_think;
- controller.think1 = self.think;
-
- // the thinking is now done by the controller
- self.think = SUB_NullThink; // for PushMove
- self.nextthink = self.ltime + traveltime;
-
- // invoke controller
- self = controller;
- self.think();
- self = self.owner;
-}
-
-void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
-{
- vector delta;
- float traveltime;
-
- if (!tspeed)
- objerror ("No speed is defined!");
-
- self.think1 = func;
- self.finaldest = tdest;
- self.think = SUB_CalcMoveDone;
-
- if (tdest == self.origin)
- {
- self.velocity = '0 0 0';
- self.nextthink = self.ltime + 0.1;
- return;
- }
-
- delta = tdest - self.origin;
-
- switch(tspeedtype)
- {
- default:
- case TSPEED_START:
- case TSPEED_END:
- case TSPEED_LINEAR:
- traveltime = vlen (delta) / tspeed;
- break;
- case TSPEED_TIME:
- traveltime = tspeed;
- break;
- }
-
- // Very short animations don't really show off the effect
- // of controlled animation, so let's just use linear movement.
- // Alternatively entities can choose to specify non-controlled movement.
- // The only currently implemented alternative movement is linear (value 1)
- if (traveltime < 0.15 || (self.platmovetype_start == 1 && self.platmovetype_end == 1)) // is this correct?
- {
- self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
- self.nextthink = self.ltime + traveltime;
- return;
- }
-
- // now just run like a bezier curve...
- SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
-}
-
-void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
-{
- entity oldself;
-
- oldself = self;
- self = ent;
-
- SUB_CalcMove (tdest, tspeedtype, tspeed, func);
-
- self = oldself;
-}
-
-/*
-=============
-SUB_CalcAngleMove
-
-calculate self.avelocity and self.nextthink to reach destangle from
-self.angles rotating
-
-The calling function should make sure self.think is valid
-===============
-*/
-void SUB_CalcAngleMoveDone (void)
-{
- // After rotating, set angle to exact final angle
- self.angles = self.finalangle;
- self.avelocity = '0 0 0';
- self.nextthink = -1;
- if (self.think1)
- self.think1 ();
-}
-
-// FIXME: I fixed this function only for rotation around the main axes
-void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
-{
- vector delta;
- float traveltime;
-
- if (!tspeed)
- objerror ("No speed is defined!");
-
- // take the shortest distance for the angles
- self.angles_x -= 360 * floor((self.angles.x - destangle.x) / 360 + 0.5);
- self.angles_y -= 360 * floor((self.angles.y - destangle.y) / 360 + 0.5);
- self.angles_z -= 360 * floor((self.angles.z - destangle.z) / 360 + 0.5);
- delta = destangle - self.angles;
-
- switch(tspeedtype)
- {
- default:
- case TSPEED_START:
- case TSPEED_END:
- case TSPEED_LINEAR:
- traveltime = vlen (delta) / tspeed;
- break;
- case TSPEED_TIME:
- traveltime = tspeed;
- break;
- }
-
- self.think1 = func;
- self.finalangle = destangle;
- self.think = SUB_CalcAngleMoveDone;
-
- if (traveltime < 0.1)
- {
- self.avelocity = '0 0 0';
- self.nextthink = self.ltime + 0.1;
- return;
- }
-
- self.avelocity = delta * (1 / traveltime);
- self.nextthink = self.ltime + traveltime;
-}
-
-void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
-{
- entity oldself;
-
- oldself = self;
- self = ent;
-
- SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);
-
- self = oldself;
-}
-
/*
==================
main
void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest);
-float TSPEED_TIME = -1;
-float TSPEED_LINEAR = 0;
-float TSPEED_START = 1;
-float TSPEED_END = 2;
-// TODO average too?
-
void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func);
void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func);
return stof(substring(dat, x-1, 1));
}
-string SetXBlock(float x, string dat, float new)
+string SetXBlock(float x, string dat, float val)
{
return strcat(
substring(dat, 0, x-1),
- ftos(new),
+ ftos(val),
substring(dat, x, -1)
);
}
+++ /dev/null
-#include "g_triggers.qh"
-#include "t_jumppads.qh"
-
-void SUB_DontUseTargets()
-{
-}
-
-
-void DelayThink()
-{
- activator = self.enemy;
- SUB_UseTargets ();
- remove(self);
-}
-
-/*
-==============================
-SUB_UseTargets
-
-the global "activator" should be set to the entity that initiated the firing.
-
-If self.delay is set, a DelayedUse entity will be created that will actually
-do the SUB_UseTargets after that many seconds have passed.
-
-Centerprints any self.message to the activator.
-
-Removes all entities with a targetname that match self.killtarget,
-and removes them, so some events can remove other triggers.
-
-Search for (string)targetname in all entities that
-match (string)self.target and call their .use function
-
-==============================
-*/
-void SUB_UseTargets()
-{
- entity t, stemp, otemp, act;
- string s;
- float i;
-
-//
-// check for a delay
-//
- if (self.delay)
- {
- // create a temp object to fire at a later time
- t = spawn();
- t.classname = "DelayedUse";
- t.nextthink = time + self.delay;
- t.think = DelayThink;
- t.enemy = activator;
- t.message = self.message;
- t.killtarget = self.killtarget;
- t.target = self.target;
- t.target2 = self.target2;
- t.target3 = self.target3;
- t.target4 = self.target4;
- return;
- }
-
-
-//
-// print the message
-//
- if(self)
- if(IS_PLAYER(activator) && self.message != "")
- if(IS_REAL_CLIENT(activator))
- {
- centerprint(activator, self.message);
- if (self.noise == "")
- play2(activator, "misc/talk.wav");
- }
-
-//
-// kill the killtagets
-//
- s = self.killtarget;
- if (s != "")
- {
- for(t = world; (t = find(t, targetname, s)); )
- remove(t);
- }
-
-//
-// fire targets
-//
- act = activator;
- stemp = self;
- otemp = other;
-
- if(stemp.target_random)
- RandomSelection_Init();
-
- for(i = 0; i < 4; ++i)
- {
- switch(i)
- {
- default:
- case 0: s = stemp.target; break;
- case 1: s = stemp.target2; break;
- case 2: s = stemp.target3; break;
- case 3: s = stemp.target4; break;
- }
- if (s != "")
- {
- for(t = world; (t = find(t, targetname, s)); )
- if(t.use)
- {
- if(stemp.target_random)
- {
- RandomSelection_Add(t, 0, string_null, 1, 0);
- }
- else
- {
- self = t;
- other = stemp;
- activator = act;
- self.use();
- }
- }
- }
- }
-
- if(stemp.target_random && RandomSelection_chosen_ent)
- {
- self = RandomSelection_chosen_ent;
- other = stemp;
- activator = act;
- self.use();
- }
-
- activator = act;
- self = stemp;
- other = otemp;
-}
-
-
-//=============================================================================
-
-// the wait time has passed, so set back up for another activation
-void multi_wait()
-{
- if (self.max_health)
- {
- self.health = self.max_health;
- self.takedamage = DAMAGE_YES;
- self.solid = SOLID_BBOX;
- }
-}
-
-
-// the trigger was just touched/killed/used
-// self.enemy should be set to the activator so it can be held through a delay
-// so wait for the delay time before firing
-void multi_trigger()
-{
- if (self.nextthink > time)
- {
- return; // allready been triggered
- }
-
- if (self.classname == "trigger_secret")
- {
- if (!IS_PLAYER(self.enemy))
- return;
- found_secrets = found_secrets + 1;
- WriteByte (MSG_ALL, SVC_FOUNDSECRET);
- }
-
- if (self.noise)
- sound (self.enemy, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
-
-// don't trigger again until reset
- self.takedamage = DAMAGE_NO;
-
- activator = self.enemy;
- other = self.goalentity;
- SUB_UseTargets();
-
- if (self.wait > 0)
- {
- self.think = multi_wait;
- self.nextthink = time + self.wait;
- }
- else if (self.wait == 0)
- {
- multi_wait(); // waiting finished
- }
- else
- { // we can't just remove (self) here, because this is a touch function
- // called wheil C code is looping through area links...
- self.touch = func_null;
- }
-}
-
-void multi_use()
-{
- self.goalentity = other;
- self.enemy = activator;
- multi_trigger();
-}
-
-void multi_touch()
-{
- if(!(self.spawnflags & 2))
- if(!other.iscreature)
- return;
-
- if(self.team)
- if(((self.spawnflags & 4) == 0) == (self.team != other.team))
- return;
-
-// if the trigger has an angles field, check player's facing direction
- if (self.movedir != '0 0 0')
- {
- makevectors (other.angles);
- if (v_forward * self.movedir < 0)
- return; // not facing the right way
- }
-
- EXACTTRIGGER_TOUCH;
-
- self.enemy = other;
- self.goalentity = other;
- multi_trigger ();
-}
-
-void multi_eventdamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
- if (!self.takedamage)
- return;
- if(self.spawnflags & DOOR_NOSPLASH)
- if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
- return;
- self.health = self.health - damage;
- if (self.health <= 0)
- {
- self.enemy = attacker;
- self.goalentity = inflictor;
- multi_trigger();
- }
-}
-
-void multi_reset()
-{
- if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
- self.touch = multi_touch;
- if (self.max_health)
- {
- self.health = self.max_health;
- self.takedamage = DAMAGE_YES;
- self.solid = SOLID_BBOX;
- }
- self.think = func_null;
- self.nextthink = 0;
- self.team = self.team_saved;
-}
-
-/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
-Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
-If "delay" is set, the trigger waits some time after activating before firing.
-"wait" : Seconds between triggerings. (.2 default)
-If notouch is set, the trigger is only fired by other entities, not by touching.
-NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
-sounds
-1) secret
-2) beep beep
-3) large switch
-4)
-set "message" to text string
-*/
-void spawnfunc_trigger_multiple()
-{
- self.reset = multi_reset;
- if (self.sounds == 1)
- {
- precache_sound ("misc/secret.wav");
- self.noise = "misc/secret.wav";
- }
- else if (self.sounds == 2)
- {
- precache_sound ("misc/talk.wav");
- self.noise = "misc/talk.wav";
- }
- else if (self.sounds == 3)
- {
- precache_sound ("misc/trigger1.wav");
- self.noise = "misc/trigger1.wav";
- }
-
- if (!self.wait)
- self.wait = 0.2;
- else if(self.wait < -1)
- self.wait = 0;
- self.use = multi_use;
-
- EXACTTRIGGER_INIT;
-
- self.team_saved = self.team;
-
- if (self.health)
- {
- if (self.spawnflags & SPAWNFLAG_NOTOUCH)
- objerror ("health and notouch don't make sense\n");
- self.max_health = self.health;
- self.event_damage = multi_eventdamage;
- self.takedamage = DAMAGE_YES;
- self.solid = SOLID_BBOX;
- setorigin (self, self.origin); // make sure it links into the world
- }
- else
- {
- if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
- {
- self.touch = multi_touch;
- setorigin (self, self.origin); // make sure it links into the world
- }
- }
-}
-
-
-/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
-Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
-"targetname". If "health" is set, the trigger must be killed to activate.
-If notouch is set, the trigger is only fired by other entities, not by touching.
-if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
-if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
-sounds
-1) secret
-2) beep beep
-3) large switch
-4)
-set "message" to text string
-*/
-void spawnfunc_trigger_once()
-{
- self.wait = -1;
- spawnfunc_trigger_multiple();
-}
-
-//=============================================================================
-
-/*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
-This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
-*/
-void spawnfunc_trigger_relay()
-{
- self.use = SUB_UseTargets;
- self.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully
-}
-
-void delay_use()
-{
- self.think = SUB_UseTargets;
- self.nextthink = self.wait;
-}
-
-void delay_reset()
-{
- self.think = func_null;
- self.nextthink = 0;
-}
-
-void spawnfunc_trigger_delay()
-{
- if(!self.wait)
- self.wait = 1;
-
- self.use = delay_use;
- self.reset = delay_reset;
-}
-
-//=============================================================================
-
-
-void counter_use()
-{
- self.count -= 1;
- if (self.count < 0)
- return;
-
- if (self.count == 0)
- {
- if(IS_PLAYER(activator) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
- Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COMPLETED);
-
- self.enemy = activator;
- multi_trigger ();
- }
- else
- {
- if(IS_PLAYER(activator) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
- if(self.count >= 4)
- Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COUNTER);
- else
- Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, self.count);
- }
-}
-
-void counter_reset()
-{
- self.count = self.cnt;
- multi_reset();
-}
-
-/*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage
-Acts as an intermediary for an action that takes multiple inputs.
-
-If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
-
-After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
-*/
-void spawnfunc_trigger_counter()
-{
- self.wait = -1;
- if (!self.count)
- self.count = 2;
- self.cnt = self.count;
-
- self.use = counter_use;
- self.reset = counter_reset;
-}
-
-void trigger_hurt_use()
-{
- if(IS_PLAYER(activator))
- self.enemy = activator;
- else
- self.enemy = world; // let's just destroy it, if taking over is too much work
-}
-
-void trigger_hurt_touch()
-{
- if (self.active != ACTIVE_ACTIVE)
- return;
-
- if(self.team)
- if(((self.spawnflags & 4) == 0) == (self.team != other.team))
- return;
-
- // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
- if (other.iscreature)
- {
- if (other.takedamage)
- if (other.triggerhurttime < time)
- {
- EXACTTRIGGER_TOUCH;
- other.triggerhurttime = time + 1;
-
- entity own;
- own = self.enemy;
- if (!IS_PLAYER(own))
- {
- own = self;
- self.enemy = world; // I still hate you all
- }
-
- Damage (other, self, own, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
- }
- }
- else if(other.damagedbytriggers)
- {
- if(other.takedamage)
- {
- EXACTTRIGGER_TOUCH;
- Damage(other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
- }
- }
-
- return;
-}
-
-/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
-Any object touching this will be hurt
-set dmg to damage amount
-defalt dmg = 5
-*/
-void spawnfunc_trigger_hurt()
-{
- EXACTTRIGGER_INIT;
- self.active = ACTIVE_ACTIVE;
- self.touch = trigger_hurt_touch;
- self.use = trigger_hurt_use;
- self.enemy = world; // I hate you all
- if (!self.dmg)
- self.dmg = 1000;
- if (self.message == "")
- self.message = "was in the wrong place";
- if (self.message2 == "")
- self.message2 = "was thrown into a world of hurt by";
- // self.message = "someone like %s always gets wrongplaced";
-
- if(!trigger_hurt_first)
- trigger_hurt_first = self;
- if(trigger_hurt_last)
- trigger_hurt_last.trigger_hurt_next = self;
- trigger_hurt_last = self;
-}
-
-float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
-{
- entity th;
-
- for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
- if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
- return true;
-
- return false;
-}
-
-//////////////////////////////////////////////////////////////
-//
-//
-//
-//Trigger heal --a04191b92fbd93aa67214ef7e72d6d2e
-//
-//////////////////////////////////////////////////////////////
-
-void trigger_heal_touch()
-{
- if (self.active != ACTIVE_ACTIVE)
- return;
-
- // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
- if (other.iscreature)
- {
- if (other.takedamage)
- if (!other.deadflag)
- if (other.triggerhealtime < time)
- {
- EXACTTRIGGER_TOUCH;
- other.triggerhealtime = time + 1;
-
- if (other.health < self.max_health)
- {
- other.health = min(other.health + self.health, self.max_health);
- other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
- sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
- }
- }
- }
-}
-
-void spawnfunc_trigger_heal()
-{
- self.active = ACTIVE_ACTIVE;
-
- EXACTTRIGGER_INIT;
- self.touch = trigger_heal_touch;
- if (!self.health)
- self.health = 10;
- if (!self.max_health)
- self.max_health = 200; //Max health topoff for field
- if(self.noise == "")
- self.noise = "misc/mediumhealth.wav";
- precache_sound(self.noise);
-}
-
-
-//////////////////////////////////////////////////////////////
-//
-//
-//
-//End trigger_heal
-//
-//////////////////////////////////////////////////////////////
-
-void trigger_gravity_remove(entity own)
-{
- if(own.trigger_gravity_check.owner == own)
- {
- UpdateCSQCProjectile(own);
- own.gravity = own.trigger_gravity_check.gravity;
- remove(own.trigger_gravity_check);
- }
- else
- backtrace("Removing a trigger_gravity_check with no valid owner");
- own.trigger_gravity_check = world;
-}
-void trigger_gravity_check_think()
-{
- // This spawns when a player enters the gravity zone and checks if he left.
- // Each frame, self.count is set to 2 by trigger_gravity_touch() and decreased by 1 here.
- // It the player has left the gravity trigger, this will be allowed to reach 0 and indicate that.
- if(self.count <= 0)
- {
- if(self.owner.trigger_gravity_check == self)
- trigger_gravity_remove(self.owner);
- else
- remove(self);
- return;
- }
- else
- {
- self.count -= 1;
- self.nextthink = time;
- }
-}
-
-void trigger_gravity_use()
-{
- self.state = !self.state;
-}
-
-void trigger_gravity_touch()
-{
- float g;
-
- if(self.state != true)
- return;
-
- EXACTTRIGGER_TOUCH;
-
- g = self.gravity;
-
- if (!(self.spawnflags & 1))
- {
- if(other.trigger_gravity_check)
- {
- if(self == other.trigger_gravity_check.enemy)
- {
- // same?
- other.trigger_gravity_check.count = 2; // gravity one more frame...
- return;
- }
-
- // compare prio
- if(self.cnt > other.trigger_gravity_check.enemy.cnt)
- trigger_gravity_remove(other);
- else
- return;
- }
- other.trigger_gravity_check = spawn();
- other.trigger_gravity_check.enemy = self;
- other.trigger_gravity_check.owner = other;
- other.trigger_gravity_check.gravity = other.gravity;
- other.trigger_gravity_check.think = trigger_gravity_check_think;
- other.trigger_gravity_check.nextthink = time;
- other.trigger_gravity_check.count = 2;
- if(other.gravity)
- g *= other.gravity;
- }
-
- if (other.gravity != g)
- {
- other.gravity = g;
- if(self.noise != "")
- sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
- UpdateCSQCProjectile(self.owner);
- }
-}
-
-void spawnfunc_trigger_gravity()
-{
- if(self.gravity == 1)
- return;
-
- EXACTTRIGGER_INIT;
- self.touch = trigger_gravity_touch;
- if(self.noise != "")
- precache_sound(self.noise);
-
- self.state = true;
- IFTARGETED
- {
- self.use = trigger_gravity_use;
- if(self.spawnflags & 2)
- self.state = false;
- }
-}
-
-//=============================================================================
-
-// TODO add a way to do looped sounds with sound(); then complete this entity
-void target_speaker_use_activator()
-{
- if (!IS_REAL_CLIENT(activator))
- return;
- string snd;
- if(substring(self.noise, 0, 1) == "*")
- {
- var .string sample;
- sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
- if(GetPlayerSoundSampleField_notFound)
- snd = "misc/null.wav";
- else if(activator.sample == "")
- snd = "misc/null.wav";
- else
- {
- tokenize_console(activator.sample);
- float n;
- n = stof(argv(1));
- if(n > 0)
- snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
- else
- snd = strcat(argv(0), ".wav"); // randomization
- }
- }
- else
- snd = self.noise;
- msg_entity = activator;
- soundto(MSG_ONE, self, CH_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
-}
-void target_speaker_use_on()
-{
- string snd;
- if(substring(self.noise, 0, 1) == "*")
- {
- var .string sample;
- sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
- if(GetPlayerSoundSampleField_notFound)
- snd = "misc/null.wav";
- else if(activator.sample == "")
- snd = "misc/null.wav";
- else
- {
- tokenize_console(activator.sample);
- float n;
- n = stof(argv(1));
- if(n > 0)
- snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
- else
- snd = strcat(argv(0), ".wav"); // randomization
- }
- }
- else
- snd = self.noise;
- sound(self, CH_TRIGGER_SINGLE, snd, VOL_BASE * self.volume, self.atten);
- if(self.spawnflags & 3)
- self.use = target_speaker_use_off;
-}
-void target_speaker_use_off()
-{
- sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASE * self.volume, self.atten);
- self.use = target_speaker_use_on;
-}
-void target_speaker_reset()
-{
- if(self.spawnflags & 1) // LOOPED_ON
- {
- if(self.use == target_speaker_use_on)
- target_speaker_use_on();
- }
- else if(self.spawnflags & 2)
- {
- if(self.use == target_speaker_use_off)
- target_speaker_use_off();
- }
-}
-
-void spawnfunc_target_speaker()
-{
- // TODO: "*" prefix to sound file name
- // TODO: wait and random (just, HOW? random is not a field)
- if(self.noise)
- precache_sound (self.noise);
-
- if(!self.atten && !(self.spawnflags & 4))
- {
- IFTARGETED
- self.atten = ATTEN_NORM;
- else
- self.atten = ATTEN_STATIC;
- }
- else if(self.atten < 0)
- self.atten = 0;
-
- if(!self.volume)
- self.volume = 1;
-
- IFTARGETED
- {
- if(self.spawnflags & 8) // ACTIVATOR
- self.use = target_speaker_use_activator;
- else if(self.spawnflags & 1) // LOOPED_ON
- {
- target_speaker_use_on();
- self.reset = target_speaker_reset;
- }
- else if(self.spawnflags & 2) // LOOPED_OFF
- {
- self.use = target_speaker_use_on;
- self.reset = target_speaker_reset;
- }
- else
- self.use = target_speaker_use_on;
- }
- else if(self.spawnflags & 1) // LOOPED_ON
- {
- ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
- remove(self);
- }
- else if(self.spawnflags & 2) // LOOPED_OFF
- {
- objerror("This sound entity can never be activated");
- }
- else
- {
- // Quake/Nexuiz fallback
- ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
- remove(self);
- }
-}
-
-
-void spawnfunc_func_stardust() {
- self.effects = EF_STARDUST;
-}
-
-float pointparticles_SendEntity(entity to, float fl)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
-
- // optional features to save space
- fl = fl & 0x0F;
- if(self.spawnflags & 2)
- fl |= 0x10; // absolute count on toggle-on
- if(self.movedir != '0 0 0' || self.velocity != '0 0 0')
- fl |= 0x20; // 4 bytes - saves CPU
- if(self.waterlevel || self.count != 1)
- fl |= 0x40; // 4 bytes - obscure features almost never used
- if(self.mins != '0 0 0' || self.maxs != '0 0 0')
- fl |= 0x80; // 14 bytes - saves lots of space
-
- WriteByte(MSG_ENTITY, fl);
- if(fl & 2)
- {
- if(self.state)
- WriteCoord(MSG_ENTITY, self.impulse);
- else
- WriteCoord(MSG_ENTITY, 0); // off
- }
- if(fl & 4)
- {
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
- }
- if(fl & 1)
- {
- if(self.model != "null")
- {
- WriteShort(MSG_ENTITY, self.modelindex);
- if(fl & 0x80)
- {
- WriteCoord(MSG_ENTITY, self.mins.x);
- WriteCoord(MSG_ENTITY, self.mins.y);
- WriteCoord(MSG_ENTITY, self.mins.z);
- WriteCoord(MSG_ENTITY, self.maxs.x);
- WriteCoord(MSG_ENTITY, self.maxs.y);
- WriteCoord(MSG_ENTITY, self.maxs.z);
- }
- }
- else
- {
- WriteShort(MSG_ENTITY, 0);
- if(fl & 0x80)
- {
- WriteCoord(MSG_ENTITY, self.maxs.x);
- WriteCoord(MSG_ENTITY, self.maxs.y);
- WriteCoord(MSG_ENTITY, self.maxs.z);
- }
- }
- WriteShort(MSG_ENTITY, self.cnt);
- if(fl & 0x20)
- {
- WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
- WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
- }
- if(fl & 0x40)
- {
- WriteShort(MSG_ENTITY, self.waterlevel * 16.0);
- WriteByte(MSG_ENTITY, self.count * 16.0);
- }
- WriteString(MSG_ENTITY, self.noise);
- if(self.noise != "")
- {
- WriteByte(MSG_ENTITY, floor(self.atten * 64));
- WriteByte(MSG_ENTITY, floor(self.volume * 255));
- }
- WriteString(MSG_ENTITY, self.bgmscript);
- if(self.bgmscript != "")
- {
- WriteByte(MSG_ENTITY, floor(self.bgmscriptattack * 64));
- WriteByte(MSG_ENTITY, floor(self.bgmscriptdecay * 64));
- WriteByte(MSG_ENTITY, floor(self.bgmscriptsustain * 255));
- WriteByte(MSG_ENTITY, floor(self.bgmscriptrelease * 64));
- }
- }
- return 1;
-}
-
-void pointparticles_use()
-{
- self.state = !self.state;
- self.SendFlags |= 2;
-}
-
-void pointparticles_think()
-{
- if(self.origin != self.oldorigin)
- {
- self.SendFlags |= 4;
- self.oldorigin = self.origin;
- }
- self.nextthink = time;
-}
-
-void pointparticles_reset()
-{
- if(self.spawnflags & 1)
- self.state = 1;
- else
- self.state = 0;
-}
-
-void spawnfunc_func_pointparticles()
-{
- if(self.model != "")
- setmodel(self, self.model);
- if(self.noise != "")
- precache_sound (self.noise);
-
- if(!self.bgmscriptsustain)
- self.bgmscriptsustain = 1;
- else if(self.bgmscriptsustain < 0)
- self.bgmscriptsustain = 0;
-
- if(!self.atten)
- self.atten = ATTEN_NORM;
- else if(self.atten < 0)
- self.atten = 0;
- if(!self.volume)
- self.volume = 1;
- if(!self.count)
- self.count = 1;
- if(!self.impulse)
- self.impulse = 1;
-
- if(!self.modelindex)
- {
- setorigin(self, self.origin + self.mins);
- setsize(self, '0 0 0', self.maxs - self.mins);
- }
- if(!self.cnt)
- self.cnt = particleeffectnum(self.mdl);
-
- Net_LinkEntity(self, (self.spawnflags & 4), 0, pointparticles_SendEntity);
-
- IFTARGETED
- {
- self.use = pointparticles_use;
- self.reset = pointparticles_reset;
- self.reset();
- }
- else
- self.state = 1;
- self.think = pointparticles_think;
- self.nextthink = time;
-}
-
-void spawnfunc_func_sparks()
-{
- // self.cnt is the amount of sparks that one burst will spawn
- if(self.cnt < 1) {
- self.cnt = 25.0; // nice default value
- }
-
- // self.wait is the probability that a sparkthink will spawn a spark shower
- // range: 0 - 1, but 0 makes little sense, so...
- if(self.wait < 0.05) {
- self.wait = 0.25; // nice default value
- }
-
- self.count = self.cnt;
- self.mins = '0 0 0';
- self.maxs = '0 0 0';
- self.velocity = '0 0 -1';
- self.mdl = "TE_SPARK";
- self.impulse = 10 * self.wait; // by default 2.5/sec
- self.wait = 0;
- self.cnt = 0; // use mdl
-
- spawnfunc_func_pointparticles();
-}
-
-float rainsnow_SendEntity(entity to, float sf)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
- WriteByte(MSG_ENTITY, self.state);
- WriteCoord(MSG_ENTITY, self.origin.x + self.mins.x);
- WriteCoord(MSG_ENTITY, self.origin.y + self.mins.y);
- WriteCoord(MSG_ENTITY, self.origin.z + self.mins.z);
- WriteCoord(MSG_ENTITY, self.maxs.x - self.mins.x);
- WriteCoord(MSG_ENTITY, self.maxs.y - self.mins.y);
- WriteCoord(MSG_ENTITY, self.maxs.z - self.mins.z);
- WriteShort(MSG_ENTITY, compressShortVector(self.dest));
- WriteShort(MSG_ENTITY, self.count);
- WriteByte(MSG_ENTITY, self.cnt);
- return 1;
-}
-
-/*QUAKED spawnfunc_func_rain (0 .5 .8) ?
-This is an invisible area like a trigger, which rain falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-void spawnfunc_func_rain()
-{
- self.dest = self.velocity;
- self.velocity = '0 0 0';
- if (!self.dest)
- self.dest = '0 0 -700';
- self.angles = '0 0 0';
- self.movetype = MOVETYPE_NONE;
- self.solid = SOLID_NOT;
- SetBrushEntityModel();
- if (!self.cnt)
- self.cnt = 12;
- if (!self.count)
- self.count = 2000;
- self.count = 0.01 * self.count * (self.size.x / 1024) * (self.size.y / 1024);
- if (self.count < 1)
- self.count = 1;
- if(self.count > 65535)
- self.count = 65535;
-
- self.state = 1; // 1 is rain, 0 is snow
- self.Version = 1;
-
- Net_LinkEntity(self, false, 0, rainsnow_SendEntity);
-}
-
-
-/*QUAKED spawnfunc_func_snow (0 .5 .8) ?
-This is an invisible area like a trigger, which snow falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-void spawnfunc_func_snow()
-{
- self.dest = self.velocity;
- self.velocity = '0 0 0';
- if (!self.dest)
- self.dest = '0 0 -300';
- self.angles = '0 0 0';
- self.movetype = MOVETYPE_NONE;
- self.solid = SOLID_NOT;
- SetBrushEntityModel();
- if (!self.cnt)
- self.cnt = 12;
- if (!self.count)
- self.count = 2000;
- self.count = 0.01 * self.count * (self.size.x / 1024) * (self.size.y / 1024);
- if (self.count < 1)
- self.count = 1;
- if(self.count > 65535)
- self.count = 65535;
-
- self.state = 0; // 1 is rain, 0 is snow
- self.Version = 1;
-
- Net_LinkEntity(self, false, 0, rainsnow_SendEntity);
-}
-
-void misc_laser_aim()
-{
- vector a;
- if(self.enemy)
- {
- if(self.spawnflags & 2)
- {
- if(self.enemy.origin != self.mangle)
- {
- self.mangle = self.enemy.origin;
- self.SendFlags |= 2;
- }
- }
- else
- {
- a = vectoangles(self.enemy.origin - self.origin);
- a.x = -a.x;
- if(a != self.mangle)
- {
- self.mangle = a;
- self.SendFlags |= 2;
- }
- }
- }
- else
- {
- if(self.angles != self.mangle)
- {
- self.mangle = self.angles;
- self.SendFlags |= 2;
- }
- }
- if(self.origin != self.oldorigin)
- {
- self.SendFlags |= 1;
- self.oldorigin = self.origin;
- }
-}
-
-void misc_laser_init()
-{
- if(self.target != "")
- self.enemy = find(world, targetname, self.target);
-}
-
-void misc_laser_think()
-{
- vector o;
- entity oldself;
- entity hitent;
- vector hitloc;
-
- self.nextthink = time;
-
- if(!self.state)
- return;
-
- misc_laser_aim();
-
- if(self.enemy)
- {
- o = self.enemy.origin;
- if (!(self.spawnflags & 2))
- o = self.origin + normalize(o - self.origin) * 32768;
- }
- else
- {
- makevectors(self.mangle);
- o = self.origin + v_forward * 32768;
- }
-
- if(self.dmg || self.enemy.target != "")
- {
- traceline(self.origin, o, MOVE_NORMAL, self);
- }
- hitent = trace_ent;
- hitloc = trace_endpos;
-
- if(self.enemy.target != "") // DETECTOR laser
- {
- if(trace_ent.iscreature)
- {
- self.pusher = hitent;
- if(!self.count)
- {
- self.count = 1;
-
- oldself = self;
- self = self.enemy;
- activator = self.pusher;
- SUB_UseTargets();
- self = oldself;
- }
- }
- else
- {
- if(self.count)
- {
- self.count = 0;
-
- oldself = self;
- self = self.enemy;
- activator = self.pusher;
- SUB_UseTargets();
- self = oldself;
- }
- }
- }
-
- if(self.dmg)
- {
- if(self.team)
- if(((self.spawnflags & 8) == 0) == (self.team != hitent.team))
- return;
- if(hitent.takedamage)
- Damage(hitent, self, self, ((self.dmg < 0) ? 100000 : (self.dmg * frametime)), DEATH_HURTTRIGGER, hitloc, '0 0 0');
- }
-}
-
-float laser_SendEntity(entity to, float fl)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
- fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
- if(self.spawnflags & 2)
- fl |= 0x80;
- if(self.alpha)
- fl |= 0x40;
- if(self.scale != 1 || self.modelscale != 1)
- fl |= 0x20;
- if(self.spawnflags & 4)
- fl |= 0x10;
- WriteByte(MSG_ENTITY, fl);
- if(fl & 1)
- {
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
- }
- if(fl & 8)
- {
- WriteByte(MSG_ENTITY, self.colormod.x * 255.0);
- WriteByte(MSG_ENTITY, self.colormod.y * 255.0);
- WriteByte(MSG_ENTITY, self.colormod.z * 255.0);
- if(fl & 0x40)
- WriteByte(MSG_ENTITY, self.alpha * 255.0);
- if(fl & 0x20)
- {
- WriteByte(MSG_ENTITY, bound(0, self.scale * 16.0, 255));
- WriteByte(MSG_ENTITY, bound(0, self.modelscale * 16.0, 255));
- }
- if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
- WriteShort(MSG_ENTITY, self.cnt + 1);
- }
- if(fl & 2)
- {
- if(fl & 0x80)
- {
- WriteCoord(MSG_ENTITY, self.enemy.origin.x);
- WriteCoord(MSG_ENTITY, self.enemy.origin.y);
- WriteCoord(MSG_ENTITY, self.enemy.origin.z);
- }
- else
- {
- WriteAngle(MSG_ENTITY, self.mangle.x);
- WriteAngle(MSG_ENTITY, self.mangle.y);
- }
- }
- if(fl & 4)
- WriteByte(MSG_ENTITY, self.state);
- return 1;
-}
-
-/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
-Any object touching the beam will be hurt
-Keys:
-"target"
- spawnfunc_target_position where the laser ends
-"mdl"
- name of beam end effect to use
-"colormod"
- color of the beam (default: red)
-"dmg"
- damage per second (-1 for a laser that kills immediately)
-*/
-void laser_use()
-{
- self.state = !self.state;
- self.SendFlags |= 4;
- misc_laser_aim();
-}
-
-void laser_reset()
-{
- if(self.spawnflags & 1)
- self.state = 1;
- else
- self.state = 0;
-}
-
-void spawnfunc_misc_laser()
-{
- if(self.mdl)
- {
- if(self.mdl == "none")
- self.cnt = -1;
- else
- {
- self.cnt = particleeffectnum(self.mdl);
- if(self.cnt < 0)
- if(self.dmg)
- self.cnt = particleeffectnum("laser_deadly");
- }
- }
- else if(!self.cnt)
- {
- if(self.dmg)
- self.cnt = particleeffectnum("laser_deadly");
- else
- self.cnt = -1;
- }
- if(self.cnt < 0)
- self.cnt = -1;
-
- if(self.colormod == '0 0 0')
- if(!self.alpha)
- self.colormod = '1 0 0';
- if(self.message == "")
- self.message = "saw the light";
- if (self.message2 == "")
- self.message2 = "was pushed into a laser by";
- if(!self.scale)
- self.scale = 1;
- if(!self.modelscale)
- self.modelscale = 1;
- else if(self.modelscale < 0)
- self.modelscale = 0;
- self.think = misc_laser_think;
- self.nextthink = time;
- InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
-
- self.mangle = self.angles;
-
- Net_LinkEntity(self, false, 0, laser_SendEntity);
-
- IFTARGETED
- {
- self.reset = laser_reset;
- laser_reset();
- self.use = laser_use;
- }
- else
- self.state = 1;
-}
-
-// tZorks trigger impulse / gravity
-
-// targeted (directional) mode
-void trigger_impulse_touch1()
-{
- entity targ;
- float pushdeltatime;
- float str;
-
- if (self.active != ACTIVE_ACTIVE)
- return;
-
- if (!isPushable(other))
- return;
-
- EXACTTRIGGER_TOUCH;
-
- targ = find(world, targetname, self.target);
- if(!targ)
- {
- objerror("trigger_force without a (valid) .target!\n");
- remove(self);
- return;
- }
-
- str = min(self.radius, vlen(self.origin - other.origin));
-
- if(self.falloff == 1)
- str = (str / self.radius) * self.strength;
- else if(self.falloff == 2)
- str = (1 - (str / self.radius)) * self.strength;
- else
- str = self.strength;
-
- pushdeltatime = time - other.lastpushtime;
- if (pushdeltatime > 0.15) pushdeltatime = 0;
- other.lastpushtime = time;
- if(!pushdeltatime) return;
-
- other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
- other.flags &= ~FL_ONGROUND;
- UpdateCSQCProjectile(other);
-}
-
-// Directionless (accelerator/decelerator) mode
-void trigger_impulse_touch2()
-{
- float pushdeltatime;
-
- if (self.active != ACTIVE_ACTIVE)
- return;
-
- if (!isPushable(other))
- return;
-
- EXACTTRIGGER_TOUCH;
-
- pushdeltatime = time - other.lastpushtime;
- if (pushdeltatime > 0.15) pushdeltatime = 0;
- other.lastpushtime = time;
- if(!pushdeltatime) return;
-
- // div0: ticrate independent, 1 = identity (not 20)
- other.velocity = other.velocity * pow(self.strength, pushdeltatime);
- UpdateCSQCProjectile(other);
-}
-
-// Spherical (gravity/repulsor) mode
-void trigger_impulse_touch3()
-{
- float pushdeltatime;
- float str;
-
- if (self.active != ACTIVE_ACTIVE)
- return;
-
- if (!isPushable(other))
- return;
-
- EXACTTRIGGER_TOUCH;
-
- pushdeltatime = time - other.lastpushtime;
- if (pushdeltatime > 0.15) pushdeltatime = 0;
- other.lastpushtime = time;
- if(!pushdeltatime) return;
-
- setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
-
- str = min(self.radius, vlen(self.origin - other.origin));
-
- if(self.falloff == 1)
- str = (1 - str / self.radius) * self.strength; // 1 in the inside
- else if(self.falloff == 2)
- str = (str / self.radius) * self.strength; // 0 in the inside
- else
- str = self.strength;
-
- other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
- UpdateCSQCProjectile(other);
-}
-
-/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
--------- KEYS --------
-target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
- If not, this trigger acts like a damper/accelerator field.
-
-strength : This is how mutch force to add in the direction of .target each second
- when .target is set. If not, this is hoe mutch to slow down/accelerate
- someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
-
-radius : If set, act as a spherical device rather then a liniar one.
-
-falloff : 0 = none, 1 = liniar, 2 = inverted liniar
-
--------- NOTES --------
-Use a brush textured with common/origin in the trigger entity to determine the origin of the force
-in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
-*/
-
-void spawnfunc_trigger_impulse()
-{
- self.active = ACTIVE_ACTIVE;
-
- EXACTTRIGGER_INIT;
- if(self.radius)
- {
- if(!self.strength) self.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
- setorigin(self, self.origin);
- setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
- self.touch = trigger_impulse_touch3;
- }
- else
- {
- if(self.target)
- {
- if(!self.strength) self.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
- self.touch = trigger_impulse_touch1;
- }
- else
- {
- if(!self.strength) self.strength = 0.9;
- self.strength = pow(self.strength, autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
- self.touch = trigger_impulse_touch2;
- }
- }
-}
-
-/*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
-"Flip-flop" trigger gate... lets only every second trigger event through
-*/
-void flipflop_use()
-{
- self.state = !self.state;
- if(self.state)
- SUB_UseTargets();
-}
-
-void spawnfunc_trigger_flipflop()
-{
- if(self.spawnflags & 1)
- self.state = 1;
- self.use = flipflop_use;
- self.reset = spawnfunc_trigger_flipflop; // perfect resetter
-}
-
-/*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
-"Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
-*/
-void monoflop_use()
-{
- self.nextthink = time + self.wait;
- self.enemy = activator;
- if(self.state)
- return;
- self.state = 1;
- SUB_UseTargets();
-}
-void monoflop_fixed_use()
-{
- if(self.state)
- return;
- self.nextthink = time + self.wait;
- self.state = 1;
- self.enemy = activator;
- SUB_UseTargets();
-}
-
-void monoflop_think()
-{
- self.state = 0;
- activator = self.enemy;
- SUB_UseTargets();
-}
-
-void monoflop_reset()
-{
- self.state = 0;
- self.nextthink = 0;
-}
-
-void spawnfunc_trigger_monoflop()
-{
- if(!self.wait)
- self.wait = 1;
- if(self.spawnflags & 1)
- self.use = monoflop_fixed_use;
- else
- self.use = monoflop_use;
- self.think = monoflop_think;
- self.state = 0;
- self.reset = monoflop_reset;
-}
-
-void multivibrator_send()
-{
- float newstate;
- float cyclestart;
-
- cyclestart = floor((time + self.phase) / (self.wait + self.respawntime)) * (self.wait + self.respawntime) - self.phase;
-
- newstate = (time < cyclestart + self.wait);
-
- activator = self;
- if(self.state != newstate)
- SUB_UseTargets();
- self.state = newstate;
-
- if(self.state)
- self.nextthink = cyclestart + self.wait + 0.01;
- else
- self.nextthink = cyclestart + self.wait + self.respawntime + 0.01;
-}
-
-void multivibrator_toggle()
-{
- if(self.nextthink == 0)
- {
- multivibrator_send();
- }
- else
- {
- if(self.state)
- {
- SUB_UseTargets();
- self.state = 0;
- }
- self.nextthink = 0;
- }
-}
-
-void multivibrator_reset()
-{
- if(!(self.spawnflags & 1))
- self.nextthink = 0; // wait for a trigger event
- else
- self.nextthink = max(1, time);
-}
-
-/*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
-"Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
--------- KEYS --------
-target: trigger all entities with this targetname when it goes off
-targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
-phase: offset of the timing
-wait: "on" cycle time (default: 1)
-respawntime: "off" cycle time (default: same as wait)
--------- SPAWNFLAGS --------
-START_ON: assume it is already turned on (when targeted)
-*/
-void spawnfunc_trigger_multivibrator()
-{
- if(!self.wait)
- self.wait = 1;
- if(!self.respawntime)
- self.respawntime = self.wait;
-
- self.state = 0;
- self.use = multivibrator_toggle;
- self.think = multivibrator_send;
- self.nextthink = max(1, time);
-
- IFTARGETED
- multivibrator_reset();
-}
-
-
-void follow_init()
-{
- entity src, dst;
- src = world;
- dst = world;
- if(self.killtarget != "")
- src = find(world, targetname, self.killtarget);
- if(self.target != "")
- dst = find(world, targetname, self.target);
-
- if(!src && !dst)
- {
- objerror("follow: could not find target/killtarget");
- return;
- }
-
- if(self.jointtype)
- {
- // already done :P entity must stay
- self.aiment = src;
- self.enemy = dst;
- }
- else if(!src || !dst)
- {
- objerror("follow: could not find target/killtarget");
- return;
- }
- else if(self.spawnflags & 1)
- {
- // attach
- if(self.spawnflags & 2)
- {
- setattachment(dst, src, self.message);
- }
- else
- {
- attach_sameorigin(dst, src, self.message);
- }
-
- dst.solid = SOLID_NOT; // solid doesn't work with attachment
- remove(self);
- }
- else
- {
- if(self.spawnflags & 2)
- {
- dst.movetype = MOVETYPE_FOLLOW;
- dst.aiment = src;
- // dst.punchangle = '0 0 0'; // keep unchanged
- dst.view_ofs = dst.origin;
- dst.v_angle = dst.angles;
- }
- else
- {
- follow_sameorigin(dst, src);
- }
-
- remove(self);
- }
-}
-
-void spawnfunc_misc_follow()
-{
- InitializeEntity(self, follow_init, INITPRIO_FINDTARGET);
-}
-
-
-
-void gamestart_use() {
- activator = self;
- SUB_UseTargets();
- remove(self);
-}
-
-void spawnfunc_trigger_gamestart() {
- self.use = gamestart_use;
- self.reset2 = spawnfunc_trigger_gamestart;
-
- if(self.wait)
- {
- self.think = self.use;
- self.nextthink = game_starttime + self.wait;
- }
- else
- InitializeEntity(self, gamestart_use, INITPRIO_FINDTARGET);
-}
-
-
-
-
-void target_voicescript_clear(entity pl)
-{
- pl.voicescript = world;
-}
-
-void target_voicescript_use()
-{
- if(activator.voicescript != self)
- {
- activator.voicescript = self;
- activator.voicescript_index = 0;
- activator.voicescript_nextthink = time + self.delay;
- }
-}
-
-void target_voicescript_next(entity pl)
-{
- entity vs;
- float i, n, dt;
-
- vs = pl.voicescript;
- if(!vs)
- return;
- if(vs.message == "")
- return;
- if (!IS_PLAYER(pl))
- return;
- if(gameover)
- return;
-
- if(time >= pl.voicescript_voiceend)
- {
- if(time >= pl.voicescript_nextthink)
- {
- // get the next voice...
- n = tokenize_console(vs.message);
-
- if(pl.voicescript_index < vs.cnt)
- i = pl.voicescript_index * 2;
- else if(n > vs.cnt * 2)
- i = ((pl.voicescript_index - vs.cnt) % ((n - vs.cnt * 2 - 1) / 2)) * 2 + vs.cnt * 2 + 1;
- else
- i = -1;
-
- if(i >= 0)
- {
- play2(pl, strcat(vs.netname, "/", argv(i), ".wav"));
- dt = stof(argv(i + 1));
- if(dt >= 0)
- {
- pl.voicescript_voiceend = time + dt;
- pl.voicescript_nextthink = pl.voicescript_voiceend + vs.wait * (0.5 + random());
- }
- else
- {
- pl.voicescript_voiceend = time - dt;
- pl.voicescript_nextthink = pl.voicescript_voiceend;
- }
-
- pl.voicescript_index += 1;
- }
- else
- {
- pl.voicescript = world; // stop trying then
- }
- }
- }
-}
-
-void spawnfunc_target_voicescript()
-{
- // netname: directory of the sound files
- // message: list of "sound file" duration "sound file" duration, a *, and again a list
- // foo1 4.1 foo2 4.0 foo3 -3.1 * fool1 1.1 fool2 7.1 fool3 9.1 fool4 3.7
- // Here, a - in front of the duration means that no delay is to be
- // added after this message
- // wait: average time between messages
- // delay: initial delay before the first message
-
- float i, n;
- self.use = target_voicescript_use;
-
- n = tokenize_console(self.message);
- self.cnt = n / 2;
- for(i = 0; i+1 < n; i += 2)
- {
- if(argv(i) == "*")
- {
- self.cnt = i / 2;
- ++i;
- }
- precache_sound(strcat(self.netname, "/", argv(i), ".wav"));
- }
-}
-
-
-
-void trigger_relay_teamcheck_use()
-{
- if(activator.team)
- {
- if(self.spawnflags & 2)
- {
- if(activator.team != self.team)
- SUB_UseTargets();
- }
- else
- {
- if(activator.team == self.team)
- SUB_UseTargets();
- }
- }
- else
- {
- if(self.spawnflags & 1)
- SUB_UseTargets();
- }
-}
-
-void trigger_relay_teamcheck_reset()
-{
- self.team = self.team_saved;
-}
-
-void spawnfunc_trigger_relay_teamcheck()
-{
- self.team_saved = self.team;
- self.use = trigger_relay_teamcheck_use;
- self.reset = trigger_relay_teamcheck_reset;
-}
-
-
-
-void trigger_disablerelay_use()
-{
- entity e;
-
- float a, b;
- a = b = 0;
-
- for(e = world; (e = find(e, targetname, self.target)); )
- {
- if(e.use == SUB_UseTargets)
- {
- e.use = SUB_DontUseTargets;
- ++a;
- }
- else if(e.use == SUB_DontUseTargets)
- {
- e.use = SUB_UseTargets;
- ++b;
- }
- }
-
- if((!a) == (!b))
- print("Invalid use of trigger_disablerelay: ", ftos(a), " relays were on, ", ftos(b), " relays were off!\n");
-}
-
-void spawnfunc_trigger_disablerelay()
-{
- self.use = trigger_disablerelay_use;
-}
-
-string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
-{
- float domatch, dotrigger, matchstart, l;
- string s, msg;
- entity oldself;
- string savemessage;
-
- magicear_matched = false;
-
- dotrigger = ((IS_PLAYER(source)) && (source.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius)));
- domatch = ((ear.spawnflags & 32) || dotrigger);
-
- if (!domatch)
- return msgin;
-
- if (!msgin)
- {
- // we are in TUBA mode!
- if (!(ear.spawnflags & 256))
- return msgin;
-
- if(!W_Tuba_HasPlayed(source, ear.message, ear.movedir.x, !(ear.spawnflags & 512), ear.movedir.y, ear.movedir.z))
- return msgin;
-
- magicear_matched = true;
-
- if(dotrigger)
- {
- oldself = self;
- activator = source;
- self = ear;
- savemessage = self.message;
- self.message = string_null;
- SUB_UseTargets();
- self.message = savemessage;
- self = oldself;
- }
-
- if(ear.netname != "")
- return ear.netname;
-
- return msgin;
- }
-
- if(ear.spawnflags & 256) // ENOTUBA
- return msgin;
-
- if(privatesay)
- {
- if(ear.spawnflags & 4)
- return msgin;
- }
- else
- {
- if(!teamsay)
- if(ear.spawnflags & 1)
- return msgin;
- if(teamsay > 0)
- if(ear.spawnflags & 2)
- return msgin;
- if(teamsay < 0)
- if(ear.spawnflags & 8)
- return msgin;
- }
-
- matchstart = -1;
- l = strlen(ear.message);
-
- if(ear.spawnflags & 128)
- msg = msgin;
- else
- msg = strdecolorize(msgin);
-
- if(substring(ear.message, 0, 1) == "*")
- {
- if(substring(ear.message, -1, 1) == "*")
- {
- // two wildcards
- // as we need multi-replacement here...
- s = substring(ear.message, 1, -2);
- l -= 2;
- if(strstrofs(msg, s, 0) >= 0)
- matchstart = -2; // we use strreplace on s
- }
- else
- {
- // match at start
- s = substring(ear.message, 1, -1);
- l -= 1;
- if(substring(msg, -l, l) == s)
- matchstart = strlen(msg) - l;
- }
- }
- else
- {
- if(substring(ear.message, -1, 1) == "*")
- {
- // match at end
- s = substring(ear.message, 0, -2);
- l -= 1;
- if(substring(msg, 0, l) == s)
- matchstart = 0;
- }
- else
- {
- // full match
- s = ear.message;
- if(msg == ear.message)
- matchstart = 0;
- }
- }
-
- if(matchstart == -1) // no match
- return msgin;
-
- magicear_matched = true;
-
- if(dotrigger)
- {
- oldself = self;
- activator = source;
- self = ear;
- savemessage = self.message;
- self.message = string_null;
- SUB_UseTargets();
- self.message = savemessage;
- self = oldself;
- }
-
- if(ear.spawnflags & 16)
- {
- return ear.netname;
- }
- else if(ear.netname != "")
- {
- if(matchstart < 0)
- return strreplace(s, ear.netname, msg);
- else
- return strcat(
- substring(msg, 0, matchstart),
- ear.netname,
- substring(msg, matchstart + l, -1)
- );
- }
- else
- return msgin;
-}
-
-string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin)
-{
- entity ear;
- string msgout;
- for(ear = magicears; ear; ear = ear.enemy)
- {
- msgout = trigger_magicear_processmessage(ear, source, teamsay, privatesay, msgin);
- if(!(ear.spawnflags & 64))
- if(magicear_matched)
- return msgout;
- msgin = msgout;
- }
- return msgin;
-}
-
-void spawnfunc_trigger_magicear()
-{
- self.enemy = magicears;
- magicears = self;
-
- // actually handled in "say" processing
- // spawnflags:
- // 1 = ignore say
- // 2 = ignore teamsay
- // 4 = ignore tell
- // 8 = ignore tell to unknown player
- // 16 = let netname replace the whole message (otherwise, netname is a word replacement if set)
- // 32 = perform the replacement even if outside the radius or dead
- // 64 = continue replacing/triggering even if this one matched
- // 128 = don't decolorize message before matching
- // 256 = message is a tuba note sequence (pitch.duration pitch.duration ...)
- // 512 = tuba notes must be exact right pitch, no transposing
- // message: either
- // *pattern*
- // or
- // *pattern
- // or
- // pattern*
- // or
- // pattern
- // netname:
- // if set, replacement for the matched text
- // radius:
- // "hearing distance"
- // target:
- // what to trigger
- // movedir:
- // for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter)
-
- self.movedir_x -= 1; // map to tuba instrument numbers
-}
-
-void relay_activators_use()
-{
- entity trg, os;
-
- os = self;
-
- for(trg = world; (trg = find(trg, targetname, os.target)); )
- {
- self = trg;
- if (trg.setactive)
- trg.setactive(os.cnt);
- else
- {
- //bprint("Not using setactive\n");
- if(os.cnt == ACTIVE_TOGGLE)
- if(trg.active == ACTIVE_ACTIVE)
- trg.active = ACTIVE_NOT;
- else
- trg.active = ACTIVE_ACTIVE;
- else
- trg.active = os.cnt;
- }
- }
- self = os;
-}
-
-void spawnfunc_relay_activate()
-{
- self.cnt = ACTIVE_ACTIVE;
- self.use = relay_activators_use;
-}
-
-void spawnfunc_relay_deactivate()
-{
- self.cnt = ACTIVE_NOT;
- self.use = relay_activators_use;
-}
-
-void spawnfunc_relay_activatetoggle()
-{
- self.cnt = ACTIVE_TOGGLE;
- self.use = relay_activators_use;
-}
-
-void spawnfunc_target_changelevel_use()
-{
- if(self.gametype != "")
- MapInfo_SwitchGameType(MapInfo_Type_FromString(self.gametype));
-
- if (self.chmap == "")
- localcmd("endmatch\n");
- else
- localcmd(strcat("changelevel ", self.chmap, "\n"));
-}
-
-void spawnfunc_target_changelevel()
-{
- self.use = spawnfunc_target_changelevel_use;
-}
+++ /dev/null
-#ifndef G_TRIGGERS_H
-#define G_TRIGGERS_H
-
-void SUB_DontUseTargets();
-
-
-void() SUB_UseTargets;
-
-void DelayThink();
-
-/*
-==============================
-SUB_UseTargets
-
-the global "activator" should be set to the entity that initiated the firing.
-
-If self.delay is set, a DelayedUse entity will be created that will actually
-do the SUB_UseTargets after that many seconds have passed.
-
-Centerprints any self.message to the activator.
-
-Removes all entities with a targetname that match self.killtarget,
-and removes them, so some events can remove other triggers.
-
-Search for (string)targetname in all entities that
-match (string)self.target and call their .use function
-
-==============================
-*/
-void SUB_UseTargets();
-
-
-//=============================================================================
-
-const float SPAWNFLAG_NOMESSAGE = 1;
-const float SPAWNFLAG_NOTOUCH = 1;
-
-// the wait time has passed, so set back up for another activation
-void multi_wait();
-
-
-// the trigger was just touched/killed/used
-// self.enemy should be set to the activator so it can be held through a delay
-// so wait for the delay time before firing
-void multi_trigger();
-
-void multi_use();
-
-void multi_touch();
-
-void multi_eventdamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
-
-void multi_reset();
-
-/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
-Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
-If "delay" is set, the trigger waits some time after activating before firing.
-"wait" : Seconds between triggerings. (.2 default)
-If notouch is set, the trigger is only fired by other entities, not by touching.
-NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
-sounds
-1) secret
-2) beep beep
-3) large switch
-4)
-set "message" to text string
-*/
-void spawnfunc_trigger_multiple();
-
-
-/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
-Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
-"targetname". If "health" is set, the trigger must be killed to activate.
-If notouch is set, the trigger is only fired by other entities, not by touching.
-if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
-if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
-sounds
-1) secret
-2) beep beep
-3) large switch
-4)
-set "message" to text string
-*/
-void spawnfunc_trigger_once();
-
-//=============================================================================
-
-/*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
-This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
-*/
-void spawnfunc_trigger_relay();
-
-void delay_use();
-
-void delay_reset();
-
-void spawnfunc_trigger_delay();
-
-//=============================================================================
-
-
-void counter_use();
-
-void counter_reset();
-
-/*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage
-Acts as an intermediary for an action that takes multiple inputs.
-
-If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
-
-After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
-*/
-void spawnfunc_trigger_counter();
-
-void trigger_hurt_use();
-
-.float triggerhurttime;
-void trigger_hurt_touch();
-
-/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
-Any object touching this will be hurt
-set dmg to damage amount
-defalt dmg = 5
-*/
-.entity trigger_hurt_next;
-entity trigger_hurt_last;
-entity trigger_hurt_first;
-void spawnfunc_trigger_hurt();
-
-float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end);
-
-//////////////////////////////////////////////////////////////
-//
-//
-//
-//Trigger heal --a04191b92fbd93aa67214ef7e72d6d2e
-//
-//////////////////////////////////////////////////////////////
-
-.float triggerhealtime;
-void trigger_heal_touch();
-
-void spawnfunc_trigger_heal();
-
-
-//////////////////////////////////////////////////////////////
-//
-//
-//
-//End trigger_heal
-//
-//////////////////////////////////////////////////////////////
-
-.entity trigger_gravity_check;
-void trigger_gravity_remove(entity own);
-void trigger_gravity_check_think();
-
-void trigger_gravity_use();
-
-void trigger_gravity_touch();
-
-void spawnfunc_trigger_gravity();
-
-//=============================================================================
-
-// TODO add a way to do looped sounds with sound(); then complete this entity
-.float volume, atten;
-void target_speaker_use_off();
-void target_speaker_use_activator();
-void target_speaker_use_on();
-void target_speaker_use_off();
-void target_speaker_reset();
-
-void spawnfunc_target_speaker();
-
-
-void spawnfunc_func_stardust();
-
-.string bgmscript;
-.float bgmscriptattack;
-.float bgmscriptdecay;
-.float bgmscriptsustain;
-.float bgmscriptrelease;
-float pointparticles_SendEntity(entity to, float fl);
-
-void pointparticles_use();
-
-void pointparticles_think();
-
-void pointparticles_reset();
-
-void spawnfunc_func_pointparticles();
-
-void spawnfunc_func_sparks();
-
-float rainsnow_SendEntity(entity to, float sf);
-
-/*QUAKED spawnfunc_func_rain (0 .5 .8) ?
-This is an invisible area like a trigger, which rain falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-void spawnfunc_func_rain();
-
-
-/*QUAKED spawnfunc_func_snow (0 .5 .8) ?
-This is an invisible area like a trigger, which snow falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-void spawnfunc_func_snow();
-
-.float modelscale;
-void misc_laser_aim();
-
-void misc_laser_init();
-
-.entity pusher;
-void misc_laser_think();
-
-float laser_SendEntity(entity to, float fl);
-
-/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
-Any object touching the beam will be hurt
-Keys:
-"target"
- spawnfunc_target_position where the laser ends
-"mdl"
- name of beam end effect to use
-"colormod"
- color of the beam (default: red)
-"dmg"
- damage per second (-1 for a laser that kills immediately)
-*/
-void laser_use();
-
-void laser_reset();
-
-void spawnfunc_misc_laser();
-
-// tZorks trigger impulse / gravity
-.float radius;
-.float falloff;
-.float strength;
-.float lastpushtime;
-
-// targeted (directional) mode
-void trigger_impulse_touch1();
-
-// Directionless (accelerator/decelerator) mode
-void trigger_impulse_touch2();
-
-// Spherical (gravity/repulsor) mode
-void trigger_impulse_touch3();
-
-/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
--------- KEYS --------
-target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
- If not, this trigger acts like a damper/accelerator field.
-
-strength : This is how mutch force to add in the direction of .target each second
- when .target is set. If not, this is hoe mutch to slow down/accelerate
- someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
-
-radius : If set, act as a spherical device rather then a liniar one.
-
-falloff : 0 = none, 1 = liniar, 2 = inverted liniar
-
--------- NOTES --------
-Use a brush textured with common/origin in the trigger entity to determine the origin of the force
-in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
-*/
-
-void spawnfunc_trigger_impulse();
-
-/*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
-"Flip-flop" trigger gate... lets only every second trigger event through
-*/
-void flipflop_use();
-
-void spawnfunc_trigger_flipflop();
-
-/*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
-"Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
-*/
-void monoflop_use();
-void monoflop_fixed_use();
-
-void monoflop_think();
-
-void monoflop_reset();
-
-void spawnfunc_trigger_monoflop();
-
-void multivibrator_send();
-
-void multivibrator_toggle();
-
-void multivibrator_reset();
-
-/*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
-"Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
--------- KEYS --------
-target: trigger all entities with this targetname when it goes off
-targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
-phase: offset of the timing
-wait: "on" cycle time (default: 1)
-respawntime: "off" cycle time (default: same as wait)
--------- SPAWNFLAGS --------
-START_ON: assume it is already turned on (when targeted)
-*/
-void spawnfunc_trigger_multivibrator();
-
-
-void follow_init();
-
-void spawnfunc_misc_follow();
-
-
-
-void gamestart_use();
-
-void spawnfunc_trigger_gamestart();
-
-
-
-
-.entity voicescript; // attached voice script
-.float voicescript_index; // index of next voice, or -1 to use the randomized ones
-.float voicescript_nextthink; // time to play next voice
-.float voicescript_voiceend; // time when this voice ends
-
-void target_voicescript_clear(entity pl);
-
-void target_voicescript_use();
-
-void target_voicescript_next(entity pl);
-
-void spawnfunc_target_voicescript();
-
-
-
-void trigger_relay_teamcheck_use();
-
-void trigger_relay_teamcheck_reset();
-
-void spawnfunc_trigger_relay_teamcheck();
-
-
-
-void trigger_disablerelay_use();
-
-void spawnfunc_trigger_disablerelay();
-
-float magicear_matched;
-float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
-string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin);
-
-entity magicears;
-string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin);
-
-void spawnfunc_trigger_magicear();
-
-void relay_activators_use();
-
-void spawnfunc_relay_activate();
-
-void spawnfunc_relay_deactivate();
-
-void spawnfunc_relay_activatetoggle();
-
-.string chmap, gametype;
-void spawnfunc_target_changelevel_use();
-
-void spawnfunc_target_changelevel();
-#endif
#include "g_violence.qh"
+#include "_all.qh"
-float Violence_GibSplash_SendEntity(entity to, float sf)
+float Violence_GibSplash_SendEntity(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_GIBSPLASH);
WriteByte(MSG_ENTITY, self.state); // actually type
#ifndef G_VIOLENCE_H
#define G_VIOLENCE_H
-float Violence_GibSplash_SendEntity(entity to, float sf);
+float Violence_GibSplash_SendEntity(entity to, int sf);
// TODO maybe convert this to a TE?
void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker);
#include "g_world.qh"
-
+#include "_all.qh"
+
+#include "anticheat.qh"
+#include "antilag.qh"
+#include "bot/bot.qh"
+#include "campaign.qh"
+#include "cheats.qh"
+#include "cl_client.qh"
+#include "command/common.qh"
+#include "command/getreplies.qh"
+#include "command/sv_cmd.qh"
+#include "command/vote.qh"
+#include "g_hook.qh"
+#include "ipban.qh"
+#include "mapvoting.qh"
+#include "mutators/mutators_include.qh"
+#include "race.qh"
+#include "scores.qh"
+#include "teamplay.qh"
+#include "waypointsprites.qh"
+#include "weapons/weaponstats.qh"
#include "../common/buffs.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../common/constants.qh"
- #include "../common/stats.qh"
- #include "../common/teams.qh"
- #include "../common/util.qh"
- #include "../common/monsters/sv_monsters.qh"
- #include "../common/weapons/weapons.qh"
- #include "weapons/weaponstats.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "mutators/mutators_include.qh"
- #include "campaign.qh"
- #include "../common/mapinfo.qh"
- #include "command/common.qh"
- #include "command/vote.qh"
- #include "command/getreplies.qh"
- #include "command/sv_cmd.qh"
- #include "anticheat.qh"
- #include "cheats.qh"
- #include "../common/playerstats.qh"
- #include "g_hook.qh"
- #include "scores.qh"
- #include "mapvoting.qh"
- #include "ipban.qh"
- #include "race.qh"
- #include "antilag.qh"
- #include "secret.qh"
-#endif
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/mapinfo.qh"
+#include "../common/monsters/all.qh"
+#include "../common/monsters/sv_monsters.qh"
+#include "../common/notifications.qh"
+#include "../common/playerstats.qh"
+#include "../common/stats.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
+#include "../common/items/all.qh"
+#include "../common/weapons/all.qh"
const float LATENCY_THINKRATE = 10;
.float latency_sum;
float world_initialized;
string GetGametype();
-void GotoNextMap(float reinit);
void ShuffleMaplist();
-float(float reinit) DoNextMapOverride;
void SetDefaultAlpha()
{
BADCVAR("g_configversion");
BADCVAR("g_maplist_index");
BADCVAR("halflifebsp");
+ BADCVAR("sv_mapformat_is_quake2");
+ BADCVAR("sv_mapformat_is_quake3");
BADPREFIX("sv_world");
// client
BADCVAR("g_domination_default_teams");
BADCVAR("g_freezetag");
BADCVAR("g_freezetag_teams");
+ BADCVAR("g_invasion_teams");
BADCVAR("g_keepaway");
BADCVAR("g_keyhunt");
BADCVAR("g_keyhunt_teams");
BADCVAR("g_ca_teams_override");
BADCVAR("g_ctf_ignore_frags");
BADCVAR("g_domination_point_limit");
+ BADCVAR("g_domination_teams_override");
BADCVAR("g_freezetag_teams_override");
BADCVAR("g_friendlyfire");
BADCVAR("g_fullbrightitems");
BADCVAR("g_nexball_goallimit");
BADCVAR("g_powerups");
BADCVAR("g_start_delay");
+ BADCVAR("g_tdm_teams_override");
BADCVAR("g_warmup");
BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
BADCVAR("hostname");
}
entity randomseed;
-float RandomSeed_Send(entity to, float sf)
+float RandomSeed_Send(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
WriteShort(MSG_ENTITY, self.cnt);
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
void ClientInit_Spawn();
void WeaponStats_Init();
void WeaponStats_Shutdown();
+void Physics_AddStats();
void spawnfunc_worldspawn (void)
{
- float fd, l, i, j, n;
+ float fd, l, j, n;
string s;
cvar = cvar_normal;
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
// character set: ASCII 33-126 without the following characters: : ; ' " \ $
if(autocvar_sv_eventlog)
{
- s = sprintf("%d.%s.%06d", ftos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000));
+ 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));
addstat(STAT_FROZEN, AS_INT, frozen);
addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
- // g_movementspeed hack
- addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
- addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
- addstat(STAT_MOVEVARS_AIRACCEL_QW, AS_FLOAT, stat_sv_airaccel_qw);
- addstat(STAT_MOVEVARS_AIRSTRAFEACCEL_QW, AS_FLOAT, stat_sv_airstrafeaccel_qw);
+ // physics
+ Physics_AddStats();
+
+ // new properties
+ addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_sv_jumpvelocity);
+ addstat(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, AS_FLOAT, stat_sv_airaccel_qw_stretchfactor);
+ addstat(STAT_MOVEVARS_MAXAIRSTRAFESPEED, AS_FLOAT, stat_sv_maxairstrafespeed);
+ addstat(STAT_MOVEVARS_MAXAIRSPEED, AS_FLOAT, stat_sv_maxairspeed);
+ addstat(STAT_MOVEVARS_AIRSTRAFEACCELERATE, AS_FLOAT, stat_sv_airstrafeaccelerate);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL, AS_FLOAT, stat_sv_warsowbunny_turnaccel);
+ addstat(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, AS_FLOAT, stat_sv_airaccel_sideways_friction);
+ addstat(STAT_MOVEVARS_AIRCONTROL, AS_FLOAT, stat_sv_aircontrol);
+ addstat(STAT_MOVEVARS_AIRCONTROL_POWER, AS_FLOAT, stat_sv_aircontrol_power);
+ addstat(STAT_MOVEVARS_AIRCONTROL_PENALTY, AS_FLOAT, stat_sv_aircontrol_penalty);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, AS_FLOAT, stat_sv_warsowbunny_airforwardaccel);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED, AS_FLOAT, stat_sv_warsowbunny_topspeed);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_ACCEL, AS_FLOAT, stat_sv_warsowbunny_accel);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, AS_FLOAT, stat_sv_warsowbunny_backtosideratio);
+ addstat(STAT_MOVEVARS_FRICTION, AS_FLOAT, stat_sv_friction);
+ addstat(STAT_MOVEVARS_ACCELERATE, AS_FLOAT, stat_sv_accelerate);
+ addstat(STAT_MOVEVARS_STOPSPEED, AS_FLOAT, stat_sv_stopspeed);
+ addstat(STAT_MOVEVARS_AIRACCELERATE, AS_FLOAT, stat_sv_airaccelerate);
+ addstat(STAT_MOVEVARS_AIRSTOPACCELERATE, AS_FLOAT, stat_sv_airstopaccelerate);
// secrets
addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total);
maplist_reply = strzone(getmaplist());
lsmaps_reply = strzone(getlsmaps());
monsterlist_reply = strzone(getmonsterlist());
- for(i = 0; i < 10; ++i)
+ for(int i = 0; i < 10; ++i)
{
s = getrecords(i);
if (s)
{
s = "";
n = tokenize_console(cvar_string("sv_curl_serverpackages"));
- for(i = 0; i < n; ++i)
+ for(int i = 0; i < n; ++i)
if(substring(argv(i), -18, -1) != "-serverpackage.txt")
if(substring(argv(i), -14, -1) != ".serverpackage") // OLD legacy
s = strcat(s, " ", argv(i));
if(fd >= 0)
{
j = search_getsize(fd);
- for(i = 0; i < j; ++i)
+ for(int i = 0; i < j; ++i)
s = strcat(s, " ", search_getfilename(fd, i));
search_end(fd);
}
if(fd >= 0)
{
j = search_getsize(fd);
- for(i = 0; i < j; ++i)
+ for(int i = 0; i < j; ++i)
s = strcat(s, " ", search_getfilename(fd, i));
search_end(fd);
}
{
entity head;
FOR_EACH_PLAYER(head)
- head.winning = (head.field == value);
+ head.winning = (head.(field) == value);
}
// set the .winning flag for those players with a given field value
{
entity head;
FOR_EACH_PLAYER(head)
- if(head.field == value)
+ if (head.(field) == value)
head.winning = 1;
}
if(have_team_spawns <= 0)
return WINNING_NO;
- if(autocvar_g_spawn_useallspawns <= 0)
+ if(!autocvar_g_spawn_useallspawns)
return WINNING_NO;
if(!some_spawn_has_been_used)
Exit deathmatch games upon conditions
============
*/
-void ReadyRestart();
void CheckRules_World()
{
float timelimit;
void CheckRules_Player();
void IntermissionThink();
+void GotoNextMap(float reinit);
+void ReadyRestart();
+
+void DumpStats(float final);
+float Map_IsRecent(string m);
+string GetNextMap();
+void ShuffleMaplist();
+void Map_Goto_SetStr(string nextmapname);
+void Map_Goto(float reinit);
+float DoNextMapOverride(float reinit);
+void CheckRules_World();
#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "autocvars.qh"
- #include "defs.qh"
- #include "command/banning.qh"
- #include "ipban.qh"
-#endif
+#include "ipban.qh"
+#include "_all.qh"
+
+#include "autocvars.qh"
+#include "command/banning.qh"
+#include "defs.qh"
+#include "../common/constants.qh"
+#include "../common/util.qh"
+#include "../dpdefs/dpextensions.qh"
+#include "../dpdefs/progsdefs.qh"
/*
* Protocol of online ban list:
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/util.qh"
- #include "../common/monsters/monsters.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "item_key.qh"
-#endif
+#include "item_key.qh"
+#include "_all.qh"
+
+#include "../common/triggers/subs.qh"
+#include "../common/monsters/all.qh"
+#include "../common/notifications.qh"
+#include "../common/util.qh"
+#include "../warpzonelib/util_server.qh"
/*
TODO:
- should keys have a trigger?
*/
-bool item_keys_usekey(entity l, entity p) {
+bool item_keys_usekey(entity l, entity p)
+{
float valid = l.itemkeys & p.itemkeys;
if (!valid) {
}
string item_keys_keylist(float keylist) {
- float base, l;
- string n;
-
// no keys
if (!keylist)
return "";
if ((keylist & (keylist-1)) != 0)
return strcat("the ", item_keys_names[lowestbit(keylist)]);
- n = "";
- base = 0;
+ string n = "";
+ int base = 0;
while (keylist) {
- l = lowestbit(keylist);
+ int l = lowestbit(keylist);
if (n)
n = strcat(n, ", the ", item_keys_names[base + l]);
else
self.itemkeys = ITEM_KEY_BIT(0);
spawnfunc_item_key();
};
-
-
-/*
-================================
-trigger_keylock
-================================
-*/
-
-/**
- * trigger givent targets
- */
-void trigger_keylock_trigger(string s) {
- entity stemp = self;
- entity otemp = other;
- entity atemp = activator;
-
- entity t;
- for(t = world; (t = find(t, targetname, s)); )
- if (t.use) {
- self = t;
- other = stemp;
- activator = atemp;
- self.use();
- }
-
- self = stemp;
- other = otemp;
- activator = atemp;
-};
-
-/**
- * kill killtarget of trigger keylock.
- */
-void trigger_keylock_kill(string s) {
- entity t;
- for(t = world; (t = find(t, targetname, s)); )
- remove(t);
-};
-
-void trigger_keylock_touch(void) {
- bool key_used = false;
- bool started_delay = false;
-
- // only player may trigger the lock
- if (!IS_PLAYER(other))
- return;
-
-
- // check silver key
- if (self.itemkeys)
- key_used = item_keys_usekey(self, other);
-
- activator = other;
-
- if (self.itemkeys) {
- // at least one of the keys is missing
- if (key_used) {
- // one or more keys were given, but others are still missing!
- play2(other, self.noise1);
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(self.itemkeys));
- other.key_door_messagetime = time + 2;
- } else if (other.key_door_messagetime <= time) {
- // no keys were given
- play2(other, self.noise2);
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(self.itemkeys));
- other.key_door_messagetime = time + 2;
- }
-
- // trigger target2
- if (self.delay <= time || started_delay == true)
- if (self.target2) {
- trigger_keylock_trigger(self.target2);
- started_delay = true;
- self.delay = time + self.wait;
- }
- } else {
- // all keys were given!
- play2(other, self.noise);
- centerprint(other, self.message);
-
- if (self.target)
- trigger_keylock_trigger(self.target);
-
- if (self.killtarget)
- trigger_keylock_kill(self.killtarget);
-
- remove(self);
- }
-
-};
-
-/*QUAKED trigger_keylock (.0 .5 .8) ?
-Keylock trigger. Must target other entities.
-This trigger will trigger target entities when all required keys are provided.
--------- KEYS --------
-itemkeys: A bit field with key IDs that are needed to open this lock.
-sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (3 is default)
-target: trigger all entities with this targetname when triggered and all keys have been given to it, then remove this trigger
-target2: trigger all entities with this targetname when triggered without giving it all the required keys.
-killtarget: remove all entities with this targetname when triggered with all the needed keys.
-message: print this message to the player who activated the trigger when all needed keys have been given.
-message2: print this message to the player who activated the trigger when not all of the needed keys have been given.
-noise: sound to play when lock gets unlocked (default: see sounds)
-noise1: sound to play when only some of the needed key were used but not all (default: misc/decreasevalue.wav)
-noise2: sound to play when a key is missing (default: misc/talk.wav)
-wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4.
----------NOTES----------
-If spawned without any key specified in itemkeys, this trigger will display an error and remove itself.
-message2 and noise2 will be resent to the player every 2 seconds while he is in the trigger zone.
-*/
-void spawnfunc_trigger_keylock(void) {
- if (!self.itemkeys) {
- remove(self);
- return;
- }
-
- // set unlocked message
- if (self.message == "")
- self.message = "Unlocked!";
-
- // set default unlock noise
- if (self.noise == "") {
- if (self.sounds == 1)
- self.noise = "misc/secret.wav";
- else if (self.sounds == 2)
- self.noise = "misc/talk.wav";
- else //if (self.sounds == 3) {
- self.noise = "misc/trigger1.wav";
- }
-
- // set default use key sound
- if (self.noise1 == "")
- self.noise1 = "misc/decreasevalue.wav";
-
- // set closed sourd
- if (self.noise2 == "")
- self.noise2 = "misc/talk.wav";
-
- // delay between triggering message2 and trigger2
- if (!self.wait)
- self.wait = 5;
-
- // precache sounds
- precache_sound(self.noise);
- precache_sound(self.noise1);
- precache_sound(self.noise2);
-
- EXACTTRIGGER_INIT;
-
- self.touch = trigger_keylock_touch;
-};
-
-
/**
* list of key names.
*/
+#ifdef SVQC
string item_keys_names[ITEM_KEY_MAX];
/**
*/
string item_keys_keylist(float keylist);
#endif
+
+#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/mapinfo.qh"
- #include "command/getreplies.qh"
- #include "command/cmd.qh"
- #include "../common/playerstats.qh"
- #include "mapvoting.qh"
-#endif
-
-float GameTypeVote_AvailabilityStatus(string gtname)
+#include "mapvoting.qh"
+#include "_all.qh"
+
+#include "g_world.qh"
+#include "command/cmd.qh"
+#include "command/getreplies.qh"
+#include "../common/constants.qh"
+#include "../common/mapinfo.qh"
+#include "../common/playerstats.qh"
+#include "../common/util.qh"
+
+
+// definitions
+
+float mapvote_nextthink;
+float mapvote_keeptwotime;
+float mapvote_timeout;
+string mapvote_message;
+const float MAPVOTE_SCREENSHOT_DIRS_COUNT = 4;
+string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT];
+float mapvote_screenshot_dirs_count;
+
+float mapvote_count;
+float mapvote_count_real;
+string mapvote_maps[MAPVOTE_COUNT];
+float mapvote_maps_screenshot_dir[MAPVOTE_COUNT];
+string mapvote_maps_pakfile[MAPVOTE_COUNT];
+float mapvote_maps_suggested[MAPVOTE_COUNT];
+string mapvote_suggestions[MAPVOTE_COUNT];
+float mapvote_suggestion_ptr;
+float mapvote_voters;
+float mapvote_selections[MAPVOTE_COUNT];
+float mapvote_maps_flags[MAPVOTE_COUNT];
+float mapvote_run;
+float mapvote_detail;
+float mapvote_abstain;
+.float mapvote;
+
+entity mapvote_ent;
+
+/**
+ * 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)
{
- float type = MapInfo_Type_FromString(gtname);
+ float type = MapInfo_Type_FromString(type_name);
+ if ( type == 0 )
+ type = MapInfo_Type_FromString(cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_type")));
+ return type;
+}
+
+int GameTypeVote_AvailabilityStatus(string type_name)
+{
+ int flag = GTV_FORBIDDEN;
+
+ float type = MapInfo_Type_FromString(type_name);
+ if ( type == 0 )
+ {
+ type = MapInfo_Type_FromString(cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_type")));
+ flag |= GTV_CUSTOM;
+ }
+
if( type == 0 )
- return GTV_FORBIDDEN;
+ return flag;
if ( autocvar_nextmap != "" )
{
if ( !MapInfo_Get_ByName(autocvar_nextmap, false, 0) )
- return GTV_FORBIDDEN;
+ return flag;
if (!(MapInfo_Map_supportedGametypes & type))
- return GTV_FORBIDDEN;
+ return flag;
}
- return GTV_AVAILABLE;
+ return flag | GTV_AVAILABLE;
}
float GameTypeVote_GetMask()
n = min(MAPVOTE_COUNT, n);
gametype_mask = 0;
for(j = 0; j < n; ++j)
- gametype_mask |= MapInfo_Type_FromString(argv(j));
+ gametype_mask |= GameTypeVote_Type_FromString(argv(j));
return gametype_mask;
}
mapvote_maps_screenshot_dir[mapvote_count] = i;
mapvote_maps_pakfile[mapvote_count] = strzone(pakfile);
- mapvote_maps_availability[mapvote_count] = GTV_AVAILABLE;
+ mapvote_maps_flags[mapvote_count] = GTV_AVAILABLE;
mapvote_count += 1;
}
float mask,power;
mask = 0;
for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
- if(mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if(mapvote_maps_flags[i] & GTV_AVAILABLE )
mask |= power;
if(mapvote_count < 8)
else
{
for ( i = 0; i < mapvote_count; ++i )
- WriteByte(MSG_ENTITY, mapvote_maps_availability[i]);
+ WriteByte(MSG_ENTITY, mapvote_maps_flags[i]);
+ }
+}
+
+/*
+ * Sends a single map vote option to the client
+ */
+void MapVote_SendOption(int i)
+{
+ // abstain
+ if(mapvote_abstain && i == mapvote_count - 1)
+ {
+ WriteString(MSG_ENTITY, ""); // abstain needs no text
+ WriteString(MSG_ENTITY, ""); // abstain needs no pack
+ WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir
+ }
+ else
+ {
+ WriteString(MSG_ENTITY, mapvote_maps[i]);
+ WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]);
+ WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]);
}
}
-float MapVote_SendEntity(entity to, float sf)
+/*
+ * Sends a single gametype vote option to the client
+ */
+void GameTypeVote_SendOption(int i)
+{
+ // abstain
+ if(mapvote_abstain && i == mapvote_count - 1)
+ {
+ WriteString(MSG_ENTITY, ""); // abstain needs no text
+ WriteByte(MSG_ENTITY, GTV_AVAILABLE);
+ }
+ else
+ {
+ string type_name = mapvote_maps[i];
+ WriteString(MSG_ENTITY, type_name);
+ WriteByte(MSG_ENTITY, mapvote_maps_flags[i]);
+ if ( mapvote_maps_flags[i] & GTV_CUSTOM )
+ {
+ WriteString(MSG_ENTITY, cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_name")));
+ WriteString(MSG_ENTITY, cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_description")));
+ }
+ }
+}
+
+float MapVote_SendEntity(entity to, int sf)
{
float i;
}
else if ( autocvar_sv_vote_gametype )
{
- // map vote but gametype has been chosen via voting screen
+ // map vote but gametype has been chosen via voting screen
WriteByte(MSG_ENTITY, 2);
WriteString(MSG_ENTITY, MapInfo_Type_ToText(MapInfo_CurrentGametype()));
}
MapVote_WriteMask();
+ // Send data for the vote options
for(i = 0; i < mapvote_count; ++i)
{
- if(mapvote_abstain && i == mapvote_count - 1)
- {
- WriteString(MSG_ENTITY, ""); // abstain needs no text
- WriteString(MSG_ENTITY, ""); // abstain needs no pack
- WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir
- WriteByte(MSG_ENTITY, GTV_AVAILABLE);
- }
+ if(gametypevote)
+ GameTypeVote_SendOption(i);
else
- {
- WriteString(MSG_ENTITY, mapvote_maps[i]);
- WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]);
- WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]);
- WriteByte(MSG_ENTITY, mapvote_maps_availability[i]);
- }
+ MapVote_SendOption(i);
}
}
{
if(mapvote_detail)
for(i = 0; i < mapvote_count; ++i)
- if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
WriteByte(MSG_ENTITY, mapvote_selections[i]);
WriteByte(MSG_ENTITY, to.mapvote);
result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::");
didntvote = mapvote_voters;
for(i = 0; i < mapvote_count; ++i)
- if(mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if(mapvote_maps_flags[i] & GTV_AVAILABLE )
{
didntvote -= mapvote_selections[i];
if(i != mappos)
float i;
for(i = 0; i < mapvote_count; ++i)
- if( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if( mapvote_maps_flags[i] & GTV_AVAILABLE )
{
//dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
mapvote_selections[i] = 0;
currentPlace = 0;
currentVotes = -1;
for(i = 0; i < mapvote_count_real; ++i)
- if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
{
RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
if ( gametypevote && mapvote_maps[i] == MapInfo_Type_ToString(MapInfo_CurrentGametype()) )
RandomSelection_Init();
for(i = 0; i < mapvote_count_real; ++i)
if(i != firstPlace)
- if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
secondPlace = RandomSelection_chosen_float;
secondPlaceVotes = RandomSelection_best_priority;
result = strcat(result, ":", ftos(mapvote_selections[i]));
if(i < mapvote_count_real)
{
- mapvote_maps_availability[i] = GTV_FORBIDDEN;
+ mapvote_maps_flags[i] &= ~GTV_AVAILABLE;
}
}
}
}
// clear possibly invalid votes
- if ( mapvote_maps_availability[other.mapvote-1] != GTV_AVAILABLE )
+ if ( !(mapvote_maps_flags[other.mapvote-1] & GTV_AVAILABLE) )
other.mapvote = 0;
// use impulses as new vote
if(other.impulse >= 1 && other.impulse <= mapvote_count)
- if( mapvote_maps_availability[other.impulse - 1] == GTV_AVAILABLE )
+ if( mapvote_maps_flags[other.impulse - 1] & GTV_AVAILABLE )
{
other.mapvote = other.impulse;
MapVote_TouchVotes(other);
if(!gametypevote || gametypevote_finished)
return false;
- if ( !GameTypeVote_SetGametype(MapInfo_Type_FromString(mapvote_maps[pos])) )
+ if ( !GameTypeVote_SetGametype(GameTypeVote_Type_FromString(mapvote_maps[pos])) )
{
dprint("Selected gametype is not supported by any map");
}
float GameTypeVote_AddVotable(string nextMode)
{
float j;
- if ( nextMode == "" || MapInfo_Type_FromString(nextMode) == 0 )
+ if ( nextMode == "" || GameTypeVote_Type_FromString(nextMode) == 0 )
return false;
for(j = 0; j < mapvote_count; ++j)
if(mapvote_maps[j] == nextMode)
mapvote_maps_screenshot_dir[mapvote_count] = 0;
mapvote_maps_pakfile[mapvote_count] = strzone("");
- mapvote_maps_availability[mapvote_count] = GameTypeVote_AvailabilityStatus(nextMode);
+ mapvote_maps_flags[mapvote_count] = GameTypeVote_AvailabilityStatus(nextMode);
mapvote_count += 1;
for(j = 0; j < n; ++j)
{
if ( GameTypeVote_AddVotable(argv(j)) )
- if ( mapvote_maps_availability[j] == GTV_AVAILABLE )
+ if ( mapvote_maps_flags[j] & GTV_AVAILABLE )
{
really_available++;
which_available = j;
void MapVote_Start();
void MapVote_Spawn();
void MapVote_Think();
+void MapVote_SendPicture(float id);
float GameTypeVote_Start();
float GameTypeVote_Finished(float pos);
string GameTypeVote_MapInfo_FixName(string m);
-// definitions
float gametypevote;
string getmapname_stored;
float mapvote_initialized;
-
-float mapvote_nextthink;
-float mapvote_keeptwotime;
-float mapvote_timeout;
-string mapvote_message;
-const float MAPVOTE_SCREENSHOT_DIRS_COUNT = 4;
-string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT];
-float mapvote_screenshot_dirs_count;
-
-float mapvote_count;
-float mapvote_count_real;
-string mapvote_maps[MAPVOTE_COUNT];
-float mapvote_maps_screenshot_dir[MAPVOTE_COUNT];
-string mapvote_maps_pakfile[MAPVOTE_COUNT];
-float mapvote_maps_suggested[MAPVOTE_COUNT];
-string mapvote_suggestions[MAPVOTE_COUNT];
-float mapvote_suggestion_ptr;
-float mapvote_voters;
-float mapvote_selections[MAPVOTE_COUNT];
-float mapvote_maps_availability[MAPVOTE_COUNT];
-float mapvote_run;
-float mapvote_detail;
-float mapvote_abstain;
-.float mapvote;
-
-entity mapvote_ent;
#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "miscfunctions.qh"
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/playerstats.qh"
- #include "../warpzonelib/anglestransform.qh"
- #include "../warpzonelib/server.qh"
- #include "../common/constants.qh"
- #include "../common/teams.qh"
- #include "../common/util.qh"
- #include "../common/urllib.qh"
- #include "../common/command/generic.qh"
- #include "../common/weapons/weapons.qh"
- #include "weapons/accuracy.qh"
- #include "weapons/csqcprojectile.qh"
- #include "weapons/selection.qh"
- #include "t_items.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "../common/deathtypes.qh"
- #include "mutators/mutators_include.qh"
- #include "tturrets/include/turrets_early.qh"
- #include "../common/mapinfo.qh"
- #include "command/common.qh"
- #include "../csqcmodellib/sv_model.qh"
- #include "ipban.qh"
-#endif
+#include "miscfunctions.qh"
+#include "_all.qh"
+#include "antilag.qh"
+#include "command/common.qh"
+#include "constants.qh"
+#include "g_hook.qh"
+#include "ipban.qh"
+#include "mutators/mutators_include.qh"
+#include "tturrets/include/turrets_early.qh"
+#include "t_items.qh"
+#include "weapons/accuracy.qh"
+#include "weapons/csqcprojectile.qh"
+#include "weapons/selection.qh"
+#include "../common/command/generic.qh"
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/mapinfo.qh"
+#include "../common/notifications.qh"
+#include "../common/playerstats.qh"
+#include "../common/teams.qh"
+#include "../common/triggers/subs.qh"
+#include "../common/urllib.qh"
+#include "../common/util.qh"
+#include "../common/weapons/all.qh"
+#include "../csqcmodellib/sv_model.qh"
+#include "../warpzonelib/anglestransform.qh"
+#include "../warpzonelib/server.qh"
void crosshair_trace(entity pl)
{
void GameLogEcho(string s)
{
string fn;
- float matches;
+ int matches;
if (autocvar_sv_eventlog_files)
{
{
logfile_open = true;
matches = autocvar_sv_eventlog_files_counter + 1;
- cvar_set("sv_eventlog_files_counter", ftos(matches));
+ cvar_set("sv_eventlog_files_counter", itos(matches));
fn = ftos(matches);
if (strlen(fn) < 8)
fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
return nearest_entity[0];
}
-void spawnfunc_target_location()
-{
- self.classname = "target_location";
- // location name in netname
- // eventually support: count, teamgame selectors, line of sight?
-}
-
-void spawnfunc_info_location()
-{
- self.classname = "target_location";
- self.message = self.netname;
-}
-
string NearestLocation(vector p)
{
entity loc;
{
if (f < 0)
{
- if (self.field)
- strunzone(self.field);
- self.field = string_null;
+ if (self.(field))
+ strunzone(self.(field));
+ self.(field) = string_null;
}
else if (f > 0)
{
if (thisname == name)
{
- if (self.field)
- strunzone(self.field);
- self.field = strzone(argv(f + 1));
+ if (self.(field))
+ strunzone(self.(field));
+ self.(field) = strzone(argv(f + 1));
}
}
else
if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
if (thisname == name)
{
- string s;
- s = func(strcat1(self.field));
- if (s != self.field)
+ string s = func(strcat1(self.(field)));
+ if (s != self.(field))
{
- strunzone(self.field);
- self.field = strzone(s);
+ strunzone(self.(field));
+ self.(field) = strzone(s);
}
}
}
else if (f > 0)
{
if (thisname == name)
- self.field = stof(argv(f + 1));
+ self.(field) = stof(argv(f + 1));
}
else
stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
{
if (thisname == name)
{
- if(!self.field)
+ if (!self.(field))
{
- self.field = stof(argv(f + 1));
- if(!self.field)
- self.field = -1;
+ self.(field) = stof(argv(f + 1));
+ if (!self.(field))
+ self.(field) = -1;
}
}
}
else
{
- if(!self.field)
+ if (!self.(field))
stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
}
}
GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
GetCvars_handleFloat(s, f, cvar_cl_jetpack_jump, "cl_jetpack_jump");
GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
+ GetCvars_handleString(s, f, cvar_cl_physics, "cl_physics");
GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
s = cvar_string("g_weaponarena");
if (s == "0" || s == "")
{
- if(g_ca)
+ if(g_ca || g_freezetag)
s = "most";
}
warmup_start_weapons_default = start_weapons_default;
warmup_start_weapons_defaultmask = start_weapons_defaultmask;
- if (!g_weaponarena && !g_ca)
+ if (!g_weaponarena && !g_ca && !g_freezetag)
{
warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
}
-float sound_allowed(float _dest, entity e)
+float sound_allowed(float destin, entity e)
{
// sounds from world may always pass
for (;;)
break;
}
// sounds to self may always pass
- if (_dest == MSG_ONE)
+ if (destin == MSG_ONE)
if (e == msg_entity)
return true;
// sounds by players can be removed
}
#undef sound
-void sound(entity e, float chan, string samp, float vol, float _atten)
+void sound(entity e, float chan, string samp, float vol, float attenu)
{
if (!sound_allowed(MSG_BROADCAST, e))
return;
- sound7(e, chan, samp, vol, _atten, 0, 0);
+ sound7(e, chan, samp, vol, attenu, 0, 0);
}
-void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float _atten)
+void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float attenu)
{
float entno, idx;
entno = num_for_edict(e);
idx = precache_sound_index(samp);
- float sflags;
+ int sflags;
sflags = 0;
- _atten = floor(_atten * 64);
+ attenu = floor(attenu * 64);
vol = floor(vol * 255);
if (vol != 255)
sflags |= SND_VOLUME;
- if (_atten != 64)
+ if (attenu != 64)
sflags |= SND_ATTENUATION;
if (entno >= 8192 || chan < 0 || chan > 7)
sflags |= SND_LARGEENTITY;
if (sflags & SND_VOLUME)
WriteByte(_dest, vol);
if (sflags & SND_ATTENUATION)
- WriteByte(_dest, _atten);
+ WriteByte(_dest, attenu);
if (sflags & SND_LARGEENTITY)
{
WriteShort(_dest, entno);
e.uncustomizeentityforclient_set = !!uncustomizer;
}
-
-void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
+void Net_LinkEntity(entity e, bool docull, float dt, bool(entity, int) sendfunc)
{
vector mi, ma;
}
-entity eliminatedPlayers;
.float(entity) isEliminated;
float EliminatedPlayers_SendEntity(entity to, float sendflags)
{
#define SUB_OwnerCheck() (other && (other == self.owner))
-void RemoveGrapplingHook(entity pl);
void W_Crylink_Dequeue(entity e);
float WarpZone_Projectile_Touch_ImpactFilter_Callback()
{
.float scale2;
-float modeleffect_SendEntity(entity to, float sf)
+float modeleffect_SendEntity(entity to, int sf)
{
float f;
WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
#else
string cvar_string_normal(string n)
{
- if (!(cvar_type(n) & 1))
+ if (!(cvar_type(n) & CVAR_TYPEFLAG_EXISTS))
backtrace(strcat("Attempt to access undefined cvar: ", n));
return builtin_cvar_string(n);
}
.float uncustomizeentityforclient_set;
.float nottargeted;
+entity eliminatedPlayers;
+void EliminatedPlayers_Init(float(entity) isEliminated_func);
+
+string admin_name(void);
+
+void write_recordmarker(entity pl, float tstart, float dt);
+
+void play2all(string samp);
+
+void DistributeEvenly_Init(float amount, float totalweight);
+float DistributeEvenly_Get(float weight);
+
+void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2);
+
+void shockwave_spawn(string m, vector org, float sz, float t1, float t2);
+
+vector randompos(vector m1, vector m2);
+
+void play2team(float t, string filename);
+
+void GetCvars_handleFloat(string thisname, float f, .float field, string name);
+
+float spamsound(entity e, float chan, string samp, float vol, float _atten);
+
+void GetCvars_handleString(string thisname, float f, .string field, string name);
+
+void precache_all_playermodels(string pattern);
+
+void soundat(entity e, vector o, float chan, string samp, float vol, float _atten);
+
+void defer(float fdelay, void() func);
+
+void UncustomizeEntitiesRun();
+void InitializeEntitiesRun();
+
+void stopsoundto(float _dest, entity e, float chan);
+void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float _atten);
+float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d);
+
+vector shotorg_adjust(vector vecs, float y_is_right, float visual);
float DistributeEvenly_amount;
float DistributeEvenly_totalweight;
float LostMovetypeFollow(entity ent);
+string uid2name(string myuid);
+
float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance);
string NearestLocation(vector p);
void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
-#define IFTARGETED if(!self.nottargeted && self.targetname != "")
-
#define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
#define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP))
#define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
-#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
-
const string STR_PLAYER = "player";
const string STR_SPECTATOR = "spectator";
const string STR_OBSERVER = "observer";
const float SND_LARGEENTITY = 8;
const float SND_LARGESOUND = 16;
-// WARNING: this kills the trace globals
-#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
-#define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
-
const float INITPRIO_FIRST = 0;
const float INITPRIO_GAMETYPE = 0;
const float INITPRIO_GAMETYPE_FALLBACK = 1;
float sound_allowed(float dest, entity e);
void InitializeEntity(entity e, void(void) func, float order);
void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer);
-void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc);
+void Net_LinkEntity(entity e, bool docull, float dt, bool(entity, int) sendfunc);
#endif
+#include "base.qh"
+#include "../_all.qh"
+
.float() cbc_func;
.entity cbc_next;
.float cbc_order;
string loaded_mutators[MAX_MUTATORS];
float Mutator_Add(mutatorfunc_t func, string name)
{
- float i, j;
+ int i, j;
j = -1;
for(i = 0; i < MAX_MUTATORS; ++i)
{
}
void Mutator_Remove(float(float) func, string name)
{
- float i;
+ int i;
for(i = 0; i < MAX_MUTATORS; ++i)
if(name == loaded_mutators[i])
break;
--- /dev/null
+#ifndef GAMEMODE_H
+#define GAMEMODE_H
+
+#include "mutator_nades.qh"
+
+#include "../cl_client.qh"
+#include "../cl_player.qh"
+#include "../cl_impulse.qh"
+#include "../cheats.qh"
+#include "../g_damage.qh"
+#include "../round_handler.qh"
+#include "../scores.qh"
+#include "../scores_rules.qh"
+#include "../waypointsprites.qh"
+
+#include "../bot/bot.qh"
+#include "../bot/navigation.qh"
+#include "../bot/waypoints.qh"
+#include "../bot/havocbot/roles.qh"
+#include "../bot/havocbot/role_keyhunt.qh"
+
+#include "../bot/havocbot/havocbot.qh"
+
+#include "../command/vote.qh"
+
+#include "../../common/monsters/all.qh"
+
+#include "../command/common.qh"
+
+#include "../weapons/tracing.qh"
+#include "../weapons/weaponsystem.qh"
+
+#include "../../common/deathtypes.qh"
+#include "../../common/notifications.qh"
+#include "../../common/triggers/teleporters.qh"
+#include "../../common/triggers/subs.qh"
+#include "../../common/stats.qh"
+#include "../../common/teams.qh"
+
+#include "../../warpzonelib/mathlib.qh"
+#include "../../warpzonelib/server.qh"
+#include "../../warpzonelib/util_server.qh"
+
+.float lastground;
+float total_players;
+float redalive, bluealive, yellowalive, pinkalive;
+.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
+
+#endif
+#include "gamemode_assault.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+.entity sprite;
+
// random functions
void assault_objective_use()
{
const float SP_ASSAULT_OBJECTIVES = 4;
// predefined spawnfuncs
-void spawnfunc_func_breakable();
void target_objective_decrease_activate();
#endif
-float total_players;
-float redalive, bluealive, yellowalive, pinkalive;
-.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
+#include "gamemode_ca.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
float ca_teams;
float allowed_to_spawn;
-// ================================================================
-// Official capture the flag game mode coding, reworked by Samual
-// Last updated: September, 2012
-// ================================================================
+#include "gamemode_ctf.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+#ifdef SVQC
+#include "../vehicles/vehicle.qh"
+#endif
+
+#include "../../warpzonelib/common.qh"
+#include "../../warpzonelib/mathlib.qh"
void ctf_FakeTimeLimit(entity e, float t)
{
WriteCoord(MSG_ONE, (t + 1) / 60);
}
-void ctf_EventLog(string mode, float flagteam, entity actor) // use an alias for easy changing and quick editing later
+void ctf_EventLog(string mode, int flagteam, entity actor) // use an alias for easy changing and quick editing later
{
if(autocvar_sv_eventlog)
GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
}
-float ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
+bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
{
if(autocvar_g_ctf_pass_directional_max || autocvar_g_ctf_pass_directional_min)
{
// CaptureShield Functions
// =======================
-float ctf_CaptureShield_CheckStatus(entity p)
+bool ctf_CaptureShield_CheckStatus(entity p)
{
float s, se;
entity e;
}
}
-void ctf_FlagDamage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void ctf_FlagDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(ITEM_DAMAGE_NEEDKILL(deathtype))
{
self.bot_basewaypoint = self.nearestwaypoint;
// waypointsprites
+ // move_origin isnt accessible just yet
WaypointSprite_SpawnFixed(((self.team == NUM_TEAM_1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, false));
WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, false));
void ctf_RespawnFlag(entity flag);
// score rule declarations
-const float ST_CTF_CAPS = 1;
-const float SP_CTF_CAPS = 4;
-const float SP_CTF_CAPTIME = 5;
-const float SP_CTF_PICKUPS = 6;
-const float SP_CTF_DROPS = 7;
-const float SP_CTF_FCKILLS = 8;
-const float SP_CTF_RETURNS = 9;
+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;
// flag constants // for most of these, there is just one question to be asked: WHYYYYY?
-#define FLAG_MIN (PL_MIN + '0 0 -13')
-#define FLAG_MAX (PL_MAX + '0 0 -13')
+#define FLAG_MIN (PL_MIN_CONST + '0 0 -13')
+#define FLAG_MAX (PL_MAX_CONST + '0 0 -13')
const float FLAG_SCALE = 0.6;
const float FLAG_TOUCHRATE = 0.5;
const float WPFE_THINKRATE = 0.5;
-#define FLAG_DROP_OFFSET ('0 0 32')
-#define FLAG_CARRY_OFFSET ('-16 0 8')
-#define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_z - 13))
-#define FLAG_WAYPOINT_OFFSET ('0 0 64')
-#define FLAG_FLOAT_OFFSET ('0 0 32')
-#define FLAG_PASS_ARC_OFFSET ('0 0 -10')
+const vector FLAG_DROP_OFFSET = ('0 0 32');
+const vector FLAG_CARRY_OFFSET = ('-16 0 8');
+#define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
+const vector FLAG_WAYPOINT_OFFSET = ('0 0 64');
+const vector FLAG_FLOAT_OFFSET = ('0 0 32');
+const vector FLAG_PASS_ARC_OFFSET = ('0 0 -10');
-#define VEHICLE_FLAG_OFFSET ('0 0 96')
+const vector VEHICLE_FLAG_OFFSET = ('0 0 96');
const float VEHICLE_FLAG_SCALE = 1.0;
// waypoint colors
float wpforenemy_nextthink;
// statuses
-const float FLAG_BASE = 1;
-const float FLAG_DROPPED = 2;
-const float FLAG_CARRY = 3;
-const float FLAG_PASSING = 4;
+const int FLAG_BASE = 1;
+const int FLAG_DROPPED = 2;
+const int FLAG_CARRY = 3;
+const int FLAG_PASSING = 4;
-const float DROP_NORMAL = 1;
-const float DROP_THROW = 2;
-const float DROP_PASS = 3;
-const float DROP_RESET = 4;
+const int DROP_NORMAL = 1;
+const int DROP_THROW = 2;
+const int DROP_PASS = 3;
+const int DROP_RESET = 4;
-const float PICKUP_BASE = 1;
-const float PICKUP_DROPPED = 2;
+const int PICKUP_BASE = 1;
+const int PICKUP_DROPPED = 2;
-const float CAPTURE_NORMAL = 1;
-const float CAPTURE_DROPPED = 2;
+const int CAPTURE_NORMAL = 1;
+const int CAPTURE_DROPPED = 2;
-const float RETURN_TIMEOUT = 1;
-const float RETURN_DROPPED = 2;
-const float RETURN_DAMAGE = 3;
-const float RETURN_SPEEDRUN = 4;
-const float RETURN_NEEDKILL = 5;
+const int RETURN_TIMEOUT = 1;
+const int RETURN_DROPPED = 2;
+const int RETURN_DAMAGE = 3;
+const int RETURN_SPEEDRUN = 4;
+const int RETURN_NEEDKILL = 5;
+
+void ctf_Handle_Throw(entity player, entity receiver, float droptype);
// flag properties
#define ctf_spawnorigin dropped_origin
.entity ctf_dropper; // don't allow spam of dropping the flag
.float max_flag_health;
.float next_take_time;
+.float ctf_thinkrate;
// passing/throwing properties
.float pass_distance;
float ctf_captureshield_force; // push force of the shield
// bot player logic
-const float HAVOCBOT_CTF_ROLE_NONE = 0;
-const float HAVOCBOT_CTF_ROLE_DEFENSE = 2;
-const float HAVOCBOT_CTF_ROLE_MIDDLE = 4;
-const float HAVOCBOT_CTF_ROLE_OFFENSE = 8;
-const float HAVOCBOT_CTF_ROLE_CARRIER = 16;
-const float HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
-const float HAVOCBOT_CTF_ROLE_ESCORT = 64;
-
-.float havocbot_cantfindflag;
+const int HAVOCBOT_CTF_ROLE_NONE = 0;
+const int HAVOCBOT_CTF_ROLE_DEFENSE = 2;
+const int HAVOCBOT_CTF_ROLE_MIDDLE = 4;
+const int HAVOCBOT_CTF_ROLE_OFFENSE = 8;
+const int HAVOCBOT_CTF_ROLE_CARRIER = 16;
+const int HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
+const int HAVOCBOT_CTF_ROLE_ESCORT = 64;
+
+.bool havocbot_cantfindflag;
vector havocbot_ctf_middlepoint;
float havocbot_ctf_middlepoint_radius;
+#include "gamemode_cts.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+#include "../race.qh"
+
// legacy bot roles
.float race_checkpoint;
void havocbot_role_cts()
+#include "gamemode_domination.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
{
if(autocvar_sv_eventlog)
-.float freezetag_frozen_time;
-.float freezetag_frozen_timeout;
-const float ICE_MAX_ALPHA = 1;
-const float ICE_MIN_ALPHA = 0.1;
-float freezetag_teams;
+#include "gamemode_freezetag.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
const float SP_FREEZETAG_REVIVALS = 4;
void freezetag_ScoreRules(float teams)
return 1;
}
-.float reviving; // temp var
MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
{
float n;
return 1;
}
+MUTATOR_HOOKFUNCTION(freezetag_SetStartItems)
+{
+ start_items &= ~IT_UNLIMITED_AMMO;
+ //start_health = warmup_start_health = cvar("g_lms_start_health");
+ //start_armorvalue = warmup_start_armorvalue = cvar("g_lms_start_armor");
+ start_ammo_shells = warmup_start_ammo_shells = cvar("g_lms_start_ammo_shells");
+ start_ammo_nails = warmup_start_ammo_nails = cvar("g_lms_start_ammo_nails");
+ start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+ start_ammo_cells = warmup_start_ammo_cells = cvar("g_lms_start_ammo_cells");
+ start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_lms_start_ammo_plasma");
+ start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
+
+ return 0;
+}
+
MUTATOR_HOOKFUNCTION(freezetag_BotRoles)
{
if (!self.deadflag)
MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY);
MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
+ MUTATOR_HOOK(SetStartItems, freezetag_SetStartItems, CBC_ORDER_ANY);
MUTATOR_HOOK(HavocBot_ChooseRole, freezetag_BotRoles, CBC_ORDER_ANY);
MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE);
--- /dev/null
+#ifndef GAMEMODE_FREEZETAG_H
+#define GAMEMODE_FREEZETAG_H
+.float freezetag_frozen_time;
+.float freezetag_frozen_timeout;
+const float ICE_MAX_ALPHA = 1;
+const float ICE_MIN_ALPHA = 0.1;
+float freezetag_teams;
+
+.float reviving; // temp var
+
+#endif
+#include "gamemode_invasion.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+#include "../../common/monsters/spawn.qh"
+#include "../../common/monsters/sv_monsters.qh"
+
void spawnfunc_invasion_spawnpoint()
{
if(!g_invasion) { remove(self); return; }
+#include "gamemode_keepaway.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
// ===========================================================
// Keepaway game mode coding, written by Samual and Diabolik
// Last updated: September, 2012
GameLogEcho(strcat(":ka:", mode, ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
}
+void ka_TouchEvent();
void ka_RespawnBall() // runs whenever the ball needs to be relocated
{
if(gameover) { return; }
self.velocity = '0 0 200';
self.angles = '0 0 0';
self.effects = autocvar_g_keepawayball_effects;
+ self.touch = ka_TouchEvent;
self.think = ka_RespawnBall;
self.nextthink = time + autocvar_g_keepawayball_respawntime;
if((self.owner) && (IS_PLAYER(self.owner)))
ka_DropEvent(self.owner);
- ka_RespawnBall();
+ if(time < game_starttime)
+ {
+ self.think = ka_RespawnBall;
+ self.touch = func_null;
+ self.nextthink = game_starttime;
+ }
+ else
+ ka_RespawnBall();
}
t = (self.health + self.armorvalue) / (ball_owner.health + ball_owner.armorvalue);
navigation_routerating(ball_owner, t * ratingscale, 2000);
}
-
- // Ball has been dropped so collect.
- navigation_routerating(ka_ball, ratingscale, 2000);
+ else // Ball has been dropped so collect.
+ navigation_routerating(ka_ball, ratingscale, 2000);
}
void havocbot_role_ka_carrier()
void() havocbot_role_ka_carrier;
void() havocbot_role_ka_collector;
+
+void ka_DropEvent(entity plyr);
+
#endif
-#define FOR_EACH_KH_KEY(v) for(v = kh_worldkeylist; v; v = v.kh_worldkeynext )
+#include "gamemode_keyhunt.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
// #define KH_PLAYER_USE_ATTACHMENT
// #define KH_PLAYER_USE_CARRIEDMODEL
}
// in any case:
setattachment(key, world, "");
- setorigin(key, key.owner.origin + '0 0 1' * (PL_MIN_z - KH_KEY_MIN_z));
+ setorigin(key, key.owner.origin + '0 0 1' * (PL_MIN.z - KH_KEY_MIN_z));
key.angles = key.owner.angles;
#else
setorigin(key, key.owner.origin + key.origin.z * '0 0 1');
}
}
-void kh_Key_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void kh_Key_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.owner)
return;
#ifndef GAMEMODE_KEYHUNT_H
#define GAMEMODE_KEYHUNT_H
+#define FOR_EACH_KH_KEY(v) for(v = kh_worldkeylist; v; v = v.kh_worldkeynext )
+
// ALL OF THESE should be removed in the future, as other code should not have to care
// used by bots:
typedef void(void) kh_Think_t;
void kh_StartRound();
void kh_Controller_SetThink(float t, kh_Think_t func);
+
+void kh_Key_DropAll(entity player, float suicide);
+
#endif
+#include "gamemode_lms.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+#include "../campaign.qh"
+#include "../command/cmd.qh"
+
// main functions
float LMS_NewPlayerLives()
{
+#include "gamemode_nexball.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
float autocvar_g_nexball_safepass_turnrate;
float autocvar_g_nexball_safepass_maxdist;
float autocvar_g_nexball_safepass_holdtime;
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
float autocvar_g_onslaught_spawn_at_controlpoints;
float autocvar_g_onslaught_spawn_at_generator;
float autocvar_g_onslaught_cp_proxydecap;
entity ons_red_generator;
entity ons_blue_generator;
-void ons_gib_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+void ons_gib_damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce)
{
self.velocity = self.velocity + vforce;
}
self.count = self.count - 1;
}
-void onslaught_generator_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void onslaught_generator_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
float i;
if (damage <= 0)
float ons_notification_time_team1;
float ons_notification_time_team2;
-void onslaught_controlpoint_icon_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void onslaught_controlpoint_icon_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
entity oself;
float nag;
+#include "gamemode_race.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+#include "../race.qh"
+
// legacy bot roles
.float race_checkpoint;
void havocbot_role_race()
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
/*QUAKED spawnfunc_tdm_team (0 .5 .8) (-16 -16 -24) (16 16 32)
Team declaration for TDM gameplay, this allows you to decide what team names and control point models are used in your map.
Note: If you use spawnfunc_tdm_team entities you must define at least 2! However, unlike domination, you don't need to make a blank one too.
--- /dev/null
+#ifndef MUTATOR_H
+#define MUTATOR_H
+
+#include "base.qh"
+#include "mutator_nades.qh"
+
+#include "../cl_client.qh"
+#include "../cl_player.qh"
+#include "../cl_impulse.qh"
+#include "../cheats.qh"
+#include "../g_damage.qh"
+#include "../round_handler.qh"
+#include "../scores.qh"
+#include "../scores_rules.qh"
+#include "../waypointsprites.qh"
+
+#include "../bot/bot.qh"
+#include "../bot/navigation.qh"
+#include "../bot/waypoints.qh"
+
+#include "../bot/havocbot/havocbot.qh"
+#include "../bot/havocbot/roles.qh"
+#include "../bot/havocbot/role_keyhunt.qh"
+
+#include "../command/vote.qh"
+#include "../command/common.qh"
+
+#include "../weapons/common.qh"
+#include "../weapons/tracing.qh"
+#include "../weapons/throwing.qh"
+#include "../weapons/weaponsystem.qh"
+
+#include "../../common/deathtypes.qh"
+#include "../../common/notifications.qh"
+#include "../../common/triggers/teleporters.qh"
+#include "../../common/triggers/subs.qh"
+#include "../../common/stats.qh"
+#include "../../common/teams.qh"
+
+#include "../../common/monsters/all.qh"
+
+#include "../../warpzonelib/anglestransform.qh"
+#include "../../warpzonelib/mathlib.qh"
+#include "../../warpzonelib/server.qh"
+#include "../../warpzonelib/util_server.qh"
+
+#endif
+#include "../_all.qh"
+
+#include "mutator.qh"
+
.float bloodloss_timer;
MUTATOR_HOOKFUNCTION(bloodloss_PlayerThink)
+#include "mutator_buffs.qh"
+#include "../_all.qh"
+
+#include "mutator.qh"
+
+#include "../../common/buffs.qh"
+
+.float lifetime;
+
float buffs_BuffModel_Customize()
{
entity player, myowner;
{
if(self.buffs & BUFF_JUMP)
player_jumpheight = autocvar_g_buffs_jump_height;
- self.stat_jumpheight = player_jumpheight;
return false;
}
addstat(STAT_BUFFS, AS_INT, buffs);
addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time);
- addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_jumpheight);
InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
}
.float buff_invisible_prev_alpha;
// flight
.float buff_flight_prev_gravity;
-// jump
-.float stat_jumpheight;
// disability
.float buff_disability_time;
.float buff_disability_effect_time;
+#include "../_all.qh"
+
+#include "mutator.qh"
+
+#include "../campaign.qh"
+
.float campcheck_nextcheck;
.float campcheck_traveled_distance;
+#ifdef CSQC
+ #define PHYS_DODGING_FRAMETIME (1 / (frametime <= 0 ? 60 : frametime))
+ #define PHYS_DODGING getstati(STAT_DODGING)
+ #define PHYS_DODGING_DELAY getstatf(STAT_DODGING_DELAY)
+ #define PHYS_DODGING_TIMEOUT(s) getstatf(STAT_DODGING_TIMEOUT)
+ #define PHYS_DODGING_HORIZ_SPEED_FROZEN getstatf(STAT_DODGING_HORIZ_SPEED_FROZEN)
+ #define PHYS_DODGING_FROZEN_NODOUBLETAP getstati(STAT_DODGING_FROZEN_NO_DOUBLETAP)
+ #define PHYS_DODGING_HORIZ_SPEED getstatf(STAT_DODGING_HORIZ_SPEED)
+ #define PHYS_DODGING_PRESSED_KEYS(s) s.pressedkeys
+ #define PHYS_DODGING_HEIGHT_THRESHOLD getstatf(STAT_DODGING_HEIGHT_THRESHOLD)
+ #define PHYS_DODGING_DISTANCE_THRESHOLD getstatf(STAT_DODGING_DISTANCE_THRESHOLD)
+ #define PHYS_DODGING_RAMP_TIME getstatf(STAT_DODGING_RAMP_TIME)
+ #define PHYS_DODGING_UP_SPEED getstatf(STAT_DODGING_UP_SPEED)
+ #define PHYS_DODGING_WALL getstatf(STAT_DODGING_WALL)
+#elif defined(SVQC)
+ #define PHYS_DODGING_FRAMETIME sys_frametime
+ #define PHYS_DODGING g_dodging
+ #define PHYS_DODGING_DELAY autocvar_sv_dodging_delay
+ #define PHYS_DODGING_TIMEOUT(s) s.cvar_cl_dodging_timeout
+ #define PHYS_DODGING_HORIZ_SPEED_FROZEN autocvar_sv_dodging_horiz_speed_frozen
+ #define PHYS_DODGING_FROZEN_NODOUBLETAP autocvar_sv_dodging_frozen_doubletap
+ #define PHYS_DODGING_HORIZ_SPEED autocvar_sv_dodging_horiz_speed
+ #define PHYS_DODGING_PRESSED_KEYS(s) s.pressedkeys
+ #define PHYS_DODGING_HEIGHT_THRESHOLD autocvar_sv_dodging_height_threshold
+ #define PHYS_DODGING_DISTANCE_THRESHOLD autocvar_sv_dodging_wall_distance_threshold
+ #define PHYS_DODGING_RAMP_TIME autocvar_sv_dodging_ramp_time
+ #define PHYS_DODGING_UP_SPEED autocvar_sv_dodging_up_speed
+ #define PHYS_DODGING_WALL autocvar_sv_dodging_wall_dodging
+#endif
+
+#ifdef SVQC
+#include "mutator_dodging.qh"
+#include "../_all.qh"
+
+#include "mutator.qh"
+
+#include "../../common/animdecide.qh"
.float cvar_cl_dodging_timeout;
+.float stat_dodging;
+.float stat_dodging_delay;
+.float stat_dodging_horiz_speed_frozen;
+.float stat_dodging_frozen_nodoubletap;
+.float stat_dodging_frozen;
+.float stat_dodging_horiz_speed;
+.float stat_dodging_height_threshold;
+.float stat_dodging_distance_threshold;
+.float stat_dodging_ramp_time;
+.float stat_dodging_up_speed;
+.float stat_dodging_wall;
+
+#endif
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
// these are used to store the last key press time for each of the keys..
.float last_FORWARD_KEY_time;
// until it's 0.
.float dodging_velocity_gain;
-MUTATOR_HOOKFUNCTION(dodging_GetCvars) {
- GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
- return 0;
+#ifdef CSQC
+.int pressedkeys;
+
+#elif defined(SVQC)
+
+void dodging_UpdateStats()
+{
+ self.stat_dodging = PHYS_DODGING;
+ self.stat_dodging_delay = PHYS_DODGING_DELAY;
+ self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN;
+ self.stat_dodging_frozen = PHYS_DODGING_FROZEN;
+ self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP;
+ self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD;
+ self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD;
+ self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME;
+ self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED;
+ self.stat_dodging_wall = PHYS_DODGING_WALL;
}
-MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) {
- // print("dodging_PlayerPhysics\n");
+void dodging_Initialize()
+{
+ addstat(STAT_DODGING, AS_INT, stat_dodging);
+ addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay);
+ addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos)
+ addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap);
+ addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen);
+ addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen);
+ addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed);
+ addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold);
+ addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold);
+ addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time);
+ addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed);
+ addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall);
+}
+
+#endif
+
+// returns 1 if the player is close to a wall
+bool check_close_to_wall(float threshold)
+{
+ if (PHYS_DODGING_WALL == 0) { return false; }
+
+ #define X(OFFSET) \
+ tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, true, self); \
+ if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) \
+ return true;
+ X(1000*v_right);
+ X(-1000*v_right);
+ X(1000*v_forward);
+ X(-1000*v_forward);
+ #undef X
+
+ return false;
+}
+
+bool check_close_to_ground(float threshold)
+{
+ return IS_ONGROUND(self) ? true : false;
+}
+
+float PM_dodging_checkpressedkeys()
+{
+ if(!PHYS_DODGING)
+ return false;
+
+ float frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN);
+ float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
- float common_factor;
- float new_velocity_gain;
- float velocity_difference;
- float clean_up_and_do_nothing;
- float horiz_speed = autocvar_sv_dodging_horiz_speed;
+ // first check if the last dodge is far enough back in time so we can dodge again
+ if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY)
+ return false;
+
+ makevectors(self.angles);
+
+ if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1
+ && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
+ return true;
+
+ float tap_direction_x = 0;
+ float tap_direction_y = 0;
+ float dodge_detected = 0;
+
+ #define X(COND,BTN,RESULT) \
+ if (self.movement_##COND) \
+ /* is this a state change? */ \
+ if(!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_##BTN) || frozen_no_doubletap) { \
+ tap_direction_##RESULT; \
+ if ((time - self.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(self)) \
+ dodge_detected = 1; \
+ self.last_##BTN##_KEY_time = time; \
+ }
+ X(x < 0, BACKWARD, x--);
+ X(x > 0, FORWARD, x++);
+ X(y < 0, LEFT, y--);
+ X(y > 0, RIGHT, y++);
+ #undef X
+
+ if (dodge_detected == 1)
+ {
+ self.last_dodging_time = time;
+
+ self.dodging_action = 1;
+ self.dodging_single_action = 1;
+
+ self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+
+ self.dodging_direction_x = tap_direction_x;
+ self.dodging_direction_y = tap_direction_y;
- if(self.frozen)
- horiz_speed = autocvar_sv_dodging_horiz_speed_frozen;
+ // normalize the dodging_direction vector.. (unlike UT99) XD
+ float length = self.dodging_direction_x * self.dodging_direction_x
+ + self.dodging_direction_y * self.dodging_direction_y;
+ length = sqrt(length);
+
+ self.dodging_direction_x = self.dodging_direction_x * 1.0 / length;
+ self.dodging_direction_y = self.dodging_direction_y * 1.0 / length;
+ return true;
+ }
+ return false;
+}
- if (self.deadflag != DEAD_NO)
- return 0;
+void PM_dodging()
+{
+ if (!PHYS_DODGING)
+ return;
- new_velocity_gain = 0;
- clean_up_and_do_nothing = 0;
+#ifdef SVQC
+ dodging_UpdateStats();
+#endif
- if (g_dodging == 0)
- clean_up_and_do_nothing = 1;
+ if (PHYS_DEAD(self))
+ return;
// when swimming, no dodging allowed..
if (self.waterlevel >= WATERLEVEL_SWIMMING)
- clean_up_and_do_nothing = 1;
-
- if (clean_up_and_do_nothing != 0) {
+ {
self.dodging_action = 0;
self.dodging_direction_x = 0;
self.dodging_direction_y = 0;
- return 0;
+ return;
}
// make sure v_up, v_right and v_forward are sane
// if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
// will be called ramp_time/frametime times = 2 times. so, we need to
// add 0.5 * the total speed each frame until the dodge action is done..
- common_factor = sys_frametime / autocvar_sv_dodging_ramp_time;
+ float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
// if ramp time is smaller than frametime we get problems ;D
- if (common_factor > 1)
- common_factor = 1;
+ common_factor = min(common_factor, 1);
- new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
- if (new_velocity_gain < 0)
- new_velocity_gain = 0;
+ float horiz_speed = PHYS_FROZEN(self) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
+ float new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
+ new_velocity_gain = max(0, new_velocity_gain);
- velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
+ float velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
// ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
- if (self.dodging_action == 1) {
+ if (self.dodging_action == 1)
+ {
//disable jump key during dodge accel phase
- if (self.movement.z > 0) self.movement_z = 0;
+ if(self.movement_z > 0) { self.movement_z = 0; }
- self.velocity =
- self.velocity
- + ((self.dodging_direction.y * velocity_difference) * v_right)
- + ((self.dodging_direction.x * velocity_difference) * v_forward);
+ self.velocity += ((self.dodging_direction_y * velocity_difference) * v_right)
+ + ((self.dodging_direction_x * velocity_difference) * v_forward);
self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference;
}
// the up part of the dodge is a single shot action
- if (self.dodging_single_action == 1) {
- self.flags &= ~FL_ONGROUND;
+ if (self.dodging_single_action == 1)
+ {
+ UNSET_ONGROUND(self);
- self.velocity =
- self.velocity
- + (autocvar_sv_dodging_up_speed * v_up);
+ self.velocity += PHYS_DODGING_UP_SPEED * v_up;
- if (autocvar_sv_dodging_sound == 1)
+#ifdef SVQC
+ if (autocvar_sv_dodging_sound)
PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
animdecide_setaction(self, ANIMACTION_JUMP, true);
+#endif
self.dodging_single_action = 0;
}
// are we done with the dodging ramp yet?
- if((self.dodging_action == 1) && ((time - self.last_dodging_time) > autocvar_sv_dodging_ramp_time))
+ if((self.dodging_action == 1) && ((time - self.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
{
// reset state so next dodge can be done correctly
self.dodging_action = 0;
self.dodging_direction_x = 0;
self.dodging_direction_y = 0;
}
-
- return 0;
}
+#ifdef SVQC
-// returns 1 if the player is close to a wall
-float check_close_to_wall(float threshold) {
- if (autocvar_sv_dodging_wall_dodging == 0)
- return 0;
-
- vector trace_start;
- vector trace_end;
-
- trace_start = self.origin;
-
- trace_end = self.origin + (1000*v_right);
- tracebox(trace_start, self.mins, self.maxs, trace_end, true, self);
- if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
- return 1;
-
- trace_end = self.origin - (1000*v_right);
- tracebox(trace_start, self.mins, self.maxs, trace_end, true, self);
- if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
- return 1;
-
- trace_end = self.origin + (1000*v_forward);
- tracebox(trace_start, self.mins, self.maxs, trace_end, true, self);
- if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
- return 1;
-
- trace_end = self.origin - (1000*v_forward);
- tracebox(trace_start, self.mins, self.maxs, trace_end, true, self);
- if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
- return 1;
-
- return 0;
-}
-
-float check_close_to_ground(float threshold) {
- if (self.flags & FL_ONGROUND)
- return 1;
-
- return 0;
+MUTATOR_HOOKFUNCTION(dodging_GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
+ return false;
}
-
-MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) {
+MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics)
+{
// print("dodging_PlayerPhysics\n");
+ PM_dodging();
- float length;
- vector tap_direction = '0 0 0';
-
- float frozen_dodging, frozen_no_doubletap;
- frozen_dodging = (self.frozen && autocvar_sv_dodging_frozen);
- frozen_no_doubletap = (frozen_dodging && !autocvar_sv_dodging_frozen_doubletap);
-
- float dodge_detected;
- if (g_dodging == 0)
- return 0;
-
- dodge_detected = 0;
-
- // first check if the last dodge is far enough back in time so we can dodge again
- if ((time - self.last_dodging_time) < autocvar_sv_dodging_delay)
- return 0;
-
- if (check_close_to_ground(autocvar_sv_dodging_height_threshold) != 1
- && check_close_to_wall(autocvar_sv_dodging_wall_distance_threshold) != 1)
- return 0;
-
- if (self.movement.x > 0) {
- // is this a state change?
- if (!(self.pressedkeys & KEY_FORWARD) || frozen_no_doubletap) {
- if ((time - self.last_FORWARD_KEY_time) < self.cvar_cl_dodging_timeout) {
- tap_direction.x = 1.0;
- dodge_detected = 1;
- }
- self.last_FORWARD_KEY_time = time;
- }
- }
-
- if (self.movement.x < 0) {
- // is this a state change?
- if (!(self.pressedkeys & KEY_BACKWARD) || frozen_no_doubletap) {
- tap_direction.x = -1.0;
- if ((time - self.last_BACKWARD_KEY_time) < self.cvar_cl_dodging_timeout) {
- dodge_detected = 1;
- }
- self.last_BACKWARD_KEY_time = time;
- }
- }
-
- if (self.movement.y > 0) {
- // is this a state change?
- if (!(self.pressedkeys & KEY_RIGHT) || frozen_no_doubletap) {
- tap_direction.y = 1.0;
- if ((time - self.last_RIGHT_KEY_time) < self.cvar_cl_dodging_timeout) {
- dodge_detected = 1;
- }
- self.last_RIGHT_KEY_time = time;
- }
- }
-
- if (self.movement.y < 0) {
- // is this a state change?
- if (!(self.pressedkeys & KEY_LEFT) || frozen_no_doubletap) {
- tap_direction.y = -1.0;
- if ((time - self.last_LEFT_KEY_time) < self.cvar_cl_dodging_timeout) {
- dodge_detected = 1;
- }
- self.last_LEFT_KEY_time = time;
- }
- }
-
- if (dodge_detected == 1) {
- self.last_dodging_time = time;
-
- self.dodging_action = 1;
- self.dodging_single_action = 1;
-
- self.dodging_velocity_gain = autocvar_sv_dodging_horiz_speed;
-
- self.dodging_direction_x = tap_direction.x;
- self.dodging_direction_y = tap_direction.y;
-
- // normalize the dodging_direction vector.. (unlike UT99) XD
- length = self.dodging_direction.x * self.dodging_direction.x;
- length = length + self.dodging_direction.y * self.dodging_direction.y;
- length = sqrt(length);
+ return false;
+}
- self.dodging_direction_x = self.dodging_direction.x * 1.0/length;
- self.dodging_direction_y = self.dodging_direction.y * 1.0/length;
- }
+MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys)
+{
+ PM_dodging_checkpressedkeys();
- return 0;
+ return false;
}
MUTATOR_DEFINITION(mutator_dodging)
// this just turns on the cvar.
MUTATOR_ONADD
{
- g_dodging = 1;
+ g_dodging = cvar("g_dodging");
+ dodging_Initialize();
}
// this just turns off the cvar.
g_dodging = 0;
}
- MUTATOR_ONREMOVE
- {
- }
-
- return 0;
+ return false;
}
+#endif
+#include "../_all.qh"
+
+#include "mutator.qh"
+
+#include "../cl_client.qh"
+#include "../../common/buffs.qh"
+
+#include "../../common/items/all.qc"
+
void spawnfunc_item_minst_cells (void)
{
if (!g_instagib) { remove(self); return; }
if (!self.ammo_cells)
self.ammo_cells = autocvar_g_instagib_ammo_drop;
- StartItem ("models/items/a_cells.md3",
- "misc/itempickup.wav", 45, 0,
- "Vaporizer Ammo", IT_CELLS, 0, 0, generic_pickupevalfunc, 100);
+ StartItemA (ITEM_VaporizerCells);
}
void instagib_health_mega()
{
self.max_health = 1;
- StartItem ("models/items/g_h100.md3",
- "misc/megahealth.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
- "Extralife", IT_NAILS, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+ StartItemA (ITEM_ExtraLife);
}
.float instagib_nextthink;
--- /dev/null
+#include "../../common/items/item.qh"
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+
+float instagib_respawntime_ammo = 45;
+float instagib_respawntimejitter_ammo = 0;
+GETTER(float, instagib_respawntime_ammo)
+GETTER(float, instagib_respawntimejitter_ammo)
+
+REGISTER_ITEM(VaporizerCells, Pickup, APPLY(UNWORDS
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_cells.md3"
+ , sound = "misc/itempickup.wav"
+ , name = "Vaporizer Ammo"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 100
+ , itemid = IT_CELLS
+ , respawntime = GET(instagib_respawntime_ammo)
+ , respawntimejitter = GET(instagib_respawntimejitter_ammo)
+ )
+))
+
+REGISTER_ITEM(ExtraLife, Pickup, APPLY(UNWORDS
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h100.md3"
+ , sound = "misc/megahealth.wav"
+ , name = "Extralife"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_HIGH
+ , itemflags = FL_POWERUP
+ , itemid = IT_NAILS
+ , respawntime = GET(g_pickup_respawntime_powerup)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
+ )
+))
+
+#undef WITH
+#undef CONFIGURE
+#include "../_all.qh"
+
+#include "mutator.qh"
+
MUTATOR_HOOKFUNCTION(invincibleprojectiles_EditProjectile)
{
if(other.health)
+#include "../_all.qh"
+
+#include "mutator.qh"
+
MUTATOR_HOOKFUNCTION(melee_SetStartItems)
{
start_ammo_shells = warmup_start_ammo_shells = 0;
+#include "../_all.qh"
+
+#include "mutator.qh"
+
.float midair_shieldtime;
MUTATOR_HOOKFUNCTION(midair_PlayerDamage)
+#ifdef SVQC
+ #include "../_all.qh"
+ #include "mutator.qh"
+ #include "../antilag.qh"
+#endif
+
.float multijump_count;
.float multijump_ready;
-MUTATOR_HOOKFUNCTION(multijump_PlayerPhysics)
+#ifdef CSQC
+
+#define PHYS_MULTIJUMP getstati(STAT_MULTIJUMP)
+#define PHYS_MULTIJUMP_SPEED getstatf(STAT_MULTIJUMP_SPEED)
+#define PHYS_MULTIJUMP_ADD getstati(STAT_MULTIJUMP_ADD)
+
+#elif defined(SVQC)
+
+#define PHYS_MULTIJUMP autocvar_g_multijump
+#define PHYS_MULTIJUMP_SPEED autocvar_g_multijump_speed
+#define PHYS_MULTIJUMP_ADD autocvar_g_multijump_add
+
+
+.float stat_multijump;
+.float stat_multijump_speed;
+.float stat_multijump_add;
+
+void multijump_UpdateStats()
{
- if(self.flags & FL_ONGROUND)
- self.multijump_count = 0;
+ self.stat_multijump = PHYS_MULTIJUMP;
+ self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED;
+ self.stat_multijump_add = PHYS_MULTIJUMP_ADD;
+}
- return false;
+void multijump_AddStats()
+{
+ addstat(STAT_MULTIJUMP, AS_INT, stat_multijump);
+ addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed);
+ addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add);
}
-MUTATOR_HOOKFUNCTION(multijump_PlayerJump)
+#endif
+
+void PM_multijump()
+{
+ if(!PHYS_MULTIJUMP) { return; }
+
+ if(IS_ONGROUND(self))
+ {
+ self.multijump_count = 0;
+ }
+}
+
+float PM_multijump_checkjump()
{
- if (self.flags & FL_JUMPRELEASED && !(self.flags & FL_ONGROUND)) // jump button pressed this frame and we are in midair
+ if(!PHYS_MULTIJUMP) { return false; }
+
+ if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self)) // jump button pressed this frame and we are in midair
self.multijump_ready = true; // this is necessary to check that we released the jump button and pressed it again
else
self.multijump_ready = false;
- if(!player_multijump && self.multijump_ready && (autocvar_g_multijump == -1 || self.multijump_count < autocvar_g_multijump) && self.velocity.z > autocvar_g_multijump_speed)
+ if(!player_multijump && self.multijump_ready && (self.multijump_count < PHYS_MULTIJUMP || PHYS_MULTIJUMP == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED)
{
- if (autocvar_g_multijump)
+ if (PHYS_MULTIJUMP)
{
- if (autocvar_g_multijump_add == 0) // in this case we make the z velocity == jumpvelocity
+ if (!PHYS_MULTIJUMP_ADD) // in this case we make the z velocity == jumpvelocity
{
- if (self.velocity.z < autocvar_sv_jumpvelocity)
+ if (self.velocity_z < PHYS_JUMPVELOCITY)
{
player_multijump = true;
self.velocity_z = 0;
if(player_multijump)
{
- if(self.movement.x != 0 || self.movement.y != 0) // don't remove all speed if player isnt pressing any movement keys
+ if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
{
float curspeed;
vector wishvel, wishdir;
+#ifdef SVQC
curspeed = max(
vlen(vec2(self.velocity)), // current xy speed
vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
);
- makevectors(self.v_angle.y * '0 1 0');
- wishvel = v_forward * self.movement.x + v_right * self.movement.y;
+#elif defined(CSQC)
+ curspeed = vlen(vec2(self.velocity));
+#endif
+
+ makevectors(self.v_angle_y * '0 1 0');
+ wishvel = v_forward * self.movement_x + v_right * self.movement_y;
wishdir = normalize(wishvel);
- self.velocity_x = wishdir.x * curspeed; // allow "dodging" at a multijump
- self.velocity_y = wishdir.y * curspeed;
+ self.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump
+ self.velocity_y = wishdir_y * curspeed;
// keep velocity_z unchanged!
}
self.multijump_count += 1;
return false;
}
+#ifdef SVQC
+MUTATOR_HOOKFUNCTION(multijump_PlayerPhysics)
+{
+ multijump_UpdateStats();
+ PM_multijump();
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump_PlayerJump)
+{
+ return PM_multijump_checkjump();
+}
+
MUTATOR_HOOKFUNCTION(multijump_BuildMutatorsString)
{
ret_string = strcat(ret_string, ":multijump");
MUTATOR_HOOK(BuildMutatorsString, multijump_BuildMutatorsString, CBC_ORDER_ANY);
MUTATOR_HOOK(BuildMutatorsPrettyString, multijump_BuildMutatorsPrettyString, CBC_ORDER_ANY);
+ MUTATOR_ONADD
+ {
+ multijump_AddStats();
+ }
+
return false;
}
+#endif
+#include "mutator_nades.qh"
+#include "../_all.qh"
+
+#include "mutator.qh"
+
+#include "gamemode_keyhunt.qh"
+#include "gamemode_freezetag.qh"
+#include "../../common/nades.qh"
+#include "../../common/monsters/spawn.qh"
+#include "../../common/monsters/sv_monsters.qh"
+
+.float lifetime;
+
.entity nade_spawnloc;
void nade_timer_think()
void nade_boom()
{
string expef;
- float nade_blast = 1;
+ bool nade_blast = true;
switch ( self.nade_type )
{
expef = "explosion_medium";
break;
case NADE_TYPE_ICE:
- nade_blast = 0;
+ nade_blast = false;
expef = "electro_combo"; // hookbomb_explode electro_combo bigplasma_impact
break;
case NADE_TYPE_TRANSLOCATE:
- nade_blast = 0;
+ nade_blast = false;
expef = "";
break;
case NADE_TYPE_MONSTER:
case NADE_TYPE_SPAWN:
- nade_blast = 0;
+ nade_blast = false;
switch(self.realowner.team)
{
case NUM_TEAM_1: expef = "spawn_event_red"; break;
}
break;
case NADE_TYPE_HEAL:
- nade_blast = 0;
+ nade_blast = false;
expef = "spawn_event_red";
break;
self.nextthink = max(self.wait, time);
}
-void nade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void nade_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(ITEM_DAMAGE_NEEDKILL(deathtype))
{
+#include "../_all.qh"
+
+#include "mutator.qh"
+
/*
CORE laser vortex lg rl cry gl elec hagar fireb hook
+#include "../_all.qh"
+
+#include "mutator.qh"
+
float g_nix_with_blaster;
// WEAPONTODO
-float nix_weapon;
+int nix_weapon;
float nix_nextchange;
float nix_nextweapon;
.float nix_lastchange_id;
-void ok_DecreaseCharge(entity ent, float wep)
+#include "mutator_overkill.qh"
+#include "../_all.qh"
+
+#include "mutator.qh"
+
+void W_Blaster_Attack(float, float, float, float, float, float, float, float, float, float);
+void spawnfunc_weapon_hmg();
+void spawnfunc_weapon_rpc();
+
+void ok_DecreaseCharge(entity ent, int wep)
{
if(!ent.ok_use_ammocharge) return;
ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
}
-void ok_IncreaseCharge(entity ent, float wep)
+void ok_IncreaseCharge(entity ent, int wep)
{
entity wepent = get_weaponinfo(wep);
ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
}
-float ok_CheckWeaponCharge(entity ent, float wep)
+float ok_CheckWeaponCharge(entity ent, int wep)
{
if(!ent.ok_use_ammocharge) return true;
{
if(autocvar_g_overkill_ammo_charge)
{
- float i;
-
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
self.ok_use_ammocharge = 1;
+#include "../_all.qh"
+
+#include "mutator.qh"
+
.vector spawn_origin, spawn_angles;
void physical_item_think()
}
}
-void physical_item_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void physical_item_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(!self.cnt) // not for dropped items
if(ITEM_DAMAGE_NEEDKILL(deathtype))
+#include "../_all.qh"
+
+#include "mutator.qh"
+
MUTATOR_HOOKFUNCTION(pinata_PlayerDies)
{
float j;
+#include "../_all.qh"
+
+#include "mutator.qh"
+
// Random Gravity
//
// Mutator by Mario
+#include "../_all.qh"
+
+#include "mutator.qh"
+
MUTATOR_HOOKFUNCTION(rocketflying_EditProjectile)
{
if(other.classname == "rocket" || other.classname == "mine")
+#include "../_all.qh"
+
+#include "mutator.qh"
+
.entity msnt_lookat;
.float msnt_timer;
+#include "../_all.qh"
+
+#include "mutator.qh"
+
#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
#define _ISLOCAL ((edict_num(1) == self) ? true : false)
+#include "../_all.qh"
+
+#include "mutator.qh"
+
.float touchexplode_time;
void PlayerTouchExplode(entity p1, entity p2)
+#include "../_all.qh"
+
+#include "mutator.qh"
+
MUTATOR_HOOKFUNCTION(vampire_PlayerDamage)
{
if(time >= frag_target.spawnshieldtime)
#include "../../common/command/markup.qh"
#include "../../common/command/rpn.qh"
#include "../../common/command/generic.qh"
- #include "../../common/command/shared_defs.qh"
+ #include "../../common/command/command.qh"
#include "../../common/net_notice.qh"
#include "../../common/animdecide.qh"
- #include "../../common/monsters/monsters.qh"
+ #include "../../common/monsters/all.qh"
#include "../../common/monsters/sv_monsters.qh"
#include "../../common/monsters/spawn.qh"
#include "../../common/weapons/config.qh"
- #include "../../common/weapons/weapons.qh"
+ #include "../../common/weapons/all.qh"
#include "../weapons/accuracy.qh"
#include "../weapons/common.qh"
#include "../weapons/csqcprojectile.qh"
#include "../../common/deathtypes.qh"
#include "mutators_include.qh"
#include "../tturrets/include/turrets_early.qh"
- #include "../vehicles/vehicles_def.qh"
+ #include "../vehicles/vehicle.qh"
#include "../campaign.qh"
#include "../../common/campaign_common.qh"
#include "../../common/mapinfo.qh"
#include "../playerdemo.qh"
#include "../round_handler.qh"
#include "../item_key.qh"
- #include "../secret.qh"
#include "../pathlib/pathlib.qh"
#include "../tturrets/include/turrets.qh"
- #include "../vehicles/vehicles.qh"
+ #include "../vehicles/all.qh"
#endif
#include "base.qc"
+#include "../_all.qh"
+
+#include "mutator.qh"
+
const float MAX_STORAGE_ATTACHMENTS = 16;
float object_count;
.float object_flood;
-//#define PATHLIB_RDFIELDS
-#ifdef PATHLIB_RDFIELDS
- #define path_next swampslug
- #define path_prev lasertarget
-#else
- .entity path_next;
- .entity path_prev;
-#endif
+#include "pathlib.qh"
+#include "_all.qh"
#define medium spawnshieldtime
//#define DEBUGPATHING
-
-entity openlist;
-entity closedlist;
-entity scraplist;
-
-.float pathlib_node_g;
-.float pathlib_node_h;
-.float pathlib_node_f;
-
-float pathlib_open_cnt;
-float pathlib_closed_cnt;
-float pathlib_made_cnt;
-float pathlib_merge_cnt;
-float pathlib_recycle_cnt;
-float pathlib_searched_cnt;
-
-#ifdef DEBUGPATHING
-
-#endif
-
-float pathlib_bestopen_seached;
-float pathlib_bestcash_hits;
-float pathlib_bestcash_saved;
-
-float pathlib_gridsize;
-
-float pathlib_movecost;
-float pathlib_movecost_diag;
-float pathlib_movecost_waterfactor;
-
-float pathlib_edge_check_size;
-
-float pathlib_foundgoal;
-entity goal_node;
-
-entity best_open_node;
-.float is_path_node;
-
-
#ifdef DEBUGPATHING
float edge_show(vector point,float fsize);
void mark_error(vector where,float lifetime);
return 0;
}
-#define inwater(point) (pointcontents(point) == CONTENT_WATER)
-/*
-float inwater(vector point)
-{
- if(pointcontents(point) == CONTENT_WATER)
- return 1;
- return 0;
-}
-*/
-
#define _pcheck(p) traceline(p+z_up,p-z_down,MOVE_WORLDONLY,self); if (!floor_ok(trace_endpos)) return 1
float edge_check(vector point,float fsize)
{
end.y = fsnap(end.y, pathlib_gridsize);
if(pointcontents(end) == CONTENT_EMPTY)
- return pathlib_wateroutnode( start, end);
+ return pathlib_wateroutnode( start, end, doedge);
tracebox(start, walknode_boxmin,walknode_boxmax, end, MOVE_WORLDONLY, self);
if(trace_fraction == 1)
return h;
}
-//#define PATHLIB_USE_NODESCRAP
const float PATHLIB_NODEEXPIRE = 0.05;
float pathlib_scraplist_cnt;
entity newnode()
#endif
++pathlib_made_cnt;
n = spawn();
-#ifdef PATHLIB_NODEEXPIRE
n.think = SUB_Remove;
n.nextthink = time + PATHLIB_NODEEXPIRE;
return n;
{
vector point;
vector where;
- float nodecnt;
+ float nodecnt = 0;
where = node.origin;
return world;
}
-
-
-
--- /dev/null
+#ifndef PATHLIB_H
+#define PATHLIB_H
+
+//#define PATHLIB_RDFIELDS
+#ifdef PATHLIB_RDFIELDS
+ #define path_next swampslug
+ #define path_prev lasertarget
+#else
+ .entity path_next;
+ .entity path_prev;
+#endif
+
+entity openlist;
+entity closedlist;
+entity scraplist;
+
+.float pathlib_node_g;
+.float pathlib_node_h;
+.float pathlib_node_f;
+
+float pathlib_open_cnt;
+float pathlib_closed_cnt;
+float pathlib_made_cnt;
+float pathlib_merge_cnt;
+float pathlib_recycle_cnt;
+float pathlib_searched_cnt;
+
+float pathlib_bestopen_seached;
+float pathlib_bestcash_hits;
+float pathlib_bestcash_saved;
+
+float pathlib_gridsize;
+
+float pathlib_movecost;
+float pathlib_movecost_diag;
+float pathlib_movecost_waterfactor;
+
+float pathlib_edge_check_size;
+
+float pathlib_foundgoal;
+entity goal_node;
+
+entity best_open_node;
+.float is_path_node;
+
+#define inwater(point) (pointcontents(point) == CONTENT_WATER)
+
+#endif
+#include "../pathlib.qh"
+
float pathlib_g_static(entity parent,vector to, float static_cost)
{
return parent.pathlib_node_g + static_cost;
+#include "../pathlib.qh"
#ifdef TURRET_DEBUG
void mark_error(vector where,float lifetime);
}
}
+void SUB_Remove();
+
void pathlib_showsquare(vector where,float goodsquare,float _lifetime)
{
entity s;
+#include "pathlib.qh"
+#include "utility.qh"
+
vector plib_points2[8];
vector plib_points[8];
float plib_fvals[8];
float pathlib_expandnode_starf(entity node, vector start, vector goal)
{
vector where,f,r,t;
- float i,fc,fc2,c;
+ float fc,c;
entity nap;
where = node.origin;
// Back-left
plib_points[7] = where - f - r;
- for(i=0;i < 8; ++i)
+ for(int i=0;i < 8; ++i)
{
t = plib_points[i];
fc = pathlib_heuristic(t,goal) + pathlib_cost(node, t, pathlib_gridsize);
plib_points2[0] = plib_points[0];
vector bp;
bp = plib_points[0];
- fc2 = 0;
- for(i = 0; i < 8; ++i)
+ int fc2 = 0;
+ for(int i = 0; i < 8; ++i)
{
c = 0;
nap = pathlib_nodeatpoint(plib_points[i]);
pathlib_makenode(node, start, bp, goal, pathlib_gridsize);
- for(i = 0; i < 3; ++i)
+ for(int i = 0; i < 3; ++i)
{
pathlib_makenode(node, start, plib_points2[i], goal, pathlib_gridsize);
}
+#include "../_all.qh"
+
+#include "pathlib.qh"
+#include "utility.qh"
+#include "../command/common.qh"
+
void pathlib_deletepath(entity start)
{
entity e;
--- /dev/null
+#ifndef PATHLIB_MAIN_H
+#define PATHLIB_MAIN_H
+float buildpath_nodefilter_none(vector n,vector c,vector p);
+entity path_build(entity next, vector where, entity prev, entity start);
+#endif
+#include "../_all.qh"
+
+#include "pathlib.qh"
+#include "utility.qh"
+
vector pathlib_wateroutnode(vector start,vector end, float doedge)
{
vector surface;
+#include "../bot/waypoints.qh"
+
+#include "pathlib.qh"
+#include "main.qh"
+
var float pathlib_wpp_open(entity wp, entity child, float cost);
void pathlib_wpp_close(entity wp)
#include "debug.qc"
#endif
-#include "utility.qc"
-#include "movenode.qc"
-#include "costs.qc"
-#include "expandnode.qc"
-#include "main.qc"
-#include "path_waypoint.qc"
#endif
+#include "utility.qh"
+
+#include "pathlib.qh"
+
float fsnap(float val,float fsize)
{
return rint(val / fsize) * fsize;
--- /dev/null
+#ifndef PATHLIB_UTILITY
+#define PATHLIB_UTILITY
+float fsnap(float val,float fsize);
+entity pathlib_nodeatpoint(vector where);
+float tile_check_plus2(vector where);
+#endif
void playerdemo_write_originvector(.vector f, string name)
{
- fputs(self.playerdemo_fh, strcat(vtos(self.f), "\n"));
+ fputs(self.playerdemo_fh, strcat(vtos(self.(f)), "\n"));
}
void playerdemo_write_sizevector(.vector f, string name)
{
- fputs(self.playerdemo_fh, strcat(vtos(self.f), "\n"));
+ fputs(self.playerdemo_fh, strcat(vtos(self.(f)), "\n"));
}
void playerdemo_write_vector(.vector f, string name)
{
- fputs(self.playerdemo_fh, strcat(vtos(self.f), "\n"));
+ fputs(self.playerdemo_fh, strcat(vtos(self.(f)), "\n"));
}
void playerdemo_write_string(.string f, string name)
{
- fputs(self.playerdemo_fh, strcat(self.f, "\n"));
+ fputs(self.playerdemo_fh, strcat(self.(f), "\n"));
}
void playerdemo_write_modelstring(.string f, string name)
{
- fputs(self.playerdemo_fh, strcat(self.f, "\n"));
+ fputs(self.playerdemo_fh, strcat(self.(f), "\n"));
}
void playerdemo_write_float(.float f, string name)
{
- fputs(self.playerdemo_fh, strcat(ftos(self.f), "\n"));
+ fputs(self.playerdemo_fh, strcat(ftos(self.(f)), "\n"));
}
void playerdemo_write()
{
}
void playerdemo_read_sizevector(.vector f, string name)
{
- self.f = stov(fgets(self.playerdemo_fh));
+ self.(f) = stov(fgets(self.playerdemo_fh));
setsize(self, self.mins, self.maxs);
}
void playerdemo_read_vector(.vector f, string name)
{
- self.f = stov(fgets(self.playerdemo_fh));
+ self.(f) = stov(fgets(self.playerdemo_fh));
}
void playerdemo_read_string(.string f, string name)
{
- string s;
- s = fgets(self.playerdemo_fh);
- if(s != self.f)
+ string s = fgets(self.playerdemo_fh);
+ if (s != self.(f))
{
/*
if(self.f)
strunzone(self.f);
*/
- self.f = strzone(s);
+ self.(f) = strzone(s);
}
}
void playerdemo_read_modelstring(.string f, string name)
{
- string s;
- s = fgets(self.playerdemo_fh);
- if(s != self.f)
+ string s = fgets(self.playerdemo_fh);
+ if (s != self.(f))
setmodel(self, s);
}
void playerdemo_read_float(.float f, string name)
{
- self.f = stof(fgets(self.playerdemo_fh));
+ self.(f) = stof(fgets(self.playerdemo_fh));
}
float playerdemo_read()
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/anglestransform.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
- #include "autocvars.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "../common/deathtypes.qh"
- #include "mutators/mutators_include.qh"
- #include "../csqcmodellib/sv_model.qh"
- #include "portals.qh"
- #include "g_hook.qh"
-#endif
+#include "portals.qh"
+#include "_all.qh"
+
+#include "g_hook.qh"
+#include "mutators/mutators_include.qh"
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/notifications.qh"
+#include "../common/triggers/teleporters.qh"
+#include "../common/triggers/subs.qh"
+#include "../common/util.qh"
+#include "../common/weapons/all.qh"
+#include "../csqcmodellib/sv_model.qh"
+#include "../warpzonelib/anglestransform.qh"
+#include "../warpzonelib/util_server.qh"
#define PORTALS_ARE_NOT_SOLID
return;
/*
- if(other.mins_x < PL_MIN_x || other.mins_y < PL_MIN_y || other.mins_z < PL_MIN_z
- || other.maxs_x > PL_MAX_x || other.maxs_y > PL_MAX_y || other.maxs_z > PL_MAX_z)
+ if(other.mins_x < PL_MIN.x || other.mins_y < PL_MIN.y || other.mins_z < PL_MIN.z
+ || other.maxs_x > PL_MAX.x || other.maxs_y > PL_MAX.y || other.maxs_z > PL_MAX.z)
{
// can't teleport this
return;
}
}
-void Portal_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void Portal_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(deathtype == DEATH_TELEFRAG)
return;
anticheat.qc
antilag.qc
-// assault.qc
campaign.qc
cheats.qc
cl_client.qc
cl_impulse.qc
-cl_physics.qc
cl_player.qc
csqceffects.qc
-// ctf.qc
-// domination.qc
ent_cs.qc
-func_breakable.qc
g_casings.qc
g_damage.qc
g_hook.qc
+// g_lights.qc // TODO: was never used
g_models.qc
g_subs.qc
g_tetris.qc
-g_triggers.qc
g_violence.qc
g_world.qc
ipban.qc
item_key.qc
mapvoting.qc
miscfunctions.qc
-// mode_onslaught.qc
movelib.qc
-// nexball.qc
+// pathlib.qc // TODO: was never used. Seems to duplicate `pathlib/`
playerdemo.qc
portals.qc
race.qc
round_handler.qc
-// runematch.qc
scores.qc
scores_rules.qc
-secret.qc
spawnpoints.qc
steerlib.qc
sv_main.qc
-target_music.qc
-target_spawn.qc
teamplay.qc
t_halflife.qc
t_items.qc
-t_jumppads.qc
-t_plats.qc
t_quake3.qc
t_quake.qc
-t_swamp.qc
-t_teleporters.qc
waypointsprites.qc
+bot/aim.qc
bot/bot.qc
+bot/navigation.qc
+bot/scripting.qc
+bot/waypoints.qc
-command/banning.qc
-command/cmd.qc
-command/common.qc
-command/getreplies.qc
-command/radarmap.qc
-command/sv_cmd.qc
-command/vote.qc
+bot/havocbot/havocbot.qc
+bot/havocbot/role_keyhunt.qc
+bot/havocbot/role_onslaught.qc
+bot/havocbot/roles.qc
+
+command/all.qc
mutators/mutators_include.qc
mutators/mutators.qc
+pathlib/costs.qc
+pathlib/expandnode.qc
+pathlib/main.qc
+pathlib/movenode.qc
+pathlib/path_waypoint.qc
+pathlib/utility.qc
+
+vehicles/all.qc
+
weapons/accuracy.qc
weapons/common.qc
weapons/csqcprojectile.qc // TODO
../common/buffs.qc
../common/campaign_file.qc
../common/campaign_setup.qc
-../common/command/generic.qc
-../common/command/markup.qc
-../common/command/rpn.qc
../common/mapinfo.qc
-../common/monsters/monsters.qc
+../common/monsters/all.qc
../common/monsters/spawn.qc
../common/monsters/sv_monsters.qc
+../common/movetypes/include.qc
../common/nades.qc
../common/net_notice.qc
../common/notifications.qc
+../common/physics.qc
../common/playerstats.qc
../common/test.qc
+../common/triggers/include.qc
../common/urllib.qc
../common/util.qc
+
+../common/items/all.qc
+
../common/weapons/config.qc
-../common/weapons/weapons.qc // TODO
+../common/weapons/all.qc // TODO
../csqcmodellib/sv_model.qc
#include "race.qh"
+#include "_all.qh"
+
+#include "cl_client.qh"
+#include "portals.qh"
+#include "scores.qh"
+#include "spawnpoints.qh"
+#include "waypointsprites.qh"
+#include "bot/waypoints.qh"
+#include "bot/navigation.qh"
+#include "command/getreplies.qh"
+#include "../common/deathtypes.qh"
+#include "../common/notifications.qh"
+#include "../common/mapinfo.qh"
+#include "../warpzonelib/util_server.qh"
void W_Porto_Fail(float failhard);
.float race_penalty_accumulator;
.string race_penalty_reason;
.float race_checkpoint; // player: next checkpoint that has to be reached
-.float race_laptime;
.entity race_lastpenalty;
.entity sprite;
WriteInt24_t(msg, race_readTime(GetMapname(), 1));
}
+
+void race_send_speedaward(float msg)
+{
+ // send the best speed of the round
+ WriteByte(msg, SVC_TEMPENTITY);
+ WriteByte(msg, TE_CSQC_RACE);
+ WriteByte(msg, RACE_NET_SPEED_AWARD);
+ WriteInt24_t(msg, floor(speedaward_speed+0.5));
+ WriteString(msg, speedaward_holder);
+}
+
+void race_send_speedaward_alltimebest(float msg)
+{
+ // send the best speed
+ WriteByte(msg, SVC_TEMPENTITY);
+ WriteByte(msg, TE_CSQC_RACE);
+ WriteByte(msg, RACE_NET_SPEED_AWARD_BEST);
+ WriteInt24_t(msg, floor(speedaward_alltimebest+0.5));
+ WriteString(msg, speedaward_alltimebest_holder);
+}
+
void race_SendRankings(float pos, float prevpos, float del, float msg)
{
WriteByte(msg, SVC_TEMPENTITY);
.float race_place;
.float race_started;
.float race_completed;
+.float race_laptime;
float race_completing;
.float race_movetime; // for reading
float race_readTime(string map, float pos);
string race_readUID(string map, float pos);
string race_readName(string map, float pos);
+void race_ClearRecords();
+void race_SendNextCheckpoint(entity e, float spec);
+void race_PreparePlayer();
+void race_send_recordtime(float msg);
+void race_send_speedaward(float msg);
+
+float speedaward_speed;
+string speedaward_holder;
+string speedaward_uid;
+
+float speedaward_alltimebest;
+string speedaward_alltimebest_holder;
+string speedaward_alltimebest_uid;
+
+void race_send_speedaward(float msg);
+
+void race_send_speedaward_alltimebest(float msg);
+
+void race_SendRankings(float pos, float prevpos, float del, float msg);
+
+void race_RetractPlayer();
+
#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/util.qh"
- #include "defs.qh"
- #include "round_handler.qh"
-#endif
+#include "round_handler.qh"
+#include "_all.qh"
+
+#include "command/vote.qh"
+#include "../common/util.qh"
void round_handler_Think()
{
#include "scores.qh"
+#include "_all.qh"
+
+#include "command/common.qh"
+#include "mutators/mutators_include.qh"
+#include "../common/playerstats.qh"
+#include "../common/teams.qh"
.entity scorekeeper;
entity teamscorekeepers[16];
return previous;
if((fieldflags & SFL_SORT_PRIO_MASK) < previous.y)
return previous;
- if(t1.field == t2.field)
+ if (t1.(field) == t2.(field))
return previous;
previous.y = fieldflags & SFL_SORT_PRIO_MASK;
if(fieldflags & SFL_ZERO_IS_WORST)
{
- if(t1.field == 0)
+ if (t1.(field) == 0)
{
previous.x = -1;
return previous;
}
- else if(t2.field == 0)
+ else if (t2.(field) == 0)
{
previous.x = +1;
return previous;
}
}
- if(fieldflags & SFL_LOWER_IS_BETTER)
- previous.x = (t2.field - t1.field);
+ if (fieldflags & SFL_LOWER_IS_BETTER)
+ previous.x = (t2.(field) - t1.(field));
else
- previous.x = (t1.field - t2.field);
+ previous.x = (t1.(field) - t2.(field));
return previous;
}
}
}
-float ScoreInfo_SendEntity(entity to, float sf)
+float ScoreInfo_SendEntity(entity to, int sf)
{
float i;
WriteByte(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
plist = world;
FOR_EACH_CLIENT(p)
- p.field = 0;
+ p.(field) = 0;
FOR_EACH_CLIENT(p) if(p.scorekeeper)
{
if(!plast || PlayerTeamScore_Compare(plast, pbest, teams, 0))
j = i;
- pbest.field = j;
+ pbest.(field) = j;
if (!pfirst)
pfirst = pbest;
#ifndef SCORES_H
#define SCORES_H
+#include "../common/constants.qh"
+
entity scores_initialized; // non-world when scores labels/rules have been set
.float scores[MAX_SCORE];
.float teamscores[MAX_TEAMSCORE];
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../common/constants.qh"
- #include "autocvars.qh"
- #include "defs.qh"
- #include "scores.qh"
-#endif
-
-//float c1, c2, c3, c4;
+#include "scores_rules.qh"
+#include "_all.qh"
+
+#include "cl_client.qh"
+#include "scores.qh"
+
void CheckAllowedTeams (entity for_whom);
// NOTE: SP_ constants may not be >= MAX_SCORE; ST_constants may not be >= MAX_TEAMSCORE
--- /dev/null
+#ifndef SCORES_RULES_H
+#define SCORES_RULES_H
+
+void ScoreRules_basics(float teams, float sprio, float stprio, float score_enabled);
+void ScoreRules_basics_end();
+void ScoreRules_generic();
+
+#endif
+++ /dev/null
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../common/util.qh"
- #include "defs.qh"
- #include "secret.qh"
-#endif
-
-void secrets_setstatus() {
- self.stat_secrets_total = secrets_total;
- self.stat_secrets_found = secrets_found;
-}
-
-/**
- * A secret has been found (maybe :P)
- */
-void trigger_secret_touch() {
- // only a player can trigger this
- if (!IS_PLAYER(other))
- return;
-
- // update secrets found counter
- secrets_found += 1;
- //print("Secret found: ", ftos(secret_counter.cnt), "/");
- //print(ftos(secret_counter.count), "\n");
-
- // centerprint message (multi_touch() doesn't always call centerprint())
- centerprint(other, self.message);
- self.message = "";
-
- // handle normal trigger features
- multi_touch();
- remove(self);
-}
-
-/*QUAKED trigger_secret (.5 .5 .5) ?
-Variable sized secret trigger. Can be targeted at one or more entities.
-Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
--------- KEYS --------
-sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
-noise: path to sound file, if you want to play something else
-target: trigger all entities with this targetname when triggered
-message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
-killtarget: remove all entities with this targetname when triggered
--------- NOTES --------
-You should create a common/trigger textured brush covering the entrance to a secret room/area.
-Trigger secret can only be trigger by a player's touch and can not be a target itself.
-*/
-void spawnfunc_trigger_secret() {
- // FIXME: should it be disabled in most modes?
-
- // update secrets count
- secrets_total += 1;
-
- // add default message
- if (self.message == "")
- self.message = "You found a secret!";
-
- // set default sound
- if (self.noise == "")
- if (!self.sounds)
- self.sounds = 1; // misc/secret.wav
-
- // this entity can't be a target itself!!!!
- self.targetname = "";
-
- // you can't just shoot a room to find it, can you?
- self.health = 0;
-
- // a secret can not be delayed
- self.delay = 0;
-
- // convert this trigger to trigger_once
- self.classname = "trigger_once";
- spawnfunc_trigger_once();
-
- // take over the touch() function, so we can mark secret as found
- self.touch = trigger_secret_touch;
- // ignore triggering;
- self.use = func_null;
-}
-
+++ /dev/null
-#ifndef SECRET_H
-#define SECRET_H
-
-/**
- * Total number of secrets on the map.
- */
-float secrets_total;
-
-/**
- * Total numbe of secrets found on the map.
- */
-float secrets_found;
-
-
-.float stat_secrets_total;
-.float stat_secrets_found;
-
-/**
- * update secrets status.
- */
-void secrets_setstatus();
-#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/constants.qh"
- #include "../common/teams.qh"
- #include "../common/util.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "mutators/mutators_include.qh"
- #include "spawnpoints.qh"
- #include "race.qh"
-#endif
-
-float SpawnPoint_Send(entity to, float sf)
+#include "spawnpoints.qh"
+#include "_all.qh"
+
+#include "mutators/mutators_include.qh"
+#include "g_world.qh"
+#include "race.qh"
+#include "../common/constants.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
+#include "../warpzonelib/util_server.qh"
+
+float SpawnPoint_Send(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
return true;
}
-float SpawnEvent_Send(entity to, float sf)
+float SpawnEvent_Send(entity to, int sf)
{
float send;
// nudge off the floor
setorigin(self, self.origin + '0 0 1');
- tracebox(self.origin, PL_MIN, PL_MAX, self.origin, true, self);
+ tracebox(self.origin, PL_MIN_CONST, PL_MAX_CONST, self.origin, true, self);
if (trace_startsolid)
{
vector o;
o = self.origin;
- self.mins = PL_MIN;
- self.maxs = PL_MAX;
+ self.mins = PL_MIN_CONST;
+ self.maxs = PL_MAX_CONST;
if (!move_out_of_solid(self))
objerror("could not get out of solid at all!");
print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
.vector spawnpoint_score;
float spawnpoint_nag;
-float SpawnEvent_Send(entity to, float sf);
+float SpawnEvent_Send(entity to, int sf);
entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck);
entity SelectSpawnPoint (float anypoint);
#endif
#include "../dpdefs/dpextensions.qh"
#endif
-.vector steerto;
-
/**
Uniform pull towards a point
**/
--- /dev/null
+#ifndef STEERLIB_H
+#define STEERLIB_H
+
+.vector steerto;
+
+vector steerlib_arrive(vector point,float maximal_distance);
+vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense);
+vector steerlib_pull(vector point);
+
+#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/common.qh"
- #include "../warpzonelib/server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
- #include "weapons/csqcprojectile.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/deathtypes.qh"
- #include "mutators/mutators_include.qh"
- #include "vehicles/vehicles_def.qh"
- #include "../common/mapinfo.qh"
- #include "command/common.qh"
- #include "../csqcmodellib/sv_model.qh"
- #include "anticheat.qh"
- #include "g_hook.qh"
-#endif
+#include "_all.qh"
+
+#include "anticheat.qh"
+#include "g_hook.qh"
+#include "g_world.qh"
+
+#include "bot/bot.qh"
+#include "bot/waypoints.qh"
+
+#include "command/common.qh"
+
+#include "mutators/mutators_include.qh"
+#include "vehicles/vehicle.qh"
+#include "weapons/csqcprojectile.qh"
+
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/mapinfo.qh"
+#include "../common/util.qh"
+
+#include "../common/weapons/all.qh"
+
+#include "../csqcmodellib/sv_model.qh"
+
+#include "../warpzonelib/common.qh"
+#include "../warpzonelib/server.qh"
+
+.float lastground;
void CreatureFrame (void)
{
if (g_footsteps)
if (!gameover)
if (self.flags & FL_ONGROUND)
+ if (!self.crouch)
if (velocity_len > autocvar_sv_maxspeed * 0.6)
if (!self.deadflag)
if (time < self.lastground + 0.2)
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../warpzonelib/util_server.qh"
- #include "defs.qh"
- #include "vehicles/vehicles_def.qh"
-#endif
-
.float roomtype;
.float radius;
.float pitch;
void spawnfunc_env_sound() {}
void spawnfunc_light_spot() {}
void spawnfunc_func_healthcharger() {}
-
-
-void func_ladder_touch()
-{
- if (!other.iscreature)
- return;
- if (other.vehicle_flags & VHF_ISVEHICLE)
- return;
-
- EXACTTRIGGER_TOUCH;
-
- other.ladder_time = time + 0.1;
- other.ladder_entity = self;
-}
-
-void spawnfunc_func_ladder()
-{
- EXACTTRIGGER_INIT;
- self.touch = func_ladder_touch;
-}
-
-void spawnfunc_func_water()
-{
- EXACTTRIGGER_INIT;
- self.touch = func_ladder_touch;
-}
-
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../common/util.qh"
- #include "../common/buffs.qh"
- #include "../common/weapons/weapons.qh"
- #include "../client/autocvars.qh"
- #include "../client/movetypes.qh"
- #include "../client/main.qh"
- #include "../csqcmodellib/common.qh"
- #include "../csqcmodellib/cl_model.qh"
- #include "t_items.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/monsters/monsters.qh"
- #include "../common/weapons/weapons.qh"
+#include "t_items.qh"
+
+#include "../common/items/all.qc"
+
+#if defined(SVQC)
+ #include "_all.qh"
+
+ #include "waypointsprites.qh"
+
+ #include "bot/bot.qh"
+ #include "bot/waypoints.qh"
+
+ #include "mutators/mutators_include.qh"
+
+ #include "weapons/common.qh"
+ #include "weapons/selection.qh"
#include "weapons/weaponsystem.qh"
- #include "t_items.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
+
+ #include "../common/constants.qh"
#include "../common/deathtypes.qh"
- #include "mutators/mutators_include.qh"
+ #include "../common/notifications.qh"
+ #include "../common/triggers/subs.qh"
+ #include "../common/util.qh"
+
+ #include "../common/monsters/all.qh"
+
+ #include "../common/weapons/all.qh"
+
+ #include "../warpzonelib/util_server.qh"
#endif
#ifdef CSQC
#endif
#ifdef SVQC
-float ItemSend(entity to, float sf)
+bool ItemSend(entity to, int sf)
{
if(self.gravity)
sf |= ISF_DROP;
float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
{
- if (!item.ammotype)
+ if (!item.(ammotype))
return false;
if (item.spawnshieldtime)
{
- if ((player.ammotype < ammomax) || item.pickup_anyway)
+ if ((player.(ammotype) < ammomax) || item.pickup_anyway)
{
- player.ammotype = bound(player.ammotype, ammomax, player.ammotype + item.ammotype);
+ player.(ammotype) = bound(player.(ammotype), ammomax, player.(ammotype) + item.(ammotype));
goto YEAH;
}
}
else if(g_weapon_stay == 2)
{
- float mi = min(item.ammotype, ammomax);
- if (player.ammotype < mi)
+ float mi = min(item.(ammotype), ammomax);
+ if (player.(ammotype) < mi)
{
- player.ammotype = mi;
+ player.(ammotype) = mi;
goto YEAH;
}
}
return 1;
}
+.entity itemdef;
+
void Item_Touch (void)
{
entity e, head;
self.invincible_finished = max(0, self.invincible_finished - time);
self.superweapons_finished = max(0, self.superweapons_finished - time);
}
-
- if(!Item_GiveTo(self, other))
+ entity it = self.itemdef;
+ bool gave = (it && it.instanceOfPickup) ? ITEM_HANDLE(Pickup, it, self, other) : Item_GiveTo(self, other);
+ if (!gave)
{
if (self.classname == "droppedweapon")
{
if (self.classname == "droppedweapon")
remove (self);
- else if (!self.spawnshieldtime)
- return;
- else
+ else if (self.spawnshieldtime)
{
if(self.team)
{
float weapon_pickupevalfunc(entity player, entity item)
{
- float c, j, position;
+ float c;
// See if I have it already
if(item.weapons & ~player.weapons)
if( bot_custom_weapon && c )
{
// Find the highest position on any range
- position = -1;
- for(j = 0; j < WEP_LAST ; ++j){
+ int position = -1;
+ for (int j = 0; j < WEP_LAST ; ++j){
if(
bot_weapons_far[j] == item.weapon ||
bot_weapons_mid[j] == item.weapon ||
return item.bot_pickupbasevalue * c;
}
-void Item_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void Item_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(ITEM_DAMAGE_NEEDKILL(deathtype))
RemoveItem();
return;
}
}
+
+void StartItemA (entity a)
+{
+ self.itemdef = a;
+ StartItem(a.m_model, a.m_sound, a.m_respawntime(), a.m_respawntimejitter(), a.m_name, a.m_itemid, 0, a.m_itemflags, a.m_pickupevalfunc, a.m_botvalue);
+}
+
void spawnfunc_item_rockets (void) {
if(!self.ammo_rockets)
self.ammo_rockets = g_pickup_rockets;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "rockets", IT_ROCKETS, 0, 0, commodity_pickupevalfunc, 3000);
+ StartItemA (ITEM_Rockets);
}
-void spawnfunc_item_shells (void);
void spawnfunc_item_bullets (void) {
if(!weaponswapping)
if(autocvar_sv_q3acompat_machineshotgunswap)
self.ammo_nails = g_pickup_nails;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "bullets", IT_NAILS, 0, 0, commodity_pickupevalfunc, 2000);
+ StartItemA (ITEM_Bullets);
}
void spawnfunc_item_cells (void) {
self.ammo_cells = g_pickup_cells;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
+ StartItemA (ITEM_Cells);
}
void spawnfunc_item_plasma()
self.ammo_plasma = g_pickup_plasma;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
+ StartItemA (ITEM_Plasma);
}
void spawnfunc_item_shells (void) {
self.ammo_shells = g_pickup_shells;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "shells", IT_SHELLS, 0, 0, commodity_pickupevalfunc, 500);
+ StartItemA (ITEM_Shells);
}
void spawnfunc_item_armor_small (void) {
self.max_armorvalue = g_pickup_armorsmall_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorsmall_anyway;
- StartItem ("models/items/item_armor_small.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_ArmorSmall);
}
void spawnfunc_item_armor_medium (void) {
self.max_armorvalue = g_pickup_armormedium_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armormedium_anyway;
- StartItem ("models/items/item_armor_medium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+ StartItemA (ITEM_ArmorMedium);
}
void spawnfunc_item_armor_big (void) {
self.max_armorvalue = g_pickup_armorbig_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorbig_anyway;
- StartItem ("models/items/item_armor_big.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000);
+ StartItemA (ITEM_ArmorBig);
}
void spawnfunc_item_armor_large (void) {
self.max_armorvalue = g_pickup_armorlarge_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorlarge_anyway;
- StartItem ("models/items/item_armor_large.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+ StartItemA (ITEM_ArmorLarge);
}
void spawnfunc_item_health_small (void) {
self.health = g_pickup_healthsmall;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthsmall_anyway;
- StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Health", IT_5HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_HealthSmall);
}
void spawnfunc_item_health_medium (void) {
self.health = g_pickup_healthmedium;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthmedium_anyway;
- StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "25 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+ StartItemA (ITEM_HealthMedium);
}
void spawnfunc_item_health_large (void) {
self.health = g_pickup_healthlarge;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthlarge_anyway;
- StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "50 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+ StartItemA (ITEM_HealthLarge);
}
void spawnfunc_item_health_mega (void) {
- if(!self.max_health)
- self.max_health = g_pickup_healthmega_max;
- if(!self.health)
- self.health = g_pickup_healthmega;
- if(!self.pickup_anyway)
- self.pickup_anyway = g_pickup_healthmega_anyway;
- StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+ if(!self.max_health)
+ self.max_health = g_pickup_healthmega_max;
+ if(!self.health)
+ self.health = g_pickup_healthmega;
+ if(!self.pickup_anyway)
+ self.pickup_anyway = g_pickup_healthmega_anyway;
+ StartItemA (ITEM_HealthMega);
}
// support old misnamed entities
precache_sound("weapons/strength_fire.wav");
if(!self.strength_finished)
self.strength_finished = autocvar_g_balance_powerup_strength_time;
- StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
+ StartItemA (ITEM_Strength);
}
void spawnfunc_item_invincible (void) {
if(!self.invincible_finished)
self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
- StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
+ StartItemA (ITEM_Shield);
}
// compatibility:
self.ammo_fuel = g_pickup_fuel;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/g_fuel.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "Fuel", IT_FUEL, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_JetpackFuel);
}
void spawnfunc_item_fuel_regen(void)
spawnfunc_item_fuel();
return;
}
- StartItem ("models/items/g_fuelregen.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Fuel regenerator", IT_FUEL_REGEN, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_JetpackRegen);
}
void spawnfunc_item_jetpack(void)
spawnfunc_item_fuel();
return;
}
- StartItem ("models/items/g_jetpack.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Jet pack", IT_JETPACK, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_Jetpack);
}
float GiveWeapon(entity e, float wpn, float op, float val)
float GiveBit(entity e, .float fld, float bit, float op, float val)
{
float v0, v1;
- v0 = (e.fld & bit);
+ v0 = (e.(fld) & bit);
switch(op)
{
case OP_SET:
if(val > 0)
- e.fld |= bit;
+ e.(fld) |= bit;
else
- e.fld &= ~bit;
+ e.(fld) &= ~bit;
break;
case OP_MIN:
case OP_PLUS:
if(val > 0)
- e.fld |= bit;
+ e.(fld) |= bit;
break;
case OP_MAX:
if(val <= 0)
- e.fld &= ~bit;
+ e.(fld) &= ~bit;
break;
case OP_MINUS:
if(val > 0)
- e.fld &= ~bit;
+ e.(fld) &= ~bit;
break;
}
- v1 = (e.fld & bit);
+ v1 = (e.(fld) & bit);
return (v0 != v1);
}
float GiveValue(entity e, .float fld, float op, float val)
{
float v0, v1;
- v0 = e.fld;
+ v0 = e.(fld);
switch(op)
{
case OP_SET:
- e.fld = val;
+ e.(fld) = val;
break;
case OP_MIN:
- e.fld = max(e.fld, val); // min 100 cells = at least 100 cells
+ e.(fld) = max(e.(fld), val); // min 100 cells = at least 100 cells
break;
case OP_MAX:
- e.fld = min(e.fld, val);
+ e.(fld) = min(e.(fld), val);
break;
case OP_PLUS:
- e.fld += val;
+ e.(fld) += val;
break;
case OP_MINUS:
- e.fld -= val;
+ e.(fld) -= val;
break;
}
- v1 = e.fld;
+ v1 = e.(fld);
return (v0 != v1);
}
void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime)
{
if(v0 < v1)
- e.rotfield = max(e.rotfield, time + rottime);
+ e.(rotfield) = max(e.(rotfield), time + rottime);
else if(v0 > v1)
- e.regenfield = max(e.regenfield, time + regentime);
+ e.(regenfield) = max(e.(regenfield), time + regentime);
}
float GiveItems(entity e, float beginarg, float endarg)
{
const int IT_FUEL_REGEN = 32; // fuel regeneration trigger
// where is 64... ?
const int IT_FUEL = 128;
-const int IT_SHELLS = 256;
-const int IT_NAILS = 512;
-const int IT_ROCKETS = 1024;
-const int IT_CELLS = 2048;
+// -Wdouble-declaration
+#define IT_SHELLS 256
+// -Wdouble-declaration
+#define IT_NAILS 512
+// -Wdouble-declaration
+#define IT_ROCKETS 1024
+// -Wdouble-declaration
+#define IT_CELLS 2048
const int IT_SUPERWEAPON = 4096;
const int IT_STRENGTH = 8192;
const int IT_INVINCIBLE = 16384;
// shared value space (union):
// for items:
- const int IT_KEY1 = 131072;
- const int IT_KEY2 = 262144;
+ // -Wdouble-declaration
+ #define IT_KEY1 131072
+ // -Wdouble-declaration
+ #define IT_KEY2 262144
// for players:
const int IT_RED_FLAG_TAKEN = 32768;
const int IT_RED_FLAG_LOST = 65536;
#endif
#ifdef SVQC
+void spawnfunc_item_strength();
+void spawnfunc_item_invincible();
+void spawnfunc_item_armor_small();
+void spawnfunc_item_shells();
+void spawnfunc_item_bullets();
+void spawnfunc_item_rockets();
+
float autocvar_sv_simple_items;
-float ItemSend(entity to, float sf);
+bool ItemSend(entity to, int sf);
float have_pickup_item(void);
// Savage: used for item garbage-collection
// TODO: perhaps nice special effect?
-float ItemSend(entity to, float sf);
+bool ItemSend(entity to, int sf);
void ItemUpdate(entity item);
// pickup evaluation functions
+++ /dev/null
-#include "t_jumppads.qh"
-
-void trigger_push_use()
-{
- if(teamplay)
- self.team = activator.team;
-}
-
-/*
- trigger_push_calculatevelocity
-
- Arguments:
- org - origin of the object which is to be pushed
- tgt - target entity (can be either a point or a model entity; if it is
- the latter, its midpoint is used)
- ht - jump height, measured from the higher one of org and tgt's midpoint
-
- Returns: velocity for the jump
- the global trigger_push_calculatevelocity_flighttime is set to the total
- jump time
- */
-
-vector trigger_push_calculatevelocity(vector org, entity tgt, float ht)
-{
- float grav, sdist, zdist, vs, vz, jumpheight;
- vector sdir, torg;
-
- torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
-
- grav = autocvar_sv_gravity;
- if(other.gravity)
- grav *= other.gravity;
-
- zdist = torg.z - org.z;
- sdist = vlen(torg - org - zdist * '0 0 1');
- sdir = normalize(torg - org - zdist * '0 0 1');
-
- // how high do we need to push the player?
- jumpheight = fabs(ht);
- if(zdist > 0)
- jumpheight = jumpheight + zdist;
-
- /*
- STOP.
-
- You will not understand the following equations anyway...
- But here is what I did to get them.
-
- I used the functions
-
- s(t) = t * vs
- z(t) = t * vz - 1/2 grav t^2
-
- and solved for:
-
- s(ti) = sdist
- z(ti) = zdist
- max(z, ti) = jumpheight
-
- From these three equations, you will find the three parameters vs, vz
- and ti.
- */
-
- // push him so high...
- vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
-
- // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
- if(ht < 0)
- if(zdist < 0)
- vz = -vz;
-
- vector solution;
- solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
- // ALWAYS solvable because jumpheight >= zdist
- if(!solution.z)
- solution.y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
- if(zdist == 0)
- solution.x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
-
- if(zdist < 0)
- {
- // down-jump
- if(ht < 0)
- {
- // almost straight line type
- // jump apex is before the jump
- // we must take the larger one
- trigger_push_calculatevelocity_flighttime = solution.y;
- }
- else
- {
- // regular jump
- // jump apex is during the jump
- // we must take the larger one too
- trigger_push_calculatevelocity_flighttime = solution.y;
- }
- }
- else
- {
- // up-jump
- if(ht < 0)
- {
- // almost straight line type
- // jump apex is after the jump
- // we must take the smaller one
- trigger_push_calculatevelocity_flighttime = solution.x;
- }
- else
- {
- // regular jump
- // jump apex is during the jump
- // we must take the larger one
- trigger_push_calculatevelocity_flighttime = solution.y;
- }
- }
- vs = sdist / trigger_push_calculatevelocity_flighttime;
-
- // finally calculate the velocity
- return sdir * vs + '0 0 1' * vz;
-}
-
-void trigger_push_touch()
-{
- if (self.active == ACTIVE_NOT)
- return;
-
- if (!isPushable(other))
- return;
-
- if(self.team)
- if(((self.spawnflags & 4) == 0) == (self.team != other.team))
- return;
-
- EXACTTRIGGER_TOUCH;
-
- if(self.enemy)
- {
- other.velocity = trigger_push_calculatevelocity(other.origin, self.enemy, self.height);
- }
- else if(self.target)
- {
- entity e;
- RandomSelection_Init();
- for(e = world; (e = find(e, targetname, self.target)); )
- {
- if(e.cnt)
- RandomSelection_Add(e, 0, string_null, e.cnt, 1);
- else
- RandomSelection_Add(e, 0, string_null, 1, 1);
- }
- other.velocity = trigger_push_calculatevelocity(other.origin, RandomSelection_chosen_ent, self.height);
- }
- else
- {
- other.velocity = self.movedir;
- }
-
- other.flags &= ~FL_ONGROUND;
-
- if (IS_PLAYER(other))
- {
- // reset tracking of oldvelocity for impact damage (sudden velocity changes)
- other.oldvelocity = other.velocity;
-
- if(self.pushltime < time) // prevent "snorring" sound when a player hits the jumppad more than once
- {
- // flash when activated
- pointparticles(particleeffectnum("jumppad_activate"), other.origin, other.velocity, 1);
- sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
- self.pushltime = time + 0.2;
- }
- if(IS_REAL_CLIENT(other) || IS_BOT_CLIENT(other))
- {
- bool found = false;
- for(int i = 0; i < other.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
- if(other.(jumppadsused[i]) == self)
- found = true;
- if(!found)
- {
- other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = self;
- other.jumppadcount = other.jumppadcount + 1;
- }
-
- if(IS_REAL_CLIENT(other))
- {
- if(self.message)
- centerprint(other, self.message);
- }
- else
- other.lastteleporttime = time;
-
- if (other.deadflag == DEAD_NO)
- animdecide_setaction(other, ANIMACTION_JUMP, true);
- }
- else
- other.jumppadcount = true;
-
- // reset tracking of who pushed you into a hazard (for kill credit)
- other.pushltime = 0;
- other.istypefrag = 0;
- }
-
- if(self.enemy.target)
- {
- entity oldself;
- oldself = self;
- activator = other;
- self = self.enemy;
- SUB_UseTargets();
- self = oldself;
- }
-
- if (other.flags & FL_PROJECTILE)
- {
- other.angles = vectoangles (other.velocity);
- switch(other.movetype)
- {
- case MOVETYPE_FLY:
- other.movetype = MOVETYPE_TOSS;
- other.gravity = 1;
- break;
- case MOVETYPE_BOUNCEMISSILE:
- other.movetype = MOVETYPE_BOUNCE;
- other.gravity = 1;
- break;
- }
- UpdateCSQCProjectile(other);
- }
-
- if (self.spawnflags & PUSH_ONCE)
- {
- self.touch = func_null;
- self.think = SUB_Remove;
- self.nextthink = time;
- }
-}
-
-void trigger_push_findtarget()
-{
- entity e, t;
- vector org;
-
- // first calculate a typical start point for the jump
- org = (self.absmin + self.absmax) * 0.5;
- org.z = self.absmax.z - PL_MIN_z;
-
- if (self.target)
- {
- float n;
- n = 0;
- for(t = world; (t = find(t, targetname, self.target)); )
- {
- ++n;
- e = spawn();
- setorigin(e, org);
- setsize(e, PL_MIN, PL_MAX);
- e.velocity = trigger_push_calculatevelocity(org, t, self.height);
- tracetoss(e, e);
- if(e.movetype == MOVETYPE_NONE)
- waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
- remove(e);
- }
-
- if(n == 0)
- {
- // no dest!
- objerror ("Jumppad with nonexistant target");
- return;
- }
- else if(n == 1)
- {
- // exactly one dest - bots love that
- self.enemy = find(world, targetname, self.target);
- }
- else
- {
- // have to use random selection every single time
- self.enemy = world;
- }
- }
- else
- {
- e = spawn();
- setorigin(e, org);
- setsize(e, PL_MIN, PL_MAX);
- e.velocity = self.movedir;
- tracetoss(e, e);
- waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
- remove(e);
- }
-}
-
-/*
- * ENTITY PARAMETERS:
- *
- * target: target of jump
- * height: the absolute value is the height of the highest point of the jump
- * trajectory above the higher one of the player and the target.
- * the sign indicates whether the highest point is INSIDE (positive)
- * or OUTSIDE (negative) of the jump trajectory. General rule: use
- * positive values for targets mounted on the floor, and use negative
- * values to target a point on the ceiling.
- * movedir: if target is not set, this * speed * 10 is the velocity to be reached.
- */
-void spawnfunc_trigger_push()
-{
- SetMovedir ();
-
- EXACTTRIGGER_INIT;
-
- self.active = ACTIVE_ACTIVE;
- self.use = trigger_push_use;
- self.touch = trigger_push_touch;
-
- // normal push setup
- if (!self.speed)
- self.speed = 1000;
- self.movedir = self.movedir * self.speed * 10;
-
- if (!self.noise)
- self.noise = "misc/jumppad.wav";
- precache_sound (self.noise);
-
- // this must be called to spawn the teleport waypoints for bots
- InitializeEntity(self, trigger_push_findtarget, INITPRIO_FINDTARGET);
-}
-
-void spawnfunc_target_push() {}
-void spawnfunc_info_notnull() {}
-void spawnfunc_target_position() {}
+++ /dev/null
-#ifndef T_JUMPPADS_H
-#define T_JUMPPADS_H
-
-const float PUSH_ONCE = 1;
-const float PUSH_SILENT = 2;
-
-.float pushltime;
-.float istypefrag;
-.float height;
-
-void() SUB_UseTargets;
-
-float trigger_push_calculatevelocity_flighttime;
-
-void trigger_push_use();
-
-/*
- trigger_push_calculatevelocity
-
- Arguments:
- org - origin of the object which is to be pushed
- tgt - target entity (can be either a point or a model entity; if it is
- the latter, its midpoint is used)
- ht - jump height, measured from the higher one of org and tgt's midpoint
-
- Returns: velocity for the jump
- the global trigger_push_calculatevelocity_flighttime is set to the total
- jump time
- */
-
-vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
-
-void trigger_push_touch();
-
-.vector dest;
-void trigger_push_findtarget();
-
-/*
- * ENTITY PARAMETERS:
- *
- * target: target of jump
- * height: the absolute value is the height of the highest point of the jump
- * trajectory above the higher one of the player and the target.
- * the sign indicates whether the highest point is INSIDE (positive)
- * or OUTSIDE (negative) of the jump trajectory. General rule: use
- * positive values for targets mounted on the floor, and use negative
- * values to target a point on the ceiling.
- * movedir: if target is not set, this * speed * 10 is the velocity to be reached.
- */
-void spawnfunc_trigger_push();
-
-void spawnfunc_target_push();
-void spawnfunc_info_notnull();
-void spawnfunc_target_position();
-#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/mathlib.qh"
- #include "../warpzonelib/common.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/weapons/weapons.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/notifications.qh"
- #include "../common/deathtypes.qh"
- #include "command/common.qh"
- #include "../csqcmodellib/sv_model.qh"
-#endif
+#include "_all.qh"
+
+#include "bot/bot.qh"
+
+#include "command/common.qh"
+
+#include "g_damage.qh"
+#include "item_key.qh"
+
+#include "../common/constants.qh"
+#include "../common/deathtypes.qh"
+#include "../common/notifications.qh"
+#include "../common/util.qh"
+
+#include "../common/weapons/all.qh"
+
+#include "../csqcmodellib/sv_model.qh"
+
+#include "../warpzonelib/common.qh"
+#include "../warpzonelib/mathlib.qh"
+#include "../warpzonelib/util_server.qh"
+
+.float height;
.float dmgtime2;
void generic_plat_blocked()
button_fire ();
}
-void button_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void button_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(self.spawnflags & DOOR_NOSPLASH)
if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
}
-void door_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void door_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
entity oself;
if(self.spawnflags & DOOR_NOSPLASH)
sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
}
-void fd_secret_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void fd_secret_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
fd_secret_use();
}
-#include "../common/weapons/weapons.qc"
+#include "_all.qh"
+
+#include "../common/weapons/all.qh"
+
+void spawnfunc_weapon_electro();
+void spawnfunc_weapon_hagar();
+void spawnfunc_weapon_machinegun();
+void spawnfunc_item_bullets();
+void spawnfunc_item_armor_large();
+void spawnfunc_item_armor_large();
+void spawnfunc_item_health_mega();
+void spawnfunc_item_health_medium();
//***********************
//QUAKE 1 ENTITIES - So people can play quake1 maps with the xonotic weapons
-#include "../common/weapons/weapons.qc"
+#include "_all.qh"
+
+#include "../common/weapons/all.qh"
+#include "../common/buffs.qh"
+
+void spawnfunc_weapon_crylink();
+void spawnfunc_weapon_electro();
+void spawnfunc_weapon_hagar();
+void spawnfunc_weapon_machinegun();
+void spawnfunc_weapon_vortex();
+
+void spawnfunc_target_items();
+
+void spawnfunc_item_bullets();
+void spawnfunc_item_cells();
+void spawnfunc_item_rockets();
+void spawnfunc_item_shells();
+
+void spawnfunc_item_jetpack();
+
+void spawnfunc_item_armor_big();
+void spawnfunc_item_armor_large();
+void spawnfunc_item_armor_small();
+
+void spawnfunc_item_health_medium();
+void spawnfunc_item_health_mega();
//***********************
//QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
+++ /dev/null
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../common/weapons/weapons.qh"
- #include "defs.qh"
- #include "../common/deathtypes.qh"
-#endif
-
-/*
-* t_swamp.c
-* Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
-* Author tZork (Jakob MG)
-* jakob@games43.se
-* 2005 11 29
-*/
-
-.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 (!?)
-.entity swampslug;
-
-void spawnfunc_trigger_swamp(void);
-void swamp_touch(void);
-void swampslug_think();
-
-
-/*
-* Uses a entity calld swampslug to handle players in the swamp
-* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
-* attaches a new "swampslug" to the player. As long as the plyer is inside
-* the swamp the swamp gives the slug new health. But the slug slowly kills itself
-* so when the player goes outside the swamp, it dies and releases the player from the
-* swamps curses (dmg/slowdown)
-*
-* I do it this way becuz there is no "untouch" event.
-*
-* --NOTE--
-* THE ACCTUAL slowdown is done in cl_physics.c on line 57-60
-* --NOTE--
-*/
-void swampslug_think(void)
-{
- //Slowly kill the slug
- self.health = self.health - 1;
-
- //Slug dead? then remove curses.
- if(self.health <= 0) {
- self.owner.in_swamp = 0;
- remove(self);
- //centerprint(self.owner,"Killing slug...\n");
- return;
- }
-
- // Slug still alive, so we are still in the swamp
- // Or we have exited it very recently.
- // Do the damage and renew the timer.
- Damage (self.owner, self, self, self.dmg, DEATH_SWAMP, other.origin, '0 0 0');
-
- self.nextthink = time + self.swamp_interval;
-}
-
-void swamp_touch(void)
-{
- // If whatever thats touching the swamp is not a player
- // or if its a dead player, just dont care abt it.
- if(!IS_PLAYER(other) || other.deadflag != DEAD_NO)
- return;
-
- EXACTTRIGGER_TOUCH;
-
- // Chech if player alredy got a swampslug.
- if(other.in_swamp != 1) {
- // If not attach one.
- //centerprint(other,"Entering swamp!\n");
- other.swampslug = spawn();
- other.swampslug.health = 2;
- other.swampslug.think = swampslug_think;
- other.swampslug.nextthink = time;
- other.swampslug.owner = other;
- other.swampslug.dmg = self.dmg;
- other.swampslug.swamp_interval = self.swamp_interval;
- other.swamp_slowdown = self.swamp_slowdown;
- other.in_swamp = 1;
- return;
- }
-
- //other.in_swamp = 1;
-
- //Revitalize players swampslug
- other.swampslug.health = 2;
-}
-
-/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
-Players gettin into the swamp will
-get slowd down and damaged
-*/
-void spawnfunc_trigger_swamp(void)
-{
- // Init stuff
- EXACTTRIGGER_INIT;
- self.touch = swamp_touch;
-
- // Setup default keys, if missing
- if(self.dmg <= 0)
- self.dmg = 5;
- if(self.swamp_interval <= 0)
- self.swamp_interval = 1;
- if(self.swamp_slowdown <= 0)
- self.swamp_slowdown = 0.5;
-}
+++ /dev/null
-#include "t_teleporters.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../warpzonelib/common.qh"
- #include "../warpzonelib/util_server.qh"
- #include "../warpzonelib/server.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "weapons/csqcprojectile.qh"
- #include "autocvars.qh"
- #include "constants.qh"
- #include "defs.qh"
- #include "../common/deathtypes.qh"
- #include "tturrets/include/turrets_early.qh"
- #include "vehicles/vehicles_def.qh"
- #include "../common/mapinfo.qh"
- #include "anticheat.qh"
-#endif
-
-void trigger_teleport_use()
-{
- if(teamplay)
- self.team = activator.team;
-}
-
-float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
-{
- if (IS_PLAYER(player) && player.health >= 1)
- {
- TDEATHLOOP(org)
- {
- if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
- if(IS_PLAYER(head))
- if(head.health >= 1)
- return 1;
- }
- }
- return 0;
-}
-
-void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
-{
- TDEATHLOOP(player.origin)
- {
- if (IS_PLAYER(player) && player.health >= 1)
- {
- if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
- {
- if(IS_PLAYER(head))
- if(head.health >= 1)
- ++tdeath_hit;
- Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG, head.origin, '0 0 0');
- }
- }
- else // dead bodies and monsters gib themselves instead of telefragging
- Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG, telefragger.origin, '0 0 0');
- }
-}
-
-void spawn_tdeath(vector v0, entity e, vector v)
-{
- tdeath(e, e, e, '0 0 0', '0 0 0');
-}
-
-void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
-{
- entity telefragger;
- vector from;
-
- if(teleporter.owner)
- telefragger = teleporter.owner;
- else
- telefragger = player;
-
- makevectors (to_angles);
-
- if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
- {
- if(self.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
- {
- if(tflags & TELEPORT_FLAG_SOUND)
- sound (player, CH_TRIGGER, "misc/teleport.wav", VOL_BASE, ATTEN_NORM);
- if(tflags & TELEPORT_FLAG_PARTICLES)
- {
- pointparticles(particleeffectnum("teleport"), player.origin, '0 0 0', 1);
- pointparticles(particleeffectnum("teleport"), to + v_forward * 32, '0 0 0', 1);
- }
- self.pushltime = time + 0.2;
- }
- }
-
- // Relocate the player
- // assuming to allows PL_MIN to PL_MAX box and some more
- from = player.origin;
- setorigin (player, to);
- player.oldorigin = to; // don't undo the teleport by unsticking
- player.angles = to_angles;
- player.fixangle = true;
- player.velocity = to_velocity;
- BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
-
- makevectors(player.angles);
- Reset_ArcBeam(player, v_forward);
- UpdateCSQCProjectileAfterTeleport(player);
-
- if(IS_PLAYER(player))
- {
- if(tflags & TELEPORT_FLAG_TDEATH)
- if(player.takedamage && player.deadflag == DEAD_NO && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH)))
- tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
-
- // player no longer is on ground
- player.flags &= ~FL_ONGROUND;
-
- // reset tracking of oldvelocity for impact damage (sudden velocity changes)
- player.oldvelocity = player.velocity;
-
- // reset tracking of who pushed you into a hazard (for kill credit)
- if(teleporter.owner)
- {
- player.pusher = teleporter.owner;
- player.pushltime = time + autocvar_g_maxpushtime;
- player.istypefrag = player.BUTTON_CHAT;
- }
- else
- {
- player.pushltime = 0;
- player.istypefrag = 0;
- }
-
- player.lastteleporttime = time;
- }
-}
-
-entity Simple_TeleportPlayer(entity teleporter, entity player)
-{
- vector locout;
- entity e;
- float p;
-
- // Find the output teleporter
- if(teleporter.enemy)
- {
- e = teleporter.enemy;
- }
- else
- {
- RandomSelection_Init();
- for(e = world; (e = find(e, targetname, teleporter.target)); )
- {
- p = 1;
- if(autocvar_g_telefrags_avoid)
- {
- locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
- if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
- p = 0;
- }
- RandomSelection_Add(e, 0, string_null, (e.cnt ? e.cnt : 1), p);
- }
- e = RandomSelection_chosen_ent;
- }
-
- if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
-
- makevectors(e.mangle);
-
- if(e.speed)
- if(vlen(player.velocity) > e.speed)
- player.velocity = normalize(player.velocity) * max(0, e.speed);
-
- if(autocvar_g_teleport_maxspeed)
- if(vlen(player.velocity) > autocvar_g_teleport_maxspeed)
- player.velocity = normalize(player.velocity) * max(0, autocvar_g_teleport_maxspeed);
-
- locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
- TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
-
- return e;
-}
-
-void Teleport_Touch (void)
-{
- entity oldself;
- string s;
-
- if (self.active != ACTIVE_ACTIVE)
- return;
-
- if (!other.teleportable)
- return;
-
- if(other.vehicle)
- if(!other.vehicle.teleportable)
- return;
-
- if(other.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
- return;
-
- if(other.deadflag != DEAD_NO)
- return;
-
- if(self.team)
- if(((self.spawnflags & 4) == 0) == (self.team != other.team))
- return;
-
- EXACTTRIGGER_TOUCH;
-
- if(IS_PLAYER(other))
- RemoveGrapplingHook(other);
-
- entity e;
- e = Simple_TeleportPlayer(self, other);
-
- activator = other;
- s = self.target; self.target = string_null;
- SUB_UseTargets();
- if (!self.target) self.target = s;
-
- oldself = self;
- self = e;
- SUB_UseTargets();
- self = oldself;
-}
-
-void spawnfunc_info_teleport_destination (void)
-{
- self.classname = "info_teleport_destination";
-
- self.mangle = self.angles;
- self.angles = '0 0 0';
-
- //setorigin (self, self.origin + '0 0 27'); // To fix a mappers' habit as old as Quake
- setorigin (self, self.origin);
-
- IFTARGETED
- {
- }
- else
- objerror ("^3Teleport destination without a targetname");
-}
-
-void spawnfunc_misc_teleporter_dest (void)
-{
- spawnfunc_info_teleport_destination();
-}
-
-void spawnfunc_target_teleporter (void)
-{
- spawnfunc_info_teleport_destination();
-}
-
-void teleport_findtarget (void)
-{
- entity e;
- float n;
-
- n = 0;
- for(e = world; (e = find(e, targetname, self.target)); )
- {
- ++n;
- if(e.movetype == MOVETYPE_NONE)
- waypoint_spawnforteleporter(self, e.origin, 0);
- if(e.classname != "info_teleport_destination")
- print("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.\n");
- }
-
- if(n == 0)
- {
- // no dest!
- objerror ("Teleporter with nonexistant target");
- return;
- }
- else if(n == 1)
- {
- // exactly one dest - bots love that
- self.enemy = find(e, targetname, self.target);
- }
- else
- {
- // have to use random selection every single time
- self.enemy = world;
- }
-
- // now enable touch
- self.touch = Teleport_Touch;
-}
-
-entity Teleport_Find(vector mi, vector ma)
-{
- entity e;
- for(e = world; (e = find(e, classname, "trigger_teleport")); )
- if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
- return e;
- return world;
-}
-
-void spawnfunc_trigger_teleport (void)
-{
- self.angles = '0 0 0';
-
- EXACTTRIGGER_INIT;
-
- self.active = ACTIVE_ACTIVE;
-
- self.use = trigger_teleport_use;
-
- // this must be called to spawn the teleport waypoints for bots
- InitializeEntity(self, teleport_findtarget, INITPRIO_FINDTARGET);
-
- if (self.target == "")
- {
- objerror ("Teleporter with no target");
- return;
- }
-
- self.teleport_next = teleport_first;
- teleport_first = self;
-}
-
-void WarpZone_PostTeleportPlayer_Callback(entity pl)
-{
- makevectors(pl.angles);
- Reset_ArcBeam(pl, v_forward);
- UpdateCSQCProjectileAfterTeleport(pl);
- {
- entity oldself = self;
- self = pl;
- anticheat_fixangle();
- self = oldself;
- }
- // "disown" projectiles after teleport
- if(pl.owner)
- if(pl.owner == pl.realowner)
- {
- if(!(pl.flags & FL_PROJECTILE))
- print("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".\n");
- pl.owner = world;
- }
- if(IS_PLAYER(pl))
- {
- // reset tracking of oldvelocity for impact damage (sudden velocity changes)
- pl.oldvelocity = pl.velocity;
- // reset teleport time tracking too (or multijump can cause insane speeds)
- pl.lastteleporttime = time;
- }
-}
+++ /dev/null
-#ifndef T_TELEPORTERS_H
-#define T_TELEPORTERS_H
-
-void trigger_teleport_use();
-
-#define TDEATHLOOP(o) \
- entity head; \
- vector deathmin; \
- vector deathmax; \
- float deathradius; \
- deathmin = (o) + player.mins; \
- deathmax = (o) + player.maxs; \
- if(telefragmin != telefragmax) \
- { \
- if(deathmin.x > telefragmin.x) deathmin.x = telefragmin.x; \
- if(deathmin.y > telefragmin.y) deathmin.y = telefragmin.y; \
- if(deathmin.z > telefragmin.z) deathmin.z = telefragmin.z; \
- if(deathmax.x < telefragmax.x) deathmax.x = telefragmax.x; \
- if(deathmax.y < telefragmax.y) deathmax.y = telefragmax.y; \
- if(deathmax.z < telefragmax.z) deathmax.z = telefragmax.z; \
- } \
- deathradius = max(vlen(deathmin), vlen(deathmax)); \
- for(head = findradius(o, deathradius); head; head = head.chain) \
- if(head != player) \
- if(head.takedamage) \
- if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
-
-
-float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax);
-float tdeath_hit;
-void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax);
-
-void spawn_tdeath(vector v0, entity e, vector v);
-
-.entity pusher;
-const float TELEPORT_FLAG_SOUND = 1;
-const float TELEPORT_FLAG_PARTICLES = 2;
-const float TELEPORT_FLAG_TDEATH = 4;
-const float TELEPORT_FLAG_FORCE_TDEATH = 8;
-
-#define TELEPORT_FLAGS_WARPZONE 0
-#define TELEPORT_FLAGS_PORTAL (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH)
-#define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH)
-
-// types for .teleportable entity setting
-const float TELEPORT_NORMAL = 1; // play sounds/effects etc
-const float TELEPORT_SIMPLE = 2; // only do teleport, nothing special
-
-void Reset_ArcBeam(entity player, vector forward);
-void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags);
-
-entity Simple_TeleportPlayer(entity teleporter, entity player);
-
-void Teleport_Touch (void);
-
-void spawnfunc_info_teleport_destination (void);
-
-void spawnfunc_misc_teleporter_dest (void);
-
-void spawnfunc_target_teleporter (void);
-
-void teleport_findtarget (void);
-
-entity Teleport_Find(vector mi, vector ma);
-
-entity teleport_first;
-.entity teleport_next;
-void spawnfunc_trigger_teleport (void);
-
-void WarpZone_PostTeleportPlayer_Callback(entity pl);
-#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/constants.qh"
- #include "constants.qh"
- #include "defs.qh"
-#endif
+#include "_all.qh"
+.float volume;
.float lifetime;
// values:
// volume
// spawnflags:
// 1 = START_OFF
// when triggered, it is disabled/enabled for everyone
-float trigger_music_SendEntity(entity to, float sf)
+float trigger_music_SendEntity(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
sf &= ~0x80;
+++ /dev/null
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/util.qh"
- #include "defs.qh"
-#endif
-
-// spawner entity
-// "classname" "target_spawn"
-// "message" "fieldname value fieldname value ..."
-// "spawnflags"
-// 1 = call the spawn function
-// 2 = trigger on map load
-
-float target_spawn_initialized;
-.void() target_spawn_spawnfunc;
-float target_spawn_spawnfunc_field;
-.entity target_spawn_activator;
-.float target_spawn_id;
-float target_spawn_count;
-
-void target_spawn_helper_setmodel()
-{
- setmodel(self, self.model);
-}
-
-void target_spawn_helper_setsize()
-{
- setsize(self, self.mins, self.maxs);
-}
-
-void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
-{
- float i, n, valuefieldpos;
- string key, value, valuefield, valueoffset, valueoffsetrandom;
- entity valueent;
- vector data, data2;
- entity oldself;
- entity oldactivator;
-
- n = tokenize_console(msg);
-
- for(i = 0; i < n-1; i += 2)
- {
- key = argv(i);
- value = argv(i+1);
- if(key == "$")
- {
- data.x = -1;
- data.y = FIELD_STRING;
- }
- else
- {
- data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
- if(data.y == 0) // undefined field, i.e., invalid type
- {
- print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
- continue;
- }
- }
- if(substring(value, 0, 1) == "$")
- {
- value = substring(value, 1, strlen(value) - 1);
- if(substring(value, 0, 1) == "$")
- {
- // deferred replacement
- // do nothing
- // useful for creating target_spawns with this!
- }
- else
- {
- // replace me!
- valuefieldpos = strstrofs(value, "+", 0);
- valueoffset = "";
- if(valuefieldpos != -1)
- {
- valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
- value = substring(value, 0, valuefieldpos);
- }
-
- valuefieldpos = strstrofs(valueoffset, "+", 0);
- valueoffsetrandom = "";
- if(valuefieldpos != -1)
- {
- valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
- valueoffset = substring(valueoffset, 0, valuefieldpos);
- }
-
- valuefieldpos = strstrofs(value, ".", 0);
- valuefield = "";
- if(valuefieldpos != -1)
- {
- valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
- value = substring(value, 0, valuefieldpos);
- }
-
- if(value == "self")
- {
- valueent = self;
- value = "";
- }
- else if(value == "activator")
- {
- valueent = act;
- value = "";
- }
- else if(value == "other")
- {
- valueent = other;
- value = "";
- }
- else if(value == "pusher")
- {
- if(time < act.pushltime)
- valueent = act.pusher;
- else
- valueent = world;
- value = "";
- }
- else if(value == "target")
- {
- valueent = e;
- value = "";
- }
- else if(value == "killtarget")
- {
- valueent = kt;
- value = "";
- }
- else if(value == "target2")
- {
- valueent = t2;
- value = "";
- }
- else if(value == "target3")
- {
- valueent = t3;
- value = "";
- }
- else if(value == "target4")
- {
- valueent = t4;
- value = "";
- }
- else if(value == "time")
- {
- valueent = world;
- value = ftos(time);
- }
- else
- {
- print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
- continue;
- }
-
- if(valuefield == "")
- {
- if(value == "")
- value = ftos(num_for_edict(valueent));
- }
- else
- {
- if(value != "")
- {
- print("target_spawn: try to get a field of a non-entity, ignored!\n");
- continue;
- }
- data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
- if(data2_y == 0) // undefined field, i.e., invalid type
- {
- print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
- continue;
- }
- value = getentityfieldstring(data2_x, valueent);
- }
-
- if(valueoffset != "")
- {
- switch(data.y)
- {
- case FIELD_STRING:
- value = strcat(value, valueoffset);
- break;
- case FIELD_FLOAT:
- value = ftos(stof(value) + stof(valueoffset));
- break;
- case FIELD_VECTOR:
- value = vtos(stov(value) + stov(valueoffset));
- break;
- default:
- print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
- break;
- }
- }
-
- if(valueoffsetrandom != "")
- {
- switch(data.y)
- {
- case FIELD_FLOAT:
- value = ftos(stof(value) + random() * stof(valueoffsetrandom));
- break;
- case FIELD_VECTOR:
- data2 = stov(valueoffsetrandom);
- value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
- break;
- default:
- print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
- break;
- }
- }
- }
- }
- if(key == "$")
- {
- if(substring(value, 0, 1) == "_")
- value = strcat("target_spawn_helper", value);
- putentityfieldstring(target_spawn_spawnfunc_field, e, value);
-
- oldself = self;
- oldactivator = activator;
-
- self = e;
- activator = act;
-
- self.target_spawn_spawnfunc();
-
- self = oldself;
- activator = oldactivator;
-
- // We called an external function, so we have to re-tokenize msg.
- n = tokenize_console(msg);
- }
- else
- {
- if(data.y == FIELD_VECTOR)
- value = strreplace("'", "", value); // why?!?
- putentityfieldstring(data.x, e, value);
- }
- }
-}
-
-void target_spawn_useon(entity e)
-{
- self.target_spawn_activator = activator;
- target_spawn_edit_entity(
- e,
- self.message,
- find(world, targetname, self.killtarget),
- find(world, targetname, self.target2),
- find(world, targetname, self.target3),
- find(world, targetname, self.target4),
- activator
- );
-}
-
-float target_spawn_cancreate()
-{
- float c;
- entity e;
-
- c = self.count;
- if(c == 0) // no limit?
- return 1;
-
- ++c; // increase count to not include MYSELF
- for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
- ;
-
- // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
- if(c == 0)
- return 0;
- return 1;
-}
-
-void target_spawn_use()
-{
- entity e;
-
- if(self.target == "")
- {
- // spawn new entity
- if(!target_spawn_cancreate())
- return;
- e = spawn();
- target_spawn_useon(e);
- e.target_spawn_id = self.target_spawn_id;
- }
- else if(self.target == "*activator")
- {
- // edit entity
- if(activator)
- target_spawn_useon(activator);
- }
- else
- {
- // edit entity
- for(e = world; (e = find(e, targetname, self.target)); )
- target_spawn_useon(e);
- }
-}
-
-void target_spawn_spawnfirst()
-{
- activator = self.target_spawn_activator;
- if(self.spawnflags & 2)
- target_spawn_use();
-}
-
-void initialize_field_db()
-{
- if(!target_spawn_initialized)
- {
- float n, i;
- string fn;
- vector prev, new;
- float ft;
-
- n = numentityfields();
- for(i = 0; i < n; ++i)
- {
- fn = entityfieldname(i);
- ft = entityfieldtype(i);
- new = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
- prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
- if(prev.y == 0)
- {
- db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(new));
- if(fn == "target_spawn_spawnfunc")
- target_spawn_spawnfunc_field = i;
- }
- }
-
- target_spawn_initialized = 1;
- }
-}
-
-void spawnfunc_target_spawn()
-{
- initialize_field_db();
- self.use = target_spawn_use;
- self.message = strzone(strreplace("'", "\"", self.message));
- self.target_spawn_id = ++target_spawn_count;
- InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
-}
-
-
-void trigger_relay_if_use()
-{
- float n;
- n = self.count;
-
- // TODO make this generic AND faster than nextent()ing through all, if somehow possible
- n = (cvar_string(self.netname) == cvar_string(self.message));
- if(self.spawnflags & 1)
- n = !n;
-
- if(n)
- SUB_UseTargets();
-}
-
-void spawnfunc_trigger_relay_if()
-{
- self.use = trigger_relay_if_use;
-}
#include "teamplay.qh"
+#include "_all.qh"
+
+#include "cl_client.qh"
+#include "race.qh"
+#include "scores.qh"
+#include "scores_rules.qh"
+
+#include "bot/bot.qh"
+
+#include "command/vote.qh"
+
+#include "mutators/mutators_include.qh"
+
+#include "../common/deathtypes.qh"
+#include "../common/teams.qh"
void TeamchangeFrags(entity e)
{
void turret_stdproc_track();
/// Generic damage handeling. blows up the turret when health <= 0
-void turret_stdproc_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce);
+void turret_stdproc_damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce);
/// Spawns a explotion, does some damage & trows bits arround.
void turret_stdproc_die();
/// reassembles the turret.
/*
* Standard damage proc.
*/
-void turret_stdproc_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+void turret_stdproc_damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce)
{
// Enougth allready!
if(self.deadflag == DEAD_DEAD)
+#include "../../_all.qh"
+
+#include "../../g_damage.qh"
+#include "../../bot/bot.qh"
+
#define cvar_base "g_turrets_unit_"
.float clientframe;
void turrets_setframe(float _frame, float client_only)
}
-float turret_send(entity to, float sf)
+float turret_send(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_TURRET);
turret_projectile_explode();
}
-void turret_projectile_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+void turret_projectile_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce)
{
self.velocity += vforce;
self.health -= damage;
void turret_fire()
{
- if (autocvar_g_turrets_nofire != 0)
+ if (autocvar_g_turrets_nofire)
return;
self.turret_firefunc();
self.nextthink = time + 1;
entity e;
- if (autocvar_g_turrets_reloadcvars == 1)
+ if (autocvar_g_turrets_reloadcvars)
{
e = nextent(world);
while (e)
if (!(self.spawnflags & TSF_SUSPENDED))
builtin_droptofloor(); // why can't we use regular droptofloor here?
- // Terrainbase spawnflag. This puts a enlongated model
- // under the turret, so it looks ok on uneaven surfaces.
- /* TODO: Handle this with CSQC
- if (self.spawnflags & TSF_TERRAINBASE)
- {
- entity tb;
- tb = spawn();
- setmodel(tb,"models/turrets/terrainbase.md3");
- setorigin(tb,self.origin);
- tb.solid = SOLID_BBOX;
- }
- */
-
self.cvar_basename = cvar_base_name;
load_unit_settings(self, self.cvar_basename, 0);
* Railgun-like beam, but has thickness and suppots slowing of target
*/
void FireImoBeam (vector start, vector end, vector smin, vector smax,
- float bforce, float f_dmg, float f_velfactor, float deathtype)
+ float bforce, float f_dmg, float f_velfactor, int deathtype)
{
vector hitloc, force, endpoint, dir;
#ifdef TURRET_DEBUG
-void SUB_Remove();
void marker_think()
{
if(self.cnt)
+#include "../../bot/navigation.qh"
+
const float ewheel_amin_stop = 0;
const float ewheel_amin_fwd_slow = 1;
const float ewheel_amin_fwd_fast = 2;
+void W_MachineGun_MuzzleFlash(void);
+
void spawnfunc_turret_machinegun();
void turret_machinegun_std_init();
void turret_machinegun_attack();
+#include "../../_all.qh"
+
void spawnfunc_turret_phaser();
void turret_phaser_dinit();
void turret_phaser_attack();
+#include "../../csqceffects.qh"
+
void spawnfunc_turret_tesla();
void turret_tesla_dinit();
void turret_tesla_fire();
+#include "../../_all.qh"
+
+#include "../../movelib.qh"
+#include "../../steerlib.qh"
+
const float ANIM_NO = 0;
const float ANIM_TURN = 1;
const float ANIM_WALK = 2;
remove (self);
}
-void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+void walker_rocket_damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce)
{
self.health = self.health - damage;
self.velocity = self.velocity + vforce;
--- /dev/null
+#if VEHICLES_ENABLED
+# include "vehicle.qc"
+
+# include "racer.qc"
+# include "raptor.qc"
+# include "spiderbot.qc"
+
+# ifndef VEHICLES_NO_UNSTABLE
+# include "bumblebee.qc"
+# endif
+#endif
--- /dev/null
+#ifndef VEHICLES_ALL_H
+#define VEHICLES_ALL_H
+
+#if VEHICLES_ENABLED
+# include "racer.qh"
+# include "raptor.qh"
+# include "spiderbot.qh"
+
+# ifndef VEHICLES_NO_UNSTABLE
+# include "bumblebee.qh"
+# endif
+#endif
+
+#endif
#include "bumblebee.qh"
#ifdef SVQC
+#include "vehicle.qh"
void bumb_fire_cannon(entity _gun, string _tagname, entity _owner)
{
vector v = gettaginfo(_gun, gettagindex(_gun, _tagname));
}
+.vector hook_start, hook_end;
float bumb_pilot_frame()
{
entity pilot, vehic;
}
}
-float bumble_raygun_send(entity to, float sf)
+float bumble_raygun_send(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
float autocvar_g_vehicle_bumblebee = 0;
-float bumble_raygun_send(entity to, float sf);
+float bumble_raygun_send(entity to, int sf);
const vector BUMB_MIN = '-130 -130 -130';
const vector BUMB_MAX = '130 130 130';
void spawnfunc_vehicle_bumblebee();
-float bumble_raygun_send(entity to, float sf);
+float bumble_raygun_send(entity to, int sf);
#endif // SVQC
#ifdef CSQC
-const vector RACER_MIN = '-120 -120 -40';
-const vector RACER_MAX = '120 120 40';
+#include "vehicle.qh"
+#include "racer.qh"
#ifdef SVQC
+#include "../../common/triggers/trigger/impulse.qh"
+
void racer_exit(float eject);
void racer_enter();
void racer_fire_rocket(string tagname, entity trg)
{
vector v = gettaginfo(self, gettagindex(self, tagname));
- entity rocket = rocket = vehicles_projectile("wakizashi_rocket_launch", "weapons/rocket_fire.wav",
+ entity rocket = vehicles_projectile("wakizashi_rocket_launch", "weapons/rocket_fire.wav",
v, v_forward * autocvar_g_vehicle_racer_rocket_speed,
autocvar_g_vehicle_racer_rocket_damage, autocvar_g_vehicle_racer_rocket_radius, autocvar_g_vehicle_racer_rocket_force, 3,
DEATH_VH_WAKI_ROCKET, PROJECTILE_WAKIROCKET, 20, false, false, self.owner);
return 1;
}
+.float lastpushtime;
+
void racer_think()
{
self.nextthink = time;
--- /dev/null
+#ifndef RACER_H
+#define RACER_H
+const vector RACER_MIN = '-120 -120 -40';
+const vector RACER_MAX = '120 120 40';
+#endif
-const float RSM_FIRST = 0;
-const float RSM_BOMB = 0;
-const float RSM_FLARE = 1;
-const float RSM_LAST = 1;
-
-const vector RAPTOR_MIN = '-80 -80 0';
-const vector RAPTOR_MAX = '80 80 70';
+#include "vehicle.qh"
+#include "raptor.qh"
#ifdef SVQC
float autocvar_g_vehicle_raptor;
remove(self);
}
-void raptor_flare_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void raptor_flare_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
self.health -= damage;
if(self.health <= 0)
--- /dev/null
+#ifndef RAPTOR_H
+#define RAPTOR_H
+const float RSM_FIRST = 0;
+const float RSM_BOMB = 0;
+const float RSM_FLARE = 1;
+const float RSM_LAST = 1;
+
+const vector RAPTOR_MIN = '-80 -80 0';
+const vector RAPTOR_MAX = '80 80 70';
+
+#endif
-const vector SPIDERBOT_MIN = '-75 -75 10';
-const vector SPIDERBOT_MAX = '75 75 125';
+#include "vehicle.qh"
+#include "spiderbot.qh"
#ifdef SVQC
float autocvar_g_vehicle_spiderbot;
--- /dev/null
+#ifndef SPIDERBOT_H
+#define SPIDERBOT_H
+const vector SPIDERBOT_MIN = '-75 -75 10';
+const vector SPIDERBOT_MAX = '75 75 125';
+#endif
--- /dev/null
+#include "vehicle.qh"
+
+#include "../_all.qh"
+#include "../cl_player.qh"
+#include "../../common/constants.qh"
+#include "../waypointsprites.qh"
+
+#include "../bot/waypoints.qh"
+
+float autocvar_g_vehicles_crush_dmg;
+float autocvar_g_vehicles_crush_force;
+float autocvar_g_vehicles_delayspawn;
+float autocvar_g_vehicles_delayspawn_jitter;
+
+float autocvar_g_vehicles_vortex_damagerate = 0.5;
+float autocvar_g_vehicles_machinegun_damagerate = 0.5;
+float autocvar_g_vehicles_rifle_damagerate = 0.75;
+float autocvar_g_vehicles_vaporizer_damagerate = 0.001;
+float autocvar_g_vehicles_tag_damagerate = 5;
+
+float autocvar_g_vehicles;
+
+void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void vehicles_return();
+void vehicles_enter();
+void vehicles_reset_colors();
+void vehicles_clearreturn();
+void vehicles_setreturn();
+
+
+/** AuxiliaryXhair*
+ Send additional points of interest to be drawn, to vehicle owner
+**/
+const float MAX_AXH = 4;
+.entity AuxiliaryXhairs[MAX_AXH];
+
+float SendAuxiliaryXhair(entity to, int sf)
+{
+
+ WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
+
+ WriteByte(MSG_ENTITY, self.cnt);
+
+ WriteCoord(MSG_ENTITY, self.origin.x);
+ WriteCoord(MSG_ENTITY, self.origin.y);
+ WriteCoord(MSG_ENTITY, self.origin.z);
+
+ WriteByte(MSG_ENTITY, rint(self.colormod.x * 255));
+ WriteByte(MSG_ENTITY, rint(self.colormod.y * 255));
+ WriteByte(MSG_ENTITY, rint(self.colormod.z * 255));
+
+ return true;
+}
+
+void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id)
+{
+ if (!IS_REAL_CLIENT(own))
+ return;
+
+ entity axh;
+
+ axh_id = bound(0, axh_id, MAX_AXH);
+ axh = own.(AuxiliaryXhairs[axh_id]);
+
+ if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+ {
+ axh = spawn();
+ axh.cnt = axh_id;
+ axh.drawonlytoclient = own;
+ axh.owner = own;
+ Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair);
+ }
+
+ setorigin(axh, loc);
+ axh.colormod = clr;
+ axh.SendFlags = 0x01;
+ own.(AuxiliaryXhairs[axh_id]) = axh;
+}
+
+/*
+// SVC_TEMPENTITY based, horrible with even 50 ping. hm.
+// WriteByte(MSG_ONE, SVC_TEMPENTITY) uses reliable messagess, never use for thinsg that need continous updates.
+void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id)
+{
+ msgexntity = own;
+
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR);
+
+ WriteByte(MSG_ONE, axh_id);
+
+ WriteCoord(MSG_ONE, loc_x);
+ WriteCoord(MSG_ONE, loc_y);
+ WriteCoord(MSG_ONE, loc_z);
+
+ WriteByte(MSG_ONE, rint(clr_x * 255));
+ WriteByte(MSG_ONE, rint(clr_y * 255));
+ WriteByte(MSG_ONE, rint(clr_z * 255));
+
+}
+*/
+// End AuxiliaryXhair
+
+/**
+ Notifies the client that he enterd a vehicle, and sends
+ realavent data.
+
+ only sends vehicle_id atm (wich is a HUD_* constant, ex. HUD_SPIDERBOT)
+**/
+void CSQCVehicleSetup(entity own, float vehicle_id)
+{
+ if (!IS_REAL_CLIENT(own))
+ return;
+
+ msg_entity = own;
+
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP);
+ if(vehicle_id != 0)
+ WriteByte(MSG_ONE, vehicle_id);
+ else
+ WriteByte(MSG_ONE, 1 + own.vehicle.vehicle_weapon2mode + HUD_VEHICLE_LAST);
+}
+
+
+const float DAMAGE_TARGETDRONE = 10;
+
+vector targetdrone_getnewspot()
+{
+
+ vector spot;
+ float i;
+ for(i = 0; i < 100; ++i)
+ {
+ spot = self.origin + randomvec() * 1024;
+ tracebox(spot, self.mins, self.maxs, spot, MOVE_NORMAL, self);
+ if(trace_fraction == 1.0 && trace_startsolid == 0 && trace_allsolid == 0)
+ return spot;
+ }
+ return self.origin;
+}
+
+#if 0
+void targetdrone_think();
+void targetdrone_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void targetdrone_renwe()
+{
+ self.think = targetdrone_think;
+ self.nextthink = time + 0.1;
+ setorigin(self, targetdrone_getnewspot());
+ self.health = 200;
+ self.takedamage = DAMAGE_TARGETDRONE;
+ self.event_damage = targetdrone_damage;
+ self.solid = SOLID_BBOX;
+ setmodel(self, "models/runematch/rune.mdl");
+ self.effects = EF_LOWPRECISION;
+ self.scale = 10;
+ self.movetype = MOVETYPE_BOUNCEMISSILE;
+ setsize(self, '-100 -100 -100', '100 100 100');
+
+}
+void targetdrone_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ self.health -= damage;
+ if(self.health <= 0)
+ {
+ pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1);
+
+ if(!self.cnt)
+ remove(self);
+ else
+ {
+ self.think = targetdrone_renwe;
+ self.nextthink = time + 1 + random() * 2;
+ self.solid = SOLID_NOT;
+ setmodel(self, "");
+ }
+ }
+}
+entity targetdrone_getfear()
+{
+ entity fear;
+ float i;
+
+ for(i = 64; i <= 1024; i += 64)
+ {
+ fear = findradius(self.origin, i);
+ while(fear)
+ {
+ if(fear.bot_dodge)
+ return fear;
+
+ fear = fear.chain;
+ }
+ }
+
+ return world;
+}
+void targetdrone_think()
+{
+ self.nextthink = time + 0.1;
+
+ if(self.wp00)
+ if(self.wp00.deadflag != DEAD_NO)
+ self.wp00 = targetdrone_getfear();
+
+ if(!self.wp00)
+ self.wp00 = targetdrone_getfear();
+
+ vector newdir;
+
+ if(self.wp00)
+ newdir = steerlib_push(self.wp00.origin) + randomvec() * 0.75;
+ else
+ newdir = randomvec() * 0.75;
+
+ newdir = newdir * 0.5 + normalize(self.velocity) * 0.5;
+
+ if(self.wp00)
+ self.velocity = normalize(newdir) * (500 + (1024 / min(vlen(self.wp00.origin - self.origin), 1024)) * 700);
+ else
+ self.velocity = normalize(newdir) * 750;
+
+ tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 2, MOVE_NORMAL, self);
+ if(trace_fraction != 1.0)
+ self.velocity = self.velocity * -1;
+
+ //normalize((normalize(self.velocity) * 0.5 + newdir * 0.5)) * 750;
+}
+
+void targetdrone_spawn(vector _where, float _autorenew)
+{
+ entity drone = spawn();
+ setorigin(drone, _where);
+ drone.think = targetdrone_renwe;
+ drone.nextthink = time + 0.1;
+ drone.cnt = _autorenew;
+}
+#endif
+
+void vehicles_locktarget(float incr, float decr, float _lock_time)
+{
+ if(self.lock_target && self.lock_target.deadflag != DEAD_NO)
+ {
+ self.lock_target = world;
+ self.lock_strength = 0;
+ self.lock_time = 0;
+ }
+
+ if(self.lock_time > time)
+ {
+ if(self.lock_target)
+ if(self.lock_soundtime < time)
+ {
+ self.lock_soundtime = time + 0.5;
+ play2(self.owner, "vehicles/locked.wav");
+ }
+
+ return;
+ }
+
+ if(trace_ent != world)
+ {
+ if(teamplay && trace_ent.team == self.team)
+ trace_ent = world;
+
+ if(trace_ent.deadflag != DEAD_NO)
+ trace_ent = world;
+ if(!(
+ (trace_ent.vehicle_flags & VHF_ISVEHICLE) ||
+ (trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET) ||
+ (trace_ent.takedamage == DAMAGE_TARGETDRONE)
+ )) { trace_ent = world; }
+ }
+
+ if(self.lock_target == world && trace_ent != world)
+ self.lock_target = trace_ent;
+
+ if(self.lock_target && trace_ent == self.lock_target)
+ {
+ if(self.lock_strength != 1 && self.lock_strength + incr >= 1)
+ {
+ play2(self.owner, "vehicles/lock.wav");
+ self.lock_soundtime = time + 0.8;
+ }
+ else if (self.lock_strength != 1 && self.lock_soundtime < time)
+ {
+ play2(self.owner, "vehicles/locking.wav");
+ self.lock_soundtime = time + 0.3;
+ }
+
+ }
+
+ // Have a locking target
+ // Trace hit current target
+ if(trace_ent == self.lock_target && trace_ent != world)
+ {
+ self.lock_strength = min(self.lock_strength + incr, 1);
+ if(self.lock_strength == 1)
+ self.lock_time = time + _lock_time;
+ }
+ else
+ {
+ if(trace_ent)
+ self.lock_strength = max(self.lock_strength - decr * 2, 0);
+ else
+ self.lock_strength = max(self.lock_strength - decr, 0);
+
+ if(self.lock_strength == 0)
+ self.lock_target = world;
+ }
+}
+
+
+#define vehicles_sweap_collision(orig,vel,dt,acm,mult) \
+traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \
+if(trace_fraction != 1) \
+ acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult)
+
+// Hover movement support
+float force_fromtag_power;
+vector force_fromtag_origin;
+vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power)
+{
+ force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
+ v_forward = normalize(v_forward) * -1;
+ traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self);
+
+ force_fromtag_power = (1 - trace_fraction) * max_power;
+ force_fromtag_normpower = force_fromtag_power / max_power;
+
+ return v_forward * force_fromtag_power;
+}
+
+// Experimental hovermode wich uses attraction/repulstion from surface insted of gravity/repulsion
+// Can possibly be use to move abt any surface (inclusing walls/celings)
+vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power)
+{
+
+ force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
+ v_forward = normalize(v_forward) * -1;
+ traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self);
+
+ // TODO - this may NOT be compatible with wall/celing movement, unhardcode 0.25 (engine count multiplier)
+ if(trace_fraction == 1.0)
+ {
+ force_fromtag_normpower = -0.25;
+ return '0 0 -200';
+ }
+
+ force_fromtag_power = ((1 - trace_fraction) - trace_fraction) * max_power;
+ force_fromtag_normpower = force_fromtag_power / max_power;
+
+ return v_forward * force_fromtag_power;
+}
+
+// Generic vehile projectile system
+void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ // Ignore damage from oterh projectiles from my owner (dont mess up volly's)
+ if(inflictor.owner == self.owner)
+ return;
+
+ self.health -= damage;
+ self.velocity += force;
+ if(self.health < 1)
+ {
+ self.takedamage = DAMAGE_NO;
+ self.event_damage = func_null;
+ self.think = self.use;
+ self.nextthink = time;
+ }
+}
+
+void vehicles_projectile_explode()
+{
+ if(self.owner && other != world)
+ {
+ if(other == self.owner.vehicle)
+ return;
+
+ if(other == self.owner.vehicle.tur_head)
+ return;
+ }
+
+ PROJECTILE_TOUCH;
+
+ self.event_damage = func_null;
+ RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other);
+
+ remove (self);
+}
+
+entity vehicles_projectile(string _mzlfx, string _mzlsound,
+ vector _org, vector _vel,
+ float _dmg, float _radi, float _force, float _size,
+ float _deahtype, float _projtype, float _health,
+ float _cull, float _clianim, entity _owner)
+{
+ entity proj;
+
+ proj = spawn();
+
+ PROJECTILE_MAKETRIGGER(proj);
+ setorigin(proj, _org);
+
+ proj.shot_dmg = _dmg;
+ proj.shot_radius = _radi;
+ proj.shot_force = _force;
+ proj.totalfrags = _deahtype;
+ proj.solid = SOLID_BBOX;
+ proj.movetype = MOVETYPE_FLYMISSILE;
+ proj.flags = FL_PROJECTILE;
+ proj.bot_dodge = true;
+ proj.bot_dodgerating = _dmg;
+ proj.velocity = _vel;
+ proj.touch = vehicles_projectile_explode;
+ proj.use = vehicles_projectile_explode;
+ proj.owner = self;
+ proj.realowner = _owner;
+ proj.think = SUB_Remove;
+ proj.nextthink = time + 30;
+
+ if(_health)
+ {
+ proj.takedamage = DAMAGE_AIM;
+ proj.event_damage = vehicles_projectile_damage;
+ proj.health = _health;
+ }
+ else
+ proj.flags = FL_PROJECTILE | FL_NOTARGET;
+
+ if(_mzlsound)
+ sound (self, CH_WEAPON_A, _mzlsound, VOL_BASE, ATTEN_NORM);
+
+ if(_mzlfx)
+ pointparticles(particleeffectnum(_mzlfx), proj.origin, proj.velocity, 1);
+
+
+ setsize (proj, '-1 -1 -1' * _size, '1 1 1' * _size);
+
+ CSQCProjectile(proj, _clianim, _projtype, _cull);
+
+ return proj;
+}
+// End generic vehile projectile system
+
+void vehicles_reset()
+{
+ if(self.owner)
+ {
+ entity oldself = self;
+ self = self.owner;
+ vehicles_exit(VHEF_RELESE);
+ self = oldself;
+ }
+ self.alpha = -1;
+ self.movetype = MOVETYPE_NONE;
+ self.effects = EF_NODRAW;
+ self.colormod = '0 0 0';
+ self.avelocity = '0 0 0';
+ self.velocity = '0 0 0';
+ self.event_damage = func_null;
+ self.solid = SOLID_NOT;
+ self.deadflag = DEAD_NO;
+
+ self.touch = func_null;
+ self.nextthink = 0;
+ vehicles_setreturn();
+}
+
+/** vehicles_spawn
+ Exetuted for all vehicles on (re)spawn.
+ Sets defaults for newly spawned units.
+**/
+void vehicles_spawn()
+{
+ dprint("Spawning vehicle: ", self.netname, "\n");
+
+ // De-own & reset
+ self.vehicle_hudmodel.viewmodelforclient = self;
+
+ self.owner = world;
+ self.touch = vehicles_touch;
+ self.event_damage = vehicles_damage;
+ self.reset = vehicles_reset;
+ self.iscreature = true;
+ self.teleportable = false; // no teleporting for vehicles, too buggy
+ self.damagedbycontents = true;
+ self.movetype = MOVETYPE_WALK;
+ self.solid = SOLID_SLIDEBOX;
+ self.takedamage = DAMAGE_AIM;
+ self.deadflag = DEAD_NO;
+ self.bot_attack = true;
+ self.flags = FL_NOTARGET;
+ self.avelocity = '0 0 0';
+ self.velocity = '0 0 0';
+
+ // Reset locking
+ self.lock_strength = 0;
+ self.lock_target = world;
+ self.misc_bulletcounter = 0;
+
+ // Return to spawn
+ self.angles = self.pos2;
+ setorigin(self, self.pos1 + '0 0 0');
+ // Show it
+ pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1);
+
+ if(self.vehicle_controller)
+ self.team = self.vehicle_controller.team;
+
+ vehicles_reset_colors();
+ self.vehicle_spawn(VHSF_NORMAL);
+}
+
+// Better way of determening whats crushable needed! (fl_crushable?)
+float vehicles_crushable(entity e)
+{
+ if(IS_PLAYER(e))
+ return true;
+
+ if(e.flags & FL_MONSTER)
+ return true;
+
+ return false;
+}
+
+void vehicles_impact(float _minspeed, float _speedfac, float _maxpain)
+{
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ return;
+
+ if(self.play_time < time)
+ {
+ float wc = vlen(self.velocity - self.oldvelocity);
+ //dprint("oldvel: ", vtos(self.oldvelocity), "\n");
+ //dprint("vel: ", vtos(self.velocity), "\n");
+ if(_minspeed < wc)
+ {
+ float take = min(_speedfac * wc, _maxpain);
+ Damage (self, world, world, take, DEATH_FALL, self.origin, '0 0 0');
+ self.play_time = time + 0.25;
+
+ //dprint("wc: ", ftos(wc), "\n");
+ //dprint("take: ", ftos(take), "\n");
+ }
+ }
+}
+
+void vehicles_touch()
+{
+ if(MUTATOR_CALLHOOK(VehicleTouch))
+ return;
+
+ // Vehicle currently in use
+ if(self.owner)
+ {
+ if(other != world)
+ if(vehicles_crushable(other))
+ {
+ if(vlen(self.velocity) != 0)
+ Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
+
+ return; // Dont do selfdamage when hitting "soft targets".
+ }
+
+ if(self.play_time < time)
+ if(self.vehicle_impact)
+ self.vehicle_impact();
+
+ return;
+ }
+
+ if (!IS_PLAYER(other))
+ return;
+
+ if(other.deadflag != DEAD_NO)
+ return;
+
+ if(other.vehicle != world)
+ return;
+
+ vehicles_enter();
+}
+.float monster_attack;
+void vehicles_enter()
+{
+ // Remove this when bots know how to use vehicles
+
+ if (IS_BOT_CLIENT(other))
+ if (autocvar_g_vehicles_allow_bots)
+ dprint("Bot enters vehicle\n"); // This is where we need to disconnect (some, all?) normal bot AI and hand over to vehicle's _aiframe()
+ else
+ return;
+
+ if(self.phase > time)
+ return;
+ if(other.frozen)
+ return;
+ if(other.vehicle)
+ return;
+ if(other.deadflag != DEAD_NO)
+ return;
+
+ if(teamplay)
+ if(self.team)
+ if(self.team != other.team)
+ return;
+
+ RemoveGrapplingHook(other);
+
+ self.vehicle_ammo1 = 0;
+ self.vehicle_ammo2 = 0;
+ self.vehicle_reload1 = 0;
+ self.vehicle_reload2 = 0;
+ self.vehicle_energy = 0;
+
+ self.owner = other;
+ self.switchweapon = other.switchweapon;
+
+ // .viewmodelforclient works better.
+ //self.vehicle_hudmodel.drawonlytoclient = self.owner;
+
+ self.vehicle_hudmodel.viewmodelforclient = self.owner;
+
+ self.event_damage = vehicles_damage;
+ self.nextthink = 0;
+ self.owner.angles = self.angles;
+ self.owner.takedamage = DAMAGE_NO;
+ self.owner.solid = SOLID_NOT;
+ self.owner.movetype = MOVETYPE_NOCLIP;
+ self.owner.alpha = -1;
+ self.owner.vehicle = self;
+ self.owner.event_damage = func_null;
+ self.owner.view_ofs = '0 0 0';
+ self.colormap = self.owner.colormap;
+ if(self.tur_head)
+ self.tur_head.colormap = self.owner.colormap;
+
+ self.owner.hud = self.hud;
+ self.owner.PlayerPhysplug = self.PlayerPhysplug;
+
+ self.owner.vehicle_ammo1 = self.vehicle_ammo1;
+ self.owner.vehicle_ammo2 = self.vehicle_ammo2;
+ self.owner.vehicle_reload1 = self.vehicle_reload1;
+ self.owner.vehicle_reload2 = self.vehicle_reload2;
+
+ // Cant do this, hides attached objects too.
+ //self.exteriormodeltoclient = self.owner;
+ //self.tur_head.exteriormodeltoclient = self.owner;
+
+ other.flags &= ~FL_ONGROUND;
+ self.flags &= ~FL_ONGROUND;
+
+ self.team = self.owner.team;
+ self.flags -= FL_NOTARGET;
+ self.monster_attack = true;
+
+ if (IS_REAL_CLIENT(other))
+ {
+ msg_entity = other;
+ WriteByte (MSG_ONE, SVC_SETVIEWPORT);
+ WriteEntity(MSG_ONE, self.vehicle_viewport);
+
+ WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+ if(self.tur_head)
+ {
+ WriteAngle(MSG_ONE, self.tur_head.angles.x + self.angles.x); // tilt
+ WriteAngle(MSG_ONE, self.tur_head.angles.y + self.angles.y); // yaw
+ WriteAngle(MSG_ONE, 0); // roll
+ }
+ else
+ {
+ WriteAngle(MSG_ONE, self.angles.x * -1); // tilt
+ WriteAngle(MSG_ONE, self.angles.y); // yaw
+ WriteAngle(MSG_ONE, 0); // roll
+ }
+ }
+
+ vehicles_clearreturn();
+
+ CSQCVehicleSetup(self.owner, self.hud);
+
+ vh_player = other;
+ vh_vehicle = self;
+ MUTATOR_CALLHOOK(VehicleEnter);
+ other = vh_player;
+ self = vh_vehicle;
+
+ self.vehicle_enter();
+ antilag_clear(other);
+}
+
+/** vehicles_findgoodexit
+ Locates a valid location for the player to exit the vehicle.
+ Will first try prefer_spot, then up 100 random spots arround the vehicle
+ wich are in direct line of sight and empty enougth to hold a players bbox
+**/
+vector vehicles_findgoodexit(vector prefer_spot)
+{
+ //vector exitspot;
+ float mysize;
+
+ tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, prefer_spot, MOVE_NORMAL, self.owner);
+ if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
+ return prefer_spot;
+
+ mysize = 1.5 * vlen(self.maxs - self.mins);
+ float i;
+ vector v, v2;
+ v2 = 0.5 * (self.absmin + self.absmax);
+ for(i = 0; i < 100; ++i)
+ {
+ v = randomvec();
+ v.z = 0;
+ v = v2 + normalize(v) * mysize;
+ tracebox(v2, PL_MIN, PL_MAX, v, MOVE_NORMAL, self.owner);
+ if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
+ return v;
+ }
+
+ /*
+ exitspot = (self.origin + '0 0 48') + v_forward * mysize;
+ tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
+ if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
+ return exitspot;
+
+ exitspot = (self.origin + '0 0 48') - v_forward * mysize;
+ tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
+ if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
+ return exitspot;
+
+ exitspot = (self.origin + '0 0 48') + v_right * mysize;
+ tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
+ if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
+ return exitspot;
+
+ exitspot = (self.origin + '0 0 48') - v_right * mysize;
+ tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
+ if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
+ return exitspot;
+ */
+
+ return self.origin;
+}
+
+/** vehicles_exit
+ Standarrd vehicle release fucntion.
+ custom code goes in self.vehicle_exit
+**/
+float vehicles_exit_running;
+void vehicles_exit(float eject)
+{
+ entity _vehicle;
+ entity _player;
+ entity _oldself = self;
+
+ if(vehicles_exit_running)
+ {
+ dprint("^1vehicles_exit allready running! this is not good..\n");
+ return;
+ }
+
+ vehicles_exit_running = true;
+ if(IS_CLIENT(self))
+ {
+ _vehicle = self.vehicle;
+
+ if (_vehicle.vehicle_flags & VHF_PLAYERSLOT)
+ {
+ _vehicle.vehicle_exit(eject);
+ self = _oldself;
+ vehicles_exit_running = false;
+ return;
+ }
+ }
+ else
+ _vehicle = self;
+
+ _player = _vehicle.owner;
+
+ self = _vehicle;
+
+ if (_player)
+ {
+ if (IS_REAL_CLIENT(_player))
+ {
+ msg_entity = _player;
+ WriteByte (MSG_ONE, SVC_SETVIEWPORT);
+ WriteEntity( MSG_ONE, _player);
+
+ WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+ WriteAngle(MSG_ONE, 0);
+ WriteAngle(MSG_ONE, _vehicle.angles.y);
+ WriteAngle(MSG_ONE, 0);
+ }
+
+ setsize(_player, PL_MIN,PL_MAX);
+
+ _player.takedamage = DAMAGE_AIM;
+ _player.solid = SOLID_SLIDEBOX;
+ _player.movetype = MOVETYPE_WALK;
+ _player.effects &= ~EF_NODRAW;
+ _player.alpha = 1;
+ _player.PlayerPhysplug = func_null;
+ _player.vehicle = world;
+ _player.view_ofs = PL_VIEW_OFS;
+ _player.event_damage = PlayerDamage;
+ _player.hud = HUD_NORMAL;
+ _player.switchweapon = _vehicle.switchweapon;
+
+ CSQCVehicleSetup(_player, HUD_NORMAL);
+ }
+ _vehicle.flags |= FL_NOTARGET;
+
+ if(_vehicle.deadflag == DEAD_NO)
+ _vehicle.avelocity = '0 0 0';
+
+ _vehicle.tur_head.nodrawtoclient = world;
+
+ if(!teamplay)
+ _vehicle.team = 0;
+
+ vh_player = _player;
+ vh_vehicle = _vehicle;
+ MUTATOR_CALLHOOK(VehicleExit);
+ _player = vh_player;
+ _vehicle = vh_vehicle;
+
+ _vehicle.team = _vehicle.tur_head.team;
+
+ sound (_vehicle, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTEN_NORM);
+ _vehicle.vehicle_hudmodel.viewmodelforclient = _vehicle;
+ _vehicle.phase = time + 1;
+ _vehicle.monster_attack = false;
+
+ _vehicle.vehicle_exit(eject);
+
+ vehicles_setreturn();
+ vehicles_reset_colors();
+ _vehicle.owner = world;
+ self = _oldself;
+
+ vehicles_exit_running = false;
+}
+
+
+void vehicles_regen(float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale)
+{
+ if (self.(regen_field) < field_max)
+ if (timer + rpause < time)
+ {
+ if (_healthscale)
+ regen = regen * (self.vehicle_health / self.tur_health);
+
+ self.(regen_field) = min(self.(regen_field) + regen * delta_time, field_max);
+
+ if (self.owner)
+ self.owner.(regen_field) = (self.(regen_field) / field_max) * 100;
+ }
+}
+
+void shieldhit_think()
+{
+ self.alpha -= 0.1;
+ if (self.alpha <= 0)
+ {
+ //setmodel(self, "");
+ self.alpha = -1;
+ self.effects |= EF_NODRAW;
+ }
+ else
+ {
+ self.nextthink = time + 0.1;
+ }
+}
+
+void vehicles_painframe()
+{
+ if(self.owner.vehicle_health <= 50)
+ if(self.pain_frame < time)
+ {
+ float _ftmp;
+ _ftmp = self.owner.vehicle_health / 50;
+ self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp);
+ pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+
+ if(self.vehicle_flags & VHF_DMGSHAKE)
+ self.velocity += randomvec() * 30;
+
+ if(self.vehicle_flags & VHF_DMGROLL)
+ if(self.vehicle_flags & VHF_DMGHEADROLL)
+ self.tur_head.angles += randomvec();
+ else
+ self.angles += randomvec();
+
+ }
+}
+
+void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+ self.dmg_time = time;
+
+ // WEAPONTODO
+ if(DEATH_ISWEAPON(deathtype, WEP_VORTEX))
+ damage *= autocvar_g_vehicles_vortex_damagerate;
+
+ if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
+ damage *= autocvar_g_vehicles_machinegun_damagerate;
+
+ if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
+ damage *= autocvar_g_vehicles_rifle_damagerate;
+
+ if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+ damage *= autocvar_g_vehicles_vaporizer_damagerate;
+
+ if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
+ damage *= autocvar_g_vehicles_tag_damagerate;
+
+ self.enemy = attacker;
+
+ if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0))
+ {
+ if (wasfreed(self.vehicle_shieldent) || self.vehicle_shieldent == world)
+ {
+ self.vehicle_shieldent = spawn();
+ self.vehicle_shieldent.effects = EF_LOWPRECISION;
+
+ setmodel(self.vehicle_shieldent, "models/vhshield.md3");
+ setattachment(self.vehicle_shieldent, self, "");
+ setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
+ self.vehicle_shieldent.scale = 256 / vlen(self.maxs - self.mins);
+ self.vehicle_shieldent.think = shieldhit_think;
+ }
+
+ self.vehicle_shieldent.colormod = '1 1 1';
+ self.vehicle_shieldent.alpha = 0.45;
+ self.vehicle_shieldent.angles = vectoangles(normalize(hitloc - (self.origin + self.vehicle_shieldent.origin))) - self.angles;
+ self.vehicle_shieldent.nextthink = time;
+ self.vehicle_shieldent.effects &= ~EF_NODRAW;
+
+ self.vehicle_shield -= damage;
+
+ if(self.vehicle_shield < 0)
+ {
+ self.vehicle_health -= fabs(self.vehicle_shield);
+ self.vehicle_shieldent.colormod = '2 0 0';
+ self.vehicle_shield = 0;
+ self.vehicle_shieldent.alpha = 0.75;
+
+ if(sound_allowed(MSG_BROADCAST, attacker))
+ spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
+ }
+ else
+ if(sound_allowed(MSG_BROADCAST, attacker))
+ spamsound (self, CH_PAIN, "onslaught/electricity_explode.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
+
+ }
+ else
+ {
+ self.vehicle_health -= damage;
+
+ if(sound_allowed(MSG_BROADCAST, attacker))
+ spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
+ }
+
+ if(self.damageforcescale < 1 && self.damageforcescale > 0)
+ self.velocity += force * self.damageforcescale;
+ else
+ self.velocity += force;
+
+ if(self.vehicle_health <= 0)
+ {
+ if(self.owner)
+ if(self.vehicle_flags & VHF_DEATHEJECT)
+ vehicles_exit(VHEF_EJECT);
+ else
+ vehicles_exit(VHEF_RELESE);
+
+
+ antilag_clear(self);
+
+ self.vehicle_die();
+ vehicles_setreturn();
+ }
+}
+
+void vehicles_clearreturn()
+{
+ entity ret;
+ // Remove "return helper", if any.
+ ret = findchain(classname, "vehicle_return");
+ while(ret)
+ {
+ if(ret.wp00 == self)
+ {
+ ret.classname = "";
+ ret.think = SUB_Remove;
+ ret.nextthink = time + 0.1;
+
+ if(ret.waypointsprite_attached)
+ WaypointSprite_Kill(ret.waypointsprite_attached);
+
+ return;
+ }
+ ret = ret.chain;
+ }
+}
+
+void vehicles_return()
+{
+ pointparticles(particleeffectnum("teleport"), self.wp00.origin + '0 0 64', '0 0 0', 1);
+
+ self.wp00.think = vehicles_spawn;
+ self.wp00.nextthink = time;
+
+ if(self.waypointsprite_attached)
+ WaypointSprite_Kill(self.waypointsprite_attached);
+
+ remove(self);
+}
+
+void vehicles_showwp_goaway()
+{
+ if(self.waypointsprite_attached)
+ WaypointSprite_Kill(self.waypointsprite_attached);
+
+ remove(self);
+
+}
+
+void vehicles_showwp()
+{
+ entity oldself = world;
+ vector rgb;
+
+ if(self.cnt)
+ {
+ self.think = vehicles_return;
+ self.nextthink = self.cnt;
+ }
+ else
+ {
+ self.think = vehicles_return;
+ self.nextthink = time +1;
+
+ oldself = self;
+ self = spawn();
+ setmodel(self, "null");
+ self.team = oldself.wp00.team;
+ self.wp00 = oldself.wp00;
+ setorigin(self, oldself.wp00.pos1);
+
+ self.nextthink = time + 5;
+ self.think = vehicles_showwp_goaway;
+ }
+
+ if(teamplay && self.team)
+ rgb = Team_ColorRGB(self.team);
+ else
+ rgb = '1 1 1';
+ WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, true, RADARICON_POWERUP, rgb);
+ if(self.waypointsprite_attached)
+ {
+ WaypointSprite_UpdateRule(self.waypointsprite_attached, self.wp00.team, SPRITERULE_DEFAULT);
+ if(oldself == world)
+ WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink);
+ WaypointSprite_Ping(self.waypointsprite_attached);
+ }
+
+ if(oldself != world)
+ self = oldself;
+}
+
+void vehicles_setreturn()
+{
+ entity ret;
+
+ vehicles_clearreturn();
+
+ ret = spawn();
+ ret.classname = "vehicle_return";
+ ret.wp00 = self;
+ ret.team = self.team;
+ ret.think = vehicles_showwp;
+
+ if(self.deadflag != DEAD_NO)
+ {
+ ret.cnt = max(game_starttime, time) + self.vehicle_respawntime;
+ ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 5);
+ }
+ else
+ ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 1);
+
+ setmodel(ret, "null");
+ setorigin(ret, self.pos1 + '0 0 96');
+}
+
+void vehicles_reset_colors()
+{
+ entity e;
+ float _effects = 0, _colormap;
+ vector _glowmod, _colormod;
+
+ if(autocvar_g_nodepthtestplayers)
+ _effects |= EF_NODEPTHTEST;
+
+ if(autocvar_g_fullbrightplayers)
+ _effects |= EF_FULLBRIGHT;
+
+ if(self.team)
+ _colormap = 1024 + (self.team - 1) * 17;
+ else
+ _colormap = 1024;
+
+ _glowmod = '0 0 0';
+ _colormod = '0 0 0';
+
+ // Find all ents attacked to main model and setup effects, colormod etc.
+ e = findchainentity(tag_entity, self);
+ while(e)
+ {
+ if(e != self.vehicle_shieldent)
+ {
+ e.effects = _effects; // | EF_LOWPRECISION;
+ e.colormod = _colormod;
+ e.colormap = _colormap;
+ e.alpha = 1;
+ }
+ e = e.chain;
+ }
+
+ self.vehicle_hudmodel.effects = self.effects = _effects; // | EF_LOWPRECISION;
+ self.vehicle_hudmodel.colormod = self.colormod = _colormod;
+ self.vehicle_hudmodel.colormap = self.colormap = _colormap;
+ self.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT);
+
+ self.alpha = 1;
+ self.avelocity = '0 0 0';
+ self.velocity = '0 0 0';
+ self.effects = _effects;
+}
+
+void vehicle_use()
+{
+ dprint("vehicle ",self.netname, " used by ", activator.classname, "\n");
+
+ self.tur_head.team = activator.team;
+
+ if(self.tur_head.team == 0)
+ self.active = ACTIVE_NOT;
+ else
+ self.active = ACTIVE_ACTIVE;
+
+ if(self.active == ACTIVE_ACTIVE && self.deadflag == DEAD_NO)
+ {
+ dprint("^3Eat shit yall!\n");
+ vehicles_setreturn();
+ vehicles_reset_colors();
+ }
+ else if(self.active == ACTIVE_NOT && self.deadflag != DEAD_NO)
+ {
+
+ }
+}
+
+float vehicle_addplayerslot( entity _owner,
+ entity _slot,
+ float _hud,
+ string _hud_model,
+ float() _framefunc,
+ void(float) _exitfunc)
+{
+ if (!(_owner.vehicle_flags & VHF_MULTISLOT))
+ _owner.vehicle_flags |= VHF_MULTISLOT;
+
+ _slot.PlayerPhysplug = _framefunc;
+ _slot.vehicle_exit = _exitfunc;
+ _slot.hud = _hud;
+ _slot.vehicle_flags = VHF_PLAYERSLOT;
+ _slot.vehicle_viewport = spawn();
+ _slot.vehicle_hudmodel = spawn();
+ _slot.vehicle_hudmodel.viewmodelforclient = _slot;
+ _slot.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT);
+
+ setmodel(_slot.vehicle_hudmodel, _hud_model);
+ setmodel(_slot.vehicle_viewport, "null");
+
+ setattachment(_slot.vehicle_hudmodel, _slot, "");
+ setattachment(_slot.vehicle_viewport, _slot.vehicle_hudmodel, "");
+
+ return true;
+}
+
+float vehicle_initialize(string net_name,
+ string bodymodel,
+ string topmodel,
+ string hudmodel,
+ string toptag,
+ string hudtag,
+ string viewtag,
+ float vhud,
+ vector min_s,
+ vector max_s,
+ float nodrop,
+ void(float _spawnflag) spawnproc,
+ float _respawntime,
+ float() physproc,
+ void() enterproc,
+ void(float extflag) exitfunc,
+ void() dieproc,
+ void() thinkproc,
+ float use_csqc,
+ float _max_health,
+ float _max_shield)
+{
+ if(!autocvar_g_vehicles)
+ return false;
+
+ if(self.targetname)
+ {
+ self.vehicle_controller = find(world, target, self.targetname);
+ if(!self.vehicle_controller)
+ {
+ bprint("^1WARNING: ^7Vehicle with invalid .targetname\n");
+ }
+ else
+ {
+ self.team = self.vehicle_controller.team;
+ self.use = vehicle_use;
+
+ if(teamplay)
+ {
+ if(self.vehicle_controller.team == 0)
+ self.active = ACTIVE_NOT;
+ else
+ self.active = ACTIVE_ACTIVE;
+ }
+ }
+ }
+
+ precache_sound("onslaught/ons_hit2.wav");
+ precache_sound("onslaught/electricity_explode.wav");
+
+
+ addstat(STAT_HUD, AS_INT, hud);
+ addstat(STAT_VEHICLESTAT_HEALTH, AS_INT, vehicle_health);
+ addstat(STAT_VEHICLESTAT_SHIELD, AS_INT, vehicle_shield);
+ addstat(STAT_VEHICLESTAT_ENERGY, AS_INT, vehicle_energy);
+
+ addstat(STAT_VEHICLESTAT_AMMO1, AS_INT, vehicle_ammo1);
+ addstat(STAT_VEHICLESTAT_RELOAD1, AS_INT, vehicle_reload1);
+
+ addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2);
+ addstat(STAT_VEHICLESTAT_RELOAD2, AS_INT, vehicle_reload2);
+
+ if(bodymodel == "")
+ error("vehicles: missing bodymodel!");
+
+ if(hudmodel == "")
+ error("vehicles: missing hudmodel!");
+
+ if(net_name == "")
+ self.netname = self.classname;
+ else
+ self.netname = net_name;
+
+ if(self.team && !teamplay)
+ self.team = 0;
+
+ self.vehicle_flags |= VHF_ISVEHICLE;
+
+ setmodel(self, bodymodel);
+
+ self.vehicle_viewport = spawn();
+ self.vehicle_hudmodel = spawn();
+ self.tur_head = spawn();
+ self.tur_head.owner = self;
+ self.takedamage = DAMAGE_AIM;
+ self.bot_attack = true;
+ self.iscreature = true;
+ self.teleportable = false; // no teleporting for vehicles, too buggy
+ self.damagedbycontents = true;
+ self.hud = vhud;
+ self.tur_health = _max_health;
+ self.tur_head.tur_health = _max_shield;
+ self.vehicle_die = dieproc;
+ self.vehicle_exit = exitfunc;
+ self.vehicle_enter = enterproc;
+ self.PlayerPhysplug = physproc;
+ self.event_damage = func_null;
+ self.touch = vehicles_touch;
+ self.think = vehicles_spawn;
+ self.vehicle_spawn = spawnproc;
+ self.vehicle_respawntime = max(0, _respawntime);
+ self.effects = EF_NODRAW;
+ self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
+ if(!autocvar_g_vehicles_delayspawn || !self.vehicle_respawntime)
+ self.nextthink = time;
+ else
+ self.nextthink = max(time, game_starttime) + max(0, self.vehicle_respawntime + ((random() * 2 - 1) * autocvar_g_vehicles_delayspawn_jitter));
+
+ if(autocvar_g_playerclip_collisions)
+ self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
+
+ if(autocvar_g_nodepthtestplayers)
+ self.effects = self.effects | EF_NODEPTHTEST;
+
+ if(autocvar_g_fullbrightplayers)
+ self.effects = self.effects | EF_FULLBRIGHT;
+
+ setmodel(self.vehicle_hudmodel, hudmodel);
+ setmodel(self.vehicle_viewport, "null");
+
+ if(topmodel != "")
+ {
+ setmodel(self.tur_head, topmodel);
+ setattachment(self.tur_head, self, toptag);
+ setattachment(self.vehicle_hudmodel, self.tur_head, hudtag);
+ setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
+ }
+ else
+ {
+ setattachment(self.tur_head, self, "");
+ setattachment(self.vehicle_hudmodel, self, hudtag);
+ setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
+ }
+
+ setsize(self, min_s, max_s);
+ if (!nodrop)
+ {
+ setorigin(self, self.origin);
+ tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
+ setorigin(self, trace_endpos);
+ }
+
+ self.pos1 = self.origin;
+ self.pos2 = self.angles;
+ self.tur_head.team = self.team;
+
+ if(MUTATOR_CALLHOOK(VehicleSpawn))
+ return false;
+
+ return true;
+}
+
+vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname,
+ float _pichlimit_min, float _pichlimit_max,
+ float _rotlimit_min, float _rotlimit_max, float _aimspeed)
+{
+ vector vtmp, vtag;
+ float ftmp;
+ vtag = gettaginfo(_turrret, gettagindex(_turrret, _tagname));
+ vtmp = vectoangles(normalize(_target - vtag));
+ vtmp = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(_vehic.angles), AnglesTransform_FromAngles(vtmp))) - _turrret.angles;
+ vtmp = AnglesTransform_Normalize(vtmp, true);
+ ftmp = _aimspeed * frametime;
+ vtmp.y = bound(-ftmp, vtmp.y, ftmp);
+ vtmp.x = bound(-ftmp, vtmp.x, ftmp);
+ _turrret.angles_y = bound(_rotlimit_min, _turrret.angles.y + vtmp.y, _rotlimit_max);
+ _turrret.angles_x = bound(_pichlimit_min, _turrret.angles.x + vtmp.x, _pichlimit_max);
+ return vtag;
+}
+
+void vehicles_gib_explode()
+{
+ sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
+ pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
+ remove(self);
+}
+
+void vehicles_gib_think()
+{
+ self.alpha -= 0.1;
+ if(self.cnt >= time)
+ remove(self);
+ else
+ self.nextthink = time + 0.1;
+}
+
+entity vehicle_tossgib(entity _template, vector _vel, string _tag, float _burn, float _explode, float _maxtime, vector _rot)
+{
+ entity _gib = spawn();
+ setmodel(_gib, _template.model);
+ setorigin(_gib, gettaginfo(self, gettagindex(self, _tag)));
+ _gib.velocity = _vel;
+ _gib.movetype = MOVETYPE_TOSS;
+ _gib.solid = SOLID_CORPSE;
+ _gib.colormod = '-0.5 -0.5 -0.5';
+ _gib.effects = EF_LOWPRECISION;
+ _gib.avelocity = _rot;
+
+ if(_burn)
+ _gib.effects |= EF_FLAME;
+
+ if(_explode)
+ {
+ _gib.think = vehicles_gib_explode;
+ _gib.nextthink = time + random() * _explode;
+ _gib.touch = vehicles_gib_explode;
+ }
+ else
+ {
+ _gib.cnt = time + _maxtime;
+ _gib.think = vehicles_gib_think;
+ _gib.nextthink = time + _maxtime - 1;
+ _gib.alpha = 1;
+ }
+ return _gib;
+}
+
+/*
+vector predict_target(entity _targ, vector _from, float _shot_speed)
+{
+ float i; // loop
+ float _distance; // How far to target
+ float _impact_time; // How long untill projectile impacts
+ vector _predict_pos; // Predicted enemy location
+ vector _original_origin;// Where target is before predicted
+
+ _original_origin = real_origin(_targ); // Typicaly center of target BBOX
+
+ _predict_pos = _original_origin;
+ for(i = 0; i < 4; ++i) // Loop a few times to increase prediction accuracy (increase loop count if accuracy is to low)
+ {
+ _distance = vlen(_predict_pos - _from); // Get distance to previos predicted location
+ _impact_time = _distance / _shot_speed; // Calculate impact time
+ _predict_pos = _original_origin + _targ.velocity * _impact_time; // Calculate new predicted location
+ }
+
+ return _predict_pos;
+}
+*/
--- /dev/null
+#ifndef VEHICLE_H
+#define VEHICLE_H
+
+#include "../_all.qh"
+
+#include "../antilag.qh"
+#include "../cl_player.qh"
+#include "../g_damage.qh"
+#include "../g_hook.qh"
+#include "../movelib.qh"
+
+#include "../bot/bot.qh"
+
+#include "../command/common.qh"
+
+#include "../tturrets/include/turrets_early.qh"
+
+#include "../weapons/tracing.qh"
+
+#include "../../common/deathtypes.qh"
+#include "../../common/stats.qh"
+
+#include "../../warpzonelib/anglestransform.qh"
+#include "../../warpzonelib/server.qh"
+
+entity vehicles_projectile(string _mzlfx, string _mzlsound,
+ vector _org, vector _vel,
+ float _dmg, float _radi, float _force, float _size,
+ float _deahtype, float _projtype, float _health,
+ float _cull, float _clianim, entity _owner);
+
+vector vehicles_findgoodexit(vector prefer_spot);
+
+
+
+/** vehicles_locktarget
+
+ Generic target locking.
+
+ Figure out if what target is "locked" (if any), for missile tracking as such.
+
+ after calling, "if(self.lock_target != world && self.lock_strength == 1)" mean
+ you have a locked in target.
+
+ Exspects a crosshair_trace() or equivalent to be
+ dont before calling.
+
+**/
+.entity lock_target;
+.float lock_strength;
+.float lock_time;
+.float lock_soundtime;
+
+void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id);
+
+vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname,
+ float _pichlimit_min, float _pichlimit_max,
+ float _rotlimit_min, float _rotlimit_max, float _aimspeed);
+
+#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \
+ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100
+
+void CSQCVehicleSetup(entity own, float vehicle_id);
+
+.float() PlayerPhysplug;
+
+float autocvar_g_vehicles_allow_bots = 0;
+
+void vehicles_touch();
+
+void vehicles_regen(float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale);
+
+float shortangle_f(float ang1, float ang2);
+float anglemods(float v);
+
+entity vehicle_tossgib(entity _template, vector _vel, string _tag, float _burn, float _explode, float _maxtime, vector _rot);
+
+void vehicles_impact(float _minspeed, float _speedfac, float _maxpain);
+
+void shieldhit_think();
+
+float vehicle_addplayerslot( entity _owner,
+ entity _slot,
+ float _hud,
+ string _hud_model,
+ float() _framefunc,
+ void(float) _exitfunc);
+
+.void() vehicle_impact;
+
+float vehicle_initialize(string net_name,
+ string bodymodel,
+ string topmodel,
+ string hudmodel,
+ string toptag,
+ string hudtag,
+ string viewtag,
+ float vhud,
+ vector min_s,
+ vector max_s,
+ float nodrop,
+ void(float _spawnflag) spawnproc,
+ float _respawntime,
+ float() physproc,
+ void() enterproc,
+ void(float extflag) exitfunc,
+ void() dieproc,
+ void() thinkproc,
+ float use_csqc,
+ float _max_health,
+ float _max_shield);
+
+float force_fromtag_normpower;
+
+void vehicles_painframe();
+
+void vehicles_locktarget(float incr, float decr, float _lock_time);
+
+vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power);
+
+vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power);
+
+void vehicles_projectile_explode();
+
+#if VEHICLES_ENABLED
+
+.int vehicle_flags;
+const int VHF_ISVEHICLE = 2; /// Indicates vehicle
+const int VHF_HASSHIELD = 4; /// Vehicle has shileding
+const int VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates
+const int VHF_HEALTHREGEN = 16; /// Vehicles health regenerates
+const int VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates
+const int VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage
+const int VHF_MOVE_GROUND = 128; /// Vehicle moves on gound
+const int VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound
+const int VHF_MOVE_FLY = 512; /// Vehicle is airborn
+const int VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50%
+const int VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50%
+const int VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50%
+const int VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots
+const int VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle
+
+.entity gun1;
+.entity gun2;
+.entity gun3;
+.entity vehicle_shieldent; /// Entity to disply the shild effect on damage
+.entity vehicle;
+.entity vehicle_viewport;
+.entity vehicle_hudmodel;
+.entity vehicle_controller;
+
+.entity gunner1;
+.entity gunner2;
+
+.float vehicle_health; /// If self is player this is 0..100 indicating precentage of health left on vehicle. If self is vehile, this is the real health value.
+.float vehicle_energy; /// If self is player this is 0..100 indicating precentage of energy left on vehicle. If self is vehile, this is the real energy value.
+.float vehicle_shield; /// If self is player this is 0..100 indicating precentage of shield left on vehicle. If self is vehile, this is the real shield value.
+
+.float vehicle_ammo1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo1 value.
+.float vehicle_reload1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload1 value.
+.float vehicle_ammo2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo2 value.
+.float vehicle_reload2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload2 value.
+
+.float sound_nexttime;
+const float VOL_VEHICLEENGINE = 1;
+
+.float hud;
+.float dmg_time;
+.float vehicle_respawntime;
+//.void() vehicle_spawn;
+
+void vehicles_exit(float eject);
+.void(float exit_flags) vehicle_exit;
+const float VHEF_NORMAL = 0; /// User pressed exit key
+const float VHEF_EJECT = 1; /// User pressed exit key 3 times fast (not implemented) or vehile is dying
+const float VHEF_RELESE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented)
+
+const float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05
+const float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A
+const float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80
+
+.void() vehicle_enter; /// Vehicles custom funciton to be executed when owner exit it
+.void() vehicle_die; /// Vehicles custom function to be executed when vehile die
+const float VHSF_NORMAL = 0;
+const float VHSF_FACTORY = 2;
+.void(float _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns
+.float(float _imp) vehicles_impulse;
+.float vehicle_weapon2mode;
+
+#if VEHICLES_USE_ODE
+void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object
+void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force
+void(entity e, vector torque) physics_addtorque = #542; // add relative torque
+#endif // VEHICLES_USE_ODE
+#endif // VEHICLES_ENABLED
+#endif
+++ /dev/null
-float autocvar_g_vehicles_crush_dmg;
-float autocvar_g_vehicles_crush_force;
-float autocvar_g_vehicles_delayspawn;
-float autocvar_g_vehicles_delayspawn_jitter;
-
-float autocvar_g_vehicles_vortex_damagerate = 0.5;
-float autocvar_g_vehicles_machinegun_damagerate = 0.5;
-float autocvar_g_vehicles_rifle_damagerate = 0.75;
-float autocvar_g_vehicles_vaporizer_damagerate = 0.001;
-float autocvar_g_vehicles_tag_damagerate = 5;
-
-float autocvar_g_vehicles;
-
-void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
-void vehicles_return();
-void vehicles_enter();
-void vehicles_touch();
-void vehicles_reset_colors();
-void vehicles_clearreturn();
-void vehicles_setreturn();
-
-
-/** AuxiliaryXhair*
- Send additional points of interest to be drawn, to vehicle owner
-**/
-const float MAX_AXH = 4;
-.entity AuxiliaryXhair[MAX_AXH];
-
-float SendAuxiliaryXhair(entity to, float sf)
-{
-
- WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
-
- WriteByte(MSG_ENTITY, self.cnt);
-
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
-
- WriteByte(MSG_ENTITY, rint(self.colormod.x * 255));
- WriteByte(MSG_ENTITY, rint(self.colormod.y * 255));
- WriteByte(MSG_ENTITY, rint(self.colormod.z * 255));
-
- return true;
-}
-
-void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id)
-{
- if (!IS_REAL_CLIENT(own))
- return;
-
- entity axh;
-
- axh_id = bound(0, axh_id, MAX_AXH);
- axh = own.(AuxiliaryXhair[axh_id]);
-
- if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
- {
- axh = spawn();
- axh.cnt = axh_id;
- axh.drawonlytoclient = own;
- axh.owner = own;
- Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair);
- }
-
- setorigin(axh, loc);
- axh.colormod = clr;
- axh.SendFlags = 0x01;
- own.(AuxiliaryXhair[axh_id]) = axh;
-}
-
-/*
-// SVC_TEMPENTITY based, horrible with even 50 ping. hm.
-// WriteByte(MSG_ONE, SVC_TEMPENTITY) uses reliable messagess, never use for thinsg that need continous updates.
-void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id)
-{
- msgexntity = own;
-
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR);
-
- WriteByte(MSG_ONE, axh_id);
-
- WriteCoord(MSG_ONE, loc_x);
- WriteCoord(MSG_ONE, loc_y);
- WriteCoord(MSG_ONE, loc_z);
-
- WriteByte(MSG_ONE, rint(clr_x * 255));
- WriteByte(MSG_ONE, rint(clr_y * 255));
- WriteByte(MSG_ONE, rint(clr_z * 255));
-
-}
-*/
-// End AuxiliaryXhair
-
-/**
- Notifies the client that he enterd a vehicle, and sends
- realavent data.
-
- only sends vehicle_id atm (wich is a HUD_* constant, ex. HUD_SPIDERBOT)
-**/
-void CSQCVehicleSetup(entity own, float vehicle_id)
-{
- if (!IS_REAL_CLIENT(own))
- return;
-
- msg_entity = own;
-
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP);
- if(vehicle_id != 0)
- WriteByte(MSG_ONE, vehicle_id);
- else
- WriteByte(MSG_ONE, 1 + own.vehicle.vehicle_weapon2mode + HUD_VEHICLE_LAST);
-}
-
-/** vehicles_locktarget
-
- Generic target locking.
-
- Figure out if what target is "locked" (if any), for missile tracking as such.
-
- after calling, "if(self.lock_target != world && self.lock_strength == 1)" mean
- you have a locked in target.
-
- Exspects a crosshair_trace() or equivalent to be
- dont before calling.
-
-**/
-.entity lock_target;
-.float lock_strength;
-.float lock_time;
-.float lock_soundtime;
-const float DAMAGE_TARGETDRONE = 10;
-
-vector targetdrone_getnewspot()
-{
-
- vector spot;
- float i;
- for(i = 0; i < 100; ++i)
- {
- spot = self.origin + randomvec() * 1024;
- tracebox(spot, self.mins, self.maxs, spot, MOVE_NORMAL, self);
- if(trace_fraction == 1.0 && trace_startsolid == 0 && trace_allsolid == 0)
- return spot;
- }
- return self.origin;
-}
-
-#if 0
-void targetdrone_think();
-void targetdrone_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
-void targetdrone_renwe()
-{
- self.think = targetdrone_think;
- self.nextthink = time + 0.1;
- setorigin(self, targetdrone_getnewspot());
- self.health = 200;
- self.takedamage = DAMAGE_TARGETDRONE;
- self.event_damage = targetdrone_damage;
- self.solid = SOLID_BBOX;
- setmodel(self, "models/runematch/rune.mdl");
- self.effects = EF_LOWPRECISION;
- self.scale = 10;
- self.movetype = MOVETYPE_BOUNCEMISSILE;
- setsize(self, '-100 -100 -100', '100 100 100');
-
-}
-void targetdrone_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
- self.health -= damage;
- if(self.health <= 0)
- {
- pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1);
-
- if(!self.cnt)
- remove(self);
- else
- {
- self.think = targetdrone_renwe;
- self.nextthink = time + 1 + random() * 2;
- self.solid = SOLID_NOT;
- setmodel(self, "");
- }
- }
-}
-entity targetdrone_getfear()
-{
- entity fear;
- float i;
-
- for(i = 64; i <= 1024; i += 64)
- {
- fear = findradius(self.origin, i);
- while(fear)
- {
- if(fear.bot_dodge)
- return fear;
-
- fear = fear.chain;
- }
- }
-
- return world;
-}
-void targetdrone_think()
-{
- self.nextthink = time + 0.1;
-
- if(self.wp00)
- if(self.wp00.deadflag != DEAD_NO)
- self.wp00 = targetdrone_getfear();
-
- if(!self.wp00)
- self.wp00 = targetdrone_getfear();
-
- vector newdir;
-
- if(self.wp00)
- newdir = steerlib_push(self.wp00.origin) + randomvec() * 0.75;
- else
- newdir = randomvec() * 0.75;
-
- newdir = newdir * 0.5 + normalize(self.velocity) * 0.5;
-
- if(self.wp00)
- self.velocity = normalize(newdir) * (500 + (1024 / min(vlen(self.wp00.origin - self.origin), 1024)) * 700);
- else
- self.velocity = normalize(newdir) * 750;
-
- tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 2, MOVE_NORMAL, self);
- if(trace_fraction != 1.0)
- self.velocity = self.velocity * -1;
-
- //normalize((normalize(self.velocity) * 0.5 + newdir * 0.5)) * 750;
-}
-
-void targetdrone_spawn(vector _where, float _autorenew)
-{
- entity drone = spawn();
- setorigin(drone, _where);
- drone.think = targetdrone_renwe;
- drone.nextthink = time + 0.1;
- drone.cnt = _autorenew;
-}
-#endif
-
-void vehicles_locktarget(float incr, float decr, float _lock_time)
-{
- if(self.lock_target && self.lock_target.deadflag != DEAD_NO)
- {
- self.lock_target = world;
- self.lock_strength = 0;
- self.lock_time = 0;
- }
-
- if(self.lock_time > time)
- {
- if(self.lock_target)
- if(self.lock_soundtime < time)
- {
- self.lock_soundtime = time + 0.5;
- play2(self.owner, "vehicles/locked.wav");
- }
-
- return;
- }
-
- if(trace_ent != world)
- {
- if(teamplay && trace_ent.team == self.team)
- trace_ent = world;
-
- if(trace_ent.deadflag != DEAD_NO)
- trace_ent = world;
-
- if(!trace_ent.vehicle_flags & VHF_ISVEHICLE ||
- trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET ||
- trace_ent.takedamage == DAMAGE_TARGETDRONE)
- trace_ent = world;
- }
-
- if(self.lock_target == world && trace_ent != world)
- self.lock_target = trace_ent;
-
- if(self.lock_target && trace_ent == self.lock_target)
- {
- if(self.lock_strength != 1 && self.lock_strength + incr >= 1)
- {
- play2(self.owner, "vehicles/lock.wav");
- self.lock_soundtime = time + 0.8;
- }
- else if (self.lock_strength != 1 && self.lock_soundtime < time)
- {
- play2(self.owner, "vehicles/locking.wav");
- self.lock_soundtime = time + 0.3;
- }
-
- }
-
- // Have a locking target
- // Trace hit current target
- if(trace_ent == self.lock_target && trace_ent != world)
- {
- self.lock_strength = min(self.lock_strength + incr, 1);
- if(self.lock_strength == 1)
- self.lock_time = time + _lock_time;
- }
- else
- {
- if(trace_ent)
- self.lock_strength = max(self.lock_strength - decr * 2, 0);
- else
- self.lock_strength = max(self.lock_strength - decr, 0);
-
- if(self.lock_strength == 0)
- self.lock_target = world;
- }
-}
-
-#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \
-ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100
-
-#define vehicles_sweap_collision(orig,vel,dt,acm,mult) \
-traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \
-if(trace_fraction != 1) \
- acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult)
-
-// Hover movement support
-float force_fromtag_power;
-float force_fromtag_normpower;
-vector force_fromtag_origin;
-vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power)
-{
- force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
- v_forward = normalize(v_forward) * -1;
- traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self);
-
- force_fromtag_power = (1 - trace_fraction) * max_power;
- force_fromtag_normpower = force_fromtag_power / max_power;
-
- return v_forward * force_fromtag_power;
-}
-
-// Experimental hovermode wich uses attraction/repulstion from surface insted of gravity/repulsion
-// Can possibly be use to move abt any surface (inclusing walls/celings)
-vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power)
-{
-
- force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
- v_forward = normalize(v_forward) * -1;
- traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self);
-
- // TODO - this may NOT be compatible with wall/celing movement, unhardcode 0.25 (engine count multiplier)
- if(trace_fraction == 1.0)
- {
- force_fromtag_normpower = -0.25;
- return '0 0 -200';
- }
-
- force_fromtag_power = ((1 - trace_fraction) - trace_fraction) * max_power;
- force_fromtag_normpower = force_fromtag_power / max_power;
-
- return v_forward * force_fromtag_power;
-}
-
-// Generic vehile projectile system
-void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
- // Ignore damage from oterh projectiles from my owner (dont mess up volly's)
- if(inflictor.owner == self.owner)
- return;
-
- self.health -= damage;
- self.velocity += force;
- if(self.health < 1)
- {
- self.takedamage = DAMAGE_NO;
- self.event_damage = func_null;
- self.think = self.use;
- self.nextthink = time;
- }
-}
-
-void vehicles_projectile_explode()
-{
- if(self.owner && other != world)
- {
- if(other == self.owner.vehicle)
- return;
-
- if(other == self.owner.vehicle.tur_head)
- return;
- }
-
- PROJECTILE_TOUCH;
-
- self.event_damage = func_null;
- RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other);
-
- remove (self);
-}
-
-entity vehicles_projectile(string _mzlfx, string _mzlsound,
- vector _org, vector _vel,
- float _dmg, float _radi, float _force, float _size,
- float _deahtype, float _projtype, float _health,
- float _cull, float _clianim, entity _owner)
-{
- entity proj;
-
- proj = spawn();
-
- PROJECTILE_MAKETRIGGER(proj);
- setorigin(proj, _org);
-
- proj.shot_dmg = _dmg;
- proj.shot_radius = _radi;
- proj.shot_force = _force;
- proj.totalfrags = _deahtype;
- proj.solid = SOLID_BBOX;
- proj.movetype = MOVETYPE_FLYMISSILE;
- proj.flags = FL_PROJECTILE;
- proj.bot_dodge = true;
- proj.bot_dodgerating = _dmg;
- proj.velocity = _vel;
- proj.touch = vehicles_projectile_explode;
- proj.use = vehicles_projectile_explode;
- proj.owner = self;
- proj.realowner = _owner;
- proj.think = SUB_Remove;
- proj.nextthink = time + 30;
-
- if(_health)
- {
- proj.takedamage = DAMAGE_AIM;
- proj.event_damage = vehicles_projectile_damage;
- proj.health = _health;
- }
- else
- proj.flags = FL_PROJECTILE | FL_NOTARGET;
-
- if(_mzlsound)
- sound (self, CH_WEAPON_A, _mzlsound, VOL_BASE, ATTEN_NORM);
-
- if(_mzlfx)
- pointparticles(particleeffectnum(_mzlfx), proj.origin, proj.velocity, 1);
-
-
- setsize (proj, '-1 -1 -1' * _size, '1 1 1' * _size);
-
- CSQCProjectile(proj, _clianim, _projtype, _cull);
-
- return proj;
-}
-// End generic vehile projectile system
-
-void vehicles_reset()
-{
- if(self.owner)
- {
- entity oldself = self;
- self = self.owner;
- vehicles_exit(VHEF_RELESE);
- self = oldself;
- }
- self.alpha = -1;
- self.movetype = MOVETYPE_NONE;
- self.effects = EF_NODRAW;
- self.colormod = '0 0 0';
- self.avelocity = '0 0 0';
- self.velocity = '0 0 0';
- self.event_damage = func_null;
- self.solid = SOLID_NOT;
- self.deadflag = DEAD_NO;
-
- self.touch = func_null;
- self.nextthink = 0;
- vehicles_setreturn();
-}
-
-/** vehicles_spawn
- Exetuted for all vehicles on (re)spawn.
- Sets defaults for newly spawned units.
-**/
-void vehicles_spawn()
-{
- dprint("Spawning vehicle: ", self.netname, "\n");
-
- // De-own & reset
- self.vehicle_hudmodel.viewmodelforclient = self;
-
- self.owner = world;
- self.touch = vehicles_touch;
- self.event_damage = vehicles_damage;
- self.reset = vehicles_reset;
- self.iscreature = true;
- self.teleportable = false; // no teleporting for vehicles, too buggy
- self.damagedbycontents = true;
- self.movetype = MOVETYPE_WALK;
- self.solid = SOLID_SLIDEBOX;
- self.takedamage = DAMAGE_AIM;
- self.deadflag = DEAD_NO;
- self.bot_attack = true;
- self.flags = FL_NOTARGET;
- self.avelocity = '0 0 0';
- self.velocity = '0 0 0';
-
- // Reset locking
- self.lock_strength = 0;
- self.lock_target = world;
- self.misc_bulletcounter = 0;
-
- // Return to spawn
- self.angles = self.pos2;
- setorigin(self, self.pos1 + '0 0 0');
- // Show it
- pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1);
-
- if(self.vehicle_controller)
- self.team = self.vehicle_controller.team;
-
- vehicles_reset_colors();
- self.vehicle_spawn(VHSF_NORMAL);
-}
-
-// Better way of determening whats crushable needed! (fl_crushable?)
-float vehicles_crushable(entity e)
-{
- if(IS_PLAYER(e))
- return true;
-
- if(e.flags & FL_MONSTER)
- return true;
-
- return false;
-}
-
-void vehicles_impact(float _minspeed, float _speedfac, float _maxpain)
-{
- if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- return;
-
- if(self.play_time < time)
- {
- float wc = vlen(self.velocity - self.oldvelocity);
- //dprint("oldvel: ", vtos(self.oldvelocity), "\n");
- //dprint("vel: ", vtos(self.velocity), "\n");
- if(_minspeed < wc)
- {
- float take = min(_speedfac * wc, _maxpain);
- Damage (self, world, world, take, DEATH_FALL, self.origin, '0 0 0');
- self.play_time = time + 0.25;
-
- //dprint("wc: ", ftos(wc), "\n");
- //dprint("take: ", ftos(take), "\n");
- }
- }
-}
-
-.void() vehicle_impact;
-void vehicles_touch()
-{
- if(MUTATOR_CALLHOOK(VehicleTouch))
- return;
-
- // Vehicle currently in use
- if(self.owner)
- {
- if(other != world)
- if(vehicles_crushable(other))
- {
- if(vlen(self.velocity) != 0)
- Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
-
- return; // Dont do selfdamage when hitting "soft targets".
- }
-
- if(self.play_time < time)
- if(self.vehicle_impact)
- self.vehicle_impact();
-
- return;
- }
-
- if (!IS_PLAYER(other))
- return;
-
- if(other.deadflag != DEAD_NO)
- return;
-
- if(other.vehicle != world)
- return;
-
- vehicles_enter();
-}
-float autocvar_g_vehicles_allow_bots = 0;
-void vehicles_enter()
-{
- // Remove this when bots know how to use vehicles
-
- if (IS_BOT_CLIENT(other))
- if (autocvar_g_vehicles_allow_bots)
- dprint("Bot enters vehicle\n"); // This is where we need to disconnect (some, all?) normal bot AI and hand over to vehicle's _aiframe()
- else
- return;
-
- if(self.phase > time)
- return;
- if(other.frozen)
- return;
- if(other.vehicle)
- return;
- if(other.deadflag != DEAD_NO)
- return;
-
- if(teamplay)
- if(self.team)
- if(self.team != other.team)
- return;
-
- RemoveGrapplingHook(other);
-
- self.vehicle_ammo1 = 0;
- self.vehicle_ammo2 = 0;
- self.vehicle_reload1 = 0;
- self.vehicle_reload2 = 0;
- self.vehicle_energy = 0;
-
- self.owner = other;
- self.switchweapon = other.switchweapon;
-
- // .viewmodelforclient works better.
- //self.vehicle_hudmodel.drawonlytoclient = self.owner;
-
- self.vehicle_hudmodel.viewmodelforclient = self.owner;
-
- self.event_damage = vehicles_damage;
- self.nextthink = 0;
- self.owner.angles = self.angles;
- self.owner.takedamage = DAMAGE_NO;
- self.owner.solid = SOLID_NOT;
- self.owner.movetype = MOVETYPE_NOCLIP;
- self.owner.alpha = -1;
- self.owner.vehicle = self;
- self.owner.event_damage = func_null;
- self.owner.view_ofs = '0 0 0';
- self.colormap = self.owner.colormap;
- if(self.tur_head)
- self.tur_head.colormap = self.owner.colormap;
-
- self.owner.hud = self.hud;
- self.owner.PlayerPhysplug = self.PlayerPhysplug;
-
- self.owner.vehicle_ammo1 = self.vehicle_ammo1;
- self.owner.vehicle_ammo2 = self.vehicle_ammo2;
- self.owner.vehicle_reload1 = self.vehicle_reload1;
- self.owner.vehicle_reload2 = self.vehicle_reload2;
-
- // Cant do this, hides attached objects too.
- //self.exteriormodeltoclient = self.owner;
- //self.tur_head.exteriormodeltoclient = self.owner;
-
- other.flags &= ~FL_ONGROUND;
- self.flags &= ~FL_ONGROUND;
-
- self.team = self.owner.team;
- self.flags -= FL_NOTARGET;
- self.monster_attack = true;
-
- if (IS_REAL_CLIENT(other))
- {
- msg_entity = other;
- WriteByte (MSG_ONE, SVC_SETVIEWPORT);
- WriteEntity(MSG_ONE, self.vehicle_viewport);
-
- WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
- if(self.tur_head)
- {
- WriteAngle(MSG_ONE, self.tur_head.angles.x + self.angles.x); // tilt
- WriteAngle(MSG_ONE, self.tur_head.angles.y + self.angles.y); // yaw
- WriteAngle(MSG_ONE, 0); // roll
- }
- else
- {
- WriteAngle(MSG_ONE, self.angles.x * -1); // tilt
- WriteAngle(MSG_ONE, self.angles.y); // yaw
- WriteAngle(MSG_ONE, 0); // roll
- }
- }
-
- vehicles_clearreturn();
-
- CSQCVehicleSetup(self.owner, self.hud);
-
- vh_player = other;
- vh_vehicle = self;
- MUTATOR_CALLHOOK(VehicleEnter);
- other = vh_player;
- self = vh_vehicle;
-
- self.vehicle_enter();
- antilag_clear(other);
-}
-
-/** vehicles_findgoodexit
- Locates a valid location for the player to exit the vehicle.
- Will first try prefer_spot, then up 100 random spots arround the vehicle
- wich are in direct line of sight and empty enougth to hold a players bbox
-**/
-vector vehicles_findgoodexit(vector prefer_spot)
-{
- //vector exitspot;
- float mysize;
-
- tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, prefer_spot, MOVE_NORMAL, self.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return prefer_spot;
-
- mysize = 1.5 * vlen(self.maxs - self.mins);
- float i;
- vector v, v2;
- v2 = 0.5 * (self.absmin + self.absmax);
- for(i = 0; i < 100; ++i)
- {
- v = randomvec();
- v.z = 0;
- v = v2 + normalize(v) * mysize;
- tracebox(v2, PL_MIN, PL_MAX, v, MOVE_NORMAL, self.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return v;
- }
-
- /*
- exitspot = (self.origin + '0 0 48') + v_forward * mysize;
- tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
-
- exitspot = (self.origin + '0 0 48') - v_forward * mysize;
- tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
-
- exitspot = (self.origin + '0 0 48') + v_right * mysize;
- tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
-
- exitspot = (self.origin + '0 0 48') - v_right * mysize;
- tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
- if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
- return exitspot;
- */
-
- return self.origin;
-}
-
-/** vehicles_exit
- Standarrd vehicle release fucntion.
- custom code goes in self.vehicle_exit
-**/
-float vehicles_exit_running;
-void vehicles_exit(float eject)
-{
- entity _vehicle;
- entity _player;
- entity _oldself = self;
-
- if(vehicles_exit_running)
- {
- dprint("^1vehicles_exit allready running! this is not good..\n");
- return;
- }
-
- vehicles_exit_running = true;
- if(IS_CLIENT(self))
- {
- _vehicle = self.vehicle;
-
- if (_vehicle.vehicle_flags & VHF_PLAYERSLOT)
- {
- _vehicle.vehicle_exit(eject);
- self = _oldself;
- vehicles_exit_running = false;
- return;
- }
- }
- else
- _vehicle = self;
-
- _player = _vehicle.owner;
-
- self = _vehicle;
-
- if (_player)
- {
- if (IS_REAL_CLIENT(_player))
- {
- msg_entity = _player;
- WriteByte (MSG_ONE, SVC_SETVIEWPORT);
- WriteEntity( MSG_ONE, _player);
-
- WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
- WriteAngle(MSG_ONE, 0);
- WriteAngle(MSG_ONE, _vehicle.angles.y);
- WriteAngle(MSG_ONE, 0);
- }
-
- setsize(_player, PL_MIN,PL_MAX);
-
- _player.takedamage = DAMAGE_AIM;
- _player.solid = SOLID_SLIDEBOX;
- _player.movetype = MOVETYPE_WALK;
- _player.effects &= ~EF_NODRAW;
- _player.alpha = 1;
- _player.PlayerPhysplug = func_null;
- _player.vehicle = world;
- _player.view_ofs = PL_VIEW_OFS;
- _player.event_damage = PlayerDamage;
- _player.hud = HUD_NORMAL;
- _player.switchweapon = _vehicle.switchweapon;
-
- CSQCVehicleSetup(_player, HUD_NORMAL);
- }
- _vehicle.flags |= FL_NOTARGET;
-
- if(_vehicle.deadflag == DEAD_NO)
- _vehicle.avelocity = '0 0 0';
-
- _vehicle.tur_head.nodrawtoclient = world;
-
- if(!teamplay)
- _vehicle.team = 0;
-
- vh_player = _player;
- vh_vehicle = _vehicle;
- MUTATOR_CALLHOOK(VehicleExit);
- _player = vh_player;
- _vehicle = vh_vehicle;
-
- _vehicle.team = _vehicle.tur_head.team;
-
- sound (_vehicle, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTEN_NORM);
- _vehicle.vehicle_hudmodel.viewmodelforclient = _vehicle;
- _vehicle.phase = time + 1;
- _vehicle.monster_attack = false;
-
- _vehicle.vehicle_exit(eject);
-
- vehicles_setreturn();
- vehicles_reset_colors();
- _vehicle.owner = world;
- self = _oldself;
-
- vehicles_exit_running = false;
-}
-
-
-void vehicles_regen(float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale)
-{
- if(self.regen_field < field_max)
- if(timer + rpause < time)
- {
- if(_healthscale)
- regen = regen * (self.vehicle_health / self.tur_health);
-
- self.regen_field = min(self.regen_field + regen * delta_time, field_max);
-
- if(self.owner)
- self.owner.regen_field = (self.regen_field / field_max) * 100;
- }
-}
-
-void shieldhit_think()
-{
- self.alpha -= 0.1;
- if (self.alpha <= 0)
- {
- //setmodel(self, "");
- self.alpha = -1;
- self.effects |= EF_NODRAW;
- }
- else
- {
- self.nextthink = time + 0.1;
- }
-}
-
-void vehicles_painframe()
-{
- if(self.owner.vehicle_health <= 50)
- if(self.pain_frame < time)
- {
- float _ftmp;
- _ftmp = self.owner.vehicle_health / 50;
- self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp);
- pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
-
- if(self.vehicle_flags & VHF_DMGSHAKE)
- self.velocity += randomvec() * 30;
-
- if(self.vehicle_flags & VHF_DMGROLL)
- if(self.vehicle_flags & VHF_DMGHEADROLL)
- self.tur_head.angles += randomvec();
- else
- self.angles += randomvec();
-
- }
-}
-
-void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
- self.dmg_time = time;
-
- // WEAPONTODO
- if(DEATH_ISWEAPON(deathtype, WEP_VORTEX))
- damage *= autocvar_g_vehicles_vortex_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
- damage *= autocvar_g_vehicles_machinegun_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
- damage *= autocvar_g_vehicles_rifle_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
- damage *= autocvar_g_vehicles_vaporizer_damagerate;
-
- if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
- damage *= autocvar_g_vehicles_tag_damagerate;
-
- self.enemy = attacker;
-
- if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0))
- {
- if (wasfreed(self.vehicle_shieldent) || self.vehicle_shieldent == world)
- {
- self.vehicle_shieldent = spawn();
- self.vehicle_shieldent.effects = EF_LOWPRECISION;
-
- setmodel(self.vehicle_shieldent, "models/vhshield.md3");
- setattachment(self.vehicle_shieldent, self, "");
- setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
- self.vehicle_shieldent.scale = 256 / vlen(self.maxs - self.mins);
- self.vehicle_shieldent.think = shieldhit_think;
- }
-
- self.vehicle_shieldent.colormod = '1 1 1';
- self.vehicle_shieldent.alpha = 0.45;
- self.vehicle_shieldent.angles = vectoangles(normalize(hitloc - (self.origin + self.vehicle_shieldent.origin))) - self.angles;
- self.vehicle_shieldent.nextthink = time;
- self.vehicle_shieldent.effects &= ~EF_NODRAW;
-
- self.vehicle_shield -= damage;
-
- if(self.vehicle_shield < 0)
- {
- self.vehicle_health -= fabs(self.vehicle_shield);
- self.vehicle_shieldent.colormod = '2 0 0';
- self.vehicle_shield = 0;
- self.vehicle_shieldent.alpha = 0.75;
-
- if(sound_allowed(MSG_BROADCAST, attacker))
- spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
- }
- else
- if(sound_allowed(MSG_BROADCAST, attacker))
- spamsound (self, CH_PAIN, "onslaught/electricity_explode.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
-
- }
- else
- {
- self.vehicle_health -= damage;
-
- if(sound_allowed(MSG_BROADCAST, attacker))
- spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
- }
-
- if(self.damageforcescale < 1 && self.damageforcescale > 0)
- self.velocity += force * self.damageforcescale;
- else
- self.velocity += force;
-
- if(self.vehicle_health <= 0)
- {
- if(self.owner)
- if(self.vehicle_flags & VHF_DEATHEJECT)
- vehicles_exit(VHEF_EJECT);
- else
- vehicles_exit(VHEF_RELESE);
-
-
- antilag_clear(self);
-
- self.vehicle_die();
- vehicles_setreturn();
- }
-}
-
-void vehicles_clearreturn()
-{
- entity ret;
- // Remove "return helper", if any.
- ret = findchain(classname, "vehicle_return");
- while(ret)
- {
- if(ret.wp00 == self)
- {
- ret.classname = "";
- ret.think = SUB_Remove;
- ret.nextthink = time + 0.1;
-
- if(ret.waypointsprite_attached)
- WaypointSprite_Kill(ret.waypointsprite_attached);
-
- return;
- }
- ret = ret.chain;
- }
-}
-
-void vehicles_return()
-{
- pointparticles(particleeffectnum("teleport"), self.wp00.origin + '0 0 64', '0 0 0', 1);
-
- self.wp00.think = vehicles_spawn;
- self.wp00.nextthink = time;
-
- if(self.waypointsprite_attached)
- WaypointSprite_Kill(self.waypointsprite_attached);
-
- remove(self);
-}
-
-void vehicles_showwp_goaway()
-{
- if(self.waypointsprite_attached)
- WaypointSprite_Kill(self.waypointsprite_attached);
-
- remove(self);
-
-}
-
-void vehicles_showwp()
-{
- entity oldself = world;
- vector rgb;
-
- if(self.cnt)
- {
- self.think = vehicles_return;
- self.nextthink = self.cnt;
- }
- else
- {
- self.think = vehicles_return;
- self.nextthink = time +1;
-
- oldself = self;
- self = spawn();
- setmodel(self, "null");
- self.team = oldself.wp00.team;
- self.wp00 = oldself.wp00;
- setorigin(self, oldself.wp00.pos1);
-
- self.nextthink = time + 5;
- self.think = vehicles_showwp_goaway;
- }
-
- if(teamplay && self.team)
- rgb = Team_ColorRGB(self.team);
- else
- rgb = '1 1 1';
- WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, true, RADARICON_POWERUP, rgb);
- if(self.waypointsprite_attached)
- {
- WaypointSprite_UpdateRule(self.waypointsprite_attached, self.wp00.team, SPRITERULE_DEFAULT);
- if(oldself == world)
- WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink);
- WaypointSprite_Ping(self.waypointsprite_attached);
- }
-
- if(oldself != world)
- self = oldself;
-}
-
-void vehicles_setreturn()
-{
- entity ret;
-
- vehicles_clearreturn();
-
- ret = spawn();
- ret.classname = "vehicle_return";
- ret.wp00 = self;
- ret.team = self.team;
- ret.think = vehicles_showwp;
-
- if(self.deadflag != DEAD_NO)
- {
- ret.cnt = max(game_starttime, time) + self.vehicle_respawntime;
- ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 5);
- }
- else
- ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 1);
-
- setmodel(ret, "null");
- setorigin(ret, self.pos1 + '0 0 96');
-}
-
-void vehicles_reset_colors()
-{
- entity e;
- float _effects = 0, _colormap;
- vector _glowmod, _colormod;
-
- if(autocvar_g_nodepthtestplayers)
- _effects |= EF_NODEPTHTEST;
-
- if(autocvar_g_fullbrightplayers)
- _effects |= EF_FULLBRIGHT;
-
- if(self.team)
- _colormap = 1024 + (self.team - 1) * 17;
- else
- _colormap = 1024;
-
- _glowmod = '0 0 0';
- _colormod = '0 0 0';
-
- // Find all ents attacked to main model and setup effects, colormod etc.
- e = findchainentity(tag_entity, self);
- while(e)
- {
- if(e != self.vehicle_shieldent)
- {
- e.effects = _effects; // | EF_LOWPRECISION;
- e.colormod = _colormod;
- e.colormap = _colormap;
- e.alpha = 1;
- }
- e = e.chain;
- }
-
- self.vehicle_hudmodel.effects = self.effects = _effects; // | EF_LOWPRECISION;
- self.vehicle_hudmodel.colormod = self.colormod = _colormod;
- self.vehicle_hudmodel.colormap = self.colormap = _colormap;
- self.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT);
-
- self.alpha = 1;
- self.avelocity = '0 0 0';
- self.velocity = '0 0 0';
- self.effects = _effects;
-}
-
-void vehicle_use()
-{
- dprint("vehicle ",self.netname, " used by ", activator.classname, "\n");
-
- self.tur_head.team = activator.team;
-
- if(self.tur_head.team == 0)
- self.active = ACTIVE_NOT;
- else
- self.active = ACTIVE_ACTIVE;
-
- if(self.active == ACTIVE_ACTIVE && self.deadflag == DEAD_NO)
- {
- dprint("^3Eat shit yall!\n");
- vehicles_setreturn();
- vehicles_reset_colors();
- }
- else if(self.active == ACTIVE_NOT && self.deadflag != DEAD_NO)
- {
-
- }
-}
-
-float vehicle_addplayerslot( entity _owner,
- entity _slot,
- float _hud,
- string _hud_model,
- float() _framefunc,
- void(float) _exitfunc)
-{
- if (!(_owner.vehicle_flags & VHF_MULTISLOT))
- _owner.vehicle_flags |= VHF_MULTISLOT;
-
- _slot.PlayerPhysplug = _framefunc;
- _slot.vehicle_exit = _exitfunc;
- _slot.hud = _hud;
- _slot.vehicle_flags = VHF_PLAYERSLOT;
- _slot.vehicle_viewport = spawn();
- _slot.vehicle_hudmodel = spawn();
- _slot.vehicle_hudmodel.viewmodelforclient = _slot;
- _slot.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT);
-
- setmodel(_slot.vehicle_hudmodel, _hud_model);
- setmodel(_slot.vehicle_viewport, "null");
-
- setattachment(_slot.vehicle_hudmodel, _slot, "");
- setattachment(_slot.vehicle_viewport, _slot.vehicle_hudmodel, "");
-
- return true;
-}
-
-float vehicle_initialize(string net_name,
- string bodymodel,
- string topmodel,
- string hudmodel,
- string toptag,
- string hudtag,
- string viewtag,
- float vhud,
- vector min_s,
- vector max_s,
- float nodrop,
- void(float _spawnflag) spawnproc,
- float _respawntime,
- float() physproc,
- void() enterproc,
- void(float extflag) exitfunc,
- void() dieproc,
- void() thinkproc,
- float use_csqc,
- float _max_health,
- float _max_shield)
-{
- if(!autocvar_g_vehicles)
- return false;
-
- if(self.targetname)
- {
- self.vehicle_controller = find(world, target, self.targetname);
- if(!self.vehicle_controller)
- {
- bprint("^1WARNING: ^7Vehicle with invalid .targetname\n");
- }
- else
- {
- self.team = self.vehicle_controller.team;
- self.use = vehicle_use;
-
- if(teamplay)
- {
- if(self.vehicle_controller.team == 0)
- self.active = ACTIVE_NOT;
- else
- self.active = ACTIVE_ACTIVE;
- }
- }
- }
-
- precache_sound("onslaught/ons_hit2.wav");
- precache_sound("onslaught/electricity_explode.wav");
-
-
- addstat(STAT_HUD, AS_INT, hud);
- addstat(STAT_VEHICLESTAT_HEALTH, AS_INT, vehicle_health);
- addstat(STAT_VEHICLESTAT_SHIELD, AS_INT, vehicle_shield);
- addstat(STAT_VEHICLESTAT_ENERGY, AS_INT, vehicle_energy);
-
- addstat(STAT_VEHICLESTAT_AMMO1, AS_INT, vehicle_ammo1);
- addstat(STAT_VEHICLESTAT_RELOAD1, AS_INT, vehicle_reload1);
-
- addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2);
- addstat(STAT_VEHICLESTAT_RELOAD2, AS_INT, vehicle_reload2);
-
- if(bodymodel == "")
- error("vehicles: missing bodymodel!");
-
- if(hudmodel == "")
- error("vehicles: missing hudmodel!");
-
- if(net_name == "")
- self.netname = self.classname;
- else
- self.netname = net_name;
-
- if(self.team && !teamplay)
- self.team = 0;
-
- self.vehicle_flags |= VHF_ISVEHICLE;
-
- setmodel(self, bodymodel);
-
- self.vehicle_viewport = spawn();
- self.vehicle_hudmodel = spawn();
- self.tur_head = spawn();
- self.tur_head.owner = self;
- self.takedamage = DAMAGE_AIM;
- self.bot_attack = true;
- self.iscreature = true;
- self.teleportable = false; // no teleporting for vehicles, too buggy
- self.damagedbycontents = true;
- self.hud = vhud;
- self.tur_health = _max_health;
- self.tur_head.tur_health = _max_shield;
- self.vehicle_die = dieproc;
- self.vehicle_exit = exitfunc;
- self.vehicle_enter = enterproc;
- self.PlayerPhysplug = physproc;
- self.event_damage = func_null;
- self.touch = vehicles_touch;
- self.think = vehicles_spawn;
- self.vehicle_spawn = spawnproc;
- self.vehicle_respawntime = max(0, _respawntime);
- self.effects = EF_NODRAW;
- self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
- if(!autocvar_g_vehicles_delayspawn || !self.vehicle_respawntime)
- self.nextthink = time;
- else
- self.nextthink = max(time, game_starttime) + max(0, self.vehicle_respawntime + ((random() * 2 - 1) * autocvar_g_vehicles_delayspawn_jitter));
-
- if(autocvar_g_playerclip_collisions)
- self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
-
- if(autocvar_g_nodepthtestplayers)
- self.effects = self.effects | EF_NODEPTHTEST;
-
- if(autocvar_g_fullbrightplayers)
- self.effects = self.effects | EF_FULLBRIGHT;
-
- setmodel(self.vehicle_hudmodel, hudmodel);
- setmodel(self.vehicle_viewport, "null");
-
- if(topmodel != "")
- {
- setmodel(self.tur_head, topmodel);
- setattachment(self.tur_head, self, toptag);
- setattachment(self.vehicle_hudmodel, self.tur_head, hudtag);
- setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
- }
- else
- {
- setattachment(self.tur_head, self, "");
- setattachment(self.vehicle_hudmodel, self, hudtag);
- setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
- }
-
- setsize(self, min_s, max_s);
- if (!nodrop)
- {
- setorigin(self, self.origin);
- tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
- setorigin(self, trace_endpos);
- }
-
- self.pos1 = self.origin;
- self.pos2 = self.angles;
- self.tur_head.team = self.team;
-
- if(MUTATOR_CALLHOOK(VehicleSpawn))
- return false;
-
- return true;
-}
-
-vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname,
- float _pichlimit_min, float _pichlimit_max,
- float _rotlimit_min, float _rotlimit_max, float _aimspeed)
-{
- vector vtmp, vtag;
- float ftmp;
- vtag = gettaginfo(_turrret, gettagindex(_turrret, _tagname));
- vtmp = vectoangles(normalize(_target - vtag));
- vtmp = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(_vehic.angles), AnglesTransform_FromAngles(vtmp))) - _turrret.angles;
- vtmp = AnglesTransform_Normalize(vtmp, true);
- ftmp = _aimspeed * frametime;
- vtmp.y = bound(-ftmp, vtmp.y, ftmp);
- vtmp.x = bound(-ftmp, vtmp.x, ftmp);
- _turrret.angles_y = bound(_rotlimit_min, _turrret.angles.y + vtmp.y, _rotlimit_max);
- _turrret.angles_x = bound(_pichlimit_min, _turrret.angles.x + vtmp.x, _pichlimit_max);
- return vtag;
-}
-
-void vehicles_gib_explode()
-{
- sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
- pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
- remove(self);
-}
-
-void vehicles_gib_think()
-{
- self.alpha -= 0.1;
- if(self.cnt >= time)
- remove(self);
- else
- self.nextthink = time + 0.1;
-}
-
-entity vehicle_tossgib(entity _template, vector _vel, string _tag, float _burn, float _explode, float _maxtime, vector _rot)
-{
- entity _gib = spawn();
- setmodel(_gib, _template.model);
- setorigin(_gib, gettaginfo(self, gettagindex(self, _tag)));
- _gib.velocity = _vel;
- _gib.movetype = MOVETYPE_TOSS;
- _gib.solid = SOLID_CORPSE;
- _gib.colormod = '-0.5 -0.5 -0.5';
- _gib.effects = EF_LOWPRECISION;
- _gib.avelocity = _rot;
-
- if(_burn)
- _gib.effects |= EF_FLAME;
-
- if(_explode)
- {
- _gib.think = vehicles_gib_explode;
- _gib.nextthink = time + random() * _explode;
- _gib.touch = vehicles_gib_explode;
- }
- else
- {
- _gib.cnt = time + _maxtime;
- _gib.think = vehicles_gib_think;
- _gib.nextthink = time + _maxtime - 1;
- _gib.alpha = 1;
- }
- return _gib;
-}
-
-/*
-vector predict_target(entity _targ, vector _from, float _shot_speed)
-{
- float i; // loop
- float _distance; // How far to target
- float _impact_time; // How long untill projectile impacts
- vector _predict_pos; // Predicted enemy location
- vector _original_origin;// Where target is before predicted
-
- _original_origin = real_origin(_targ); // Typicaly center of target BBOX
-
- _predict_pos = _original_origin;
- for(i = 0; i < 4; ++i) // Loop a few times to increase prediction accuracy (increase loop count if accuracy is to low)
- {
- _distance = vlen(_predict_pos - _from); // Get distance to previos predicted location
- _impact_time = _distance / _shot_speed; // Calculate impact time
- _predict_pos = _original_origin + _targ.velocity * _impact_time; // Calculate new predicted location
- }
-
- return _predict_pos;
-}
-*/
+++ /dev/null
-#ifndef VEHICLES_H
-#define VEHICLES_H
-
-#ifdef VEHICLES_ENABLED
-#include "vehicles.qc"
-
-#include "racer.qc"
-#include "spiderbot.qc"
-#include "raptor.qc"
-#ifndef VEHICLES_NO_UNSTABLE
-#include "bumblebee.qc"
-#endif
-#endif
-#endif
+++ /dev/null
-#ifndef VEHICLES_DEF_H
-#define VEHICLES_DEF_H
-
-#include "../tturrets/include/turrets_early.qh"
-
-// #define VEHICLES_USE_ODE
-#define VEHICLES_ENABLED
-#ifdef VEHICLES_ENABLED
-
-.int vehicle_flags;
-const int VHF_ISVEHICLE = 2; /// Indicates vehicle
-const int VHF_HASSHIELD = 4; /// Vehicle has shileding
-const int VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates
-const int VHF_HEALTHREGEN = 16; /// Vehicles health regenerates
-const int VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates
-const int VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage
-const int VHF_MOVE_GROUND = 128; /// Vehicle moves on gound
-const int VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound
-const int VHF_MOVE_FLY = 512; /// Vehicle is airborn
-const int VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50%
-const int VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50%
-const int VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50%
-const int VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots
-const int VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle
-
-.entity gun1;
-.entity gun2;
-.entity gun3;
-.entity vehicle_shieldent; /// Entity to disply the shild effect on damage
-.entity vehicle;
-.entity vehicle_viewport;
-.entity vehicle_hudmodel;
-.entity vehicle_controller;
-
-.entity gunner1;
-.entity gunner2;
-
-.float vehicle_health; /// If self is player this is 0..100 indicating precentage of health left on vehicle. If self is vehile, this is the real health value.
-.float vehicle_energy; /// If self is player this is 0..100 indicating precentage of energy left on vehicle. If self is vehile, this is the real energy value.
-.float vehicle_shield; /// If self is player this is 0..100 indicating precentage of shield left on vehicle. If self is vehile, this is the real shield value.
-
-.float vehicle_ammo1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo1 value.
-.float vehicle_reload1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload1 value.
-.float vehicle_ammo2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo2 value.
-.float vehicle_reload2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload2 value.
-
-.float sound_nexttime;
-const float VOL_VEHICLEENGINE = 1;
-
-.float hud;
-.float dmg_time;
-.float vehicle_respawntime;
-//.void() vehicle_spawn;
-
-void vehicles_exit(float eject);
-.void(float exit_flags) vehicle_exit;
-const float VHEF_NORMAL = 0; /// User pressed exit key
-const float VHEF_EJECT = 1; /// User pressed exit key 3 times fast (not implemented) or vehile is dying
-const float VHEF_RELESE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented)
-
-const float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05
-const float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A
-const float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80
-
-.void() vehicle_enter; /// Vehicles custom funciton to be executed when owner exit it
-.void() vehicle_die; /// Vehicles custom function to be executed when vehile die
-const float VHSF_NORMAL = 0;
-const float VHSF_FACTORY = 2;
-.void(float _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns
-.float(float _imp) vehicles_impulse;
-.float vehicle_weapon2mode = volly_counter;
-
-#ifdef VEHICLES_USE_ODE
-void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object
-void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force
-void(entity e, vector torque) physics_addtorque = #542; // add relative torque
-#endif // VEHICLES_USE_ODE
-#endif // VEHICLES_ENABLED
-#endif
wp.team = t;
wp.owner = own;
wp.currentammo = hideable;
- if(own)
+ if (own)
{
- if(own.ownfield)
- remove(own.ownfield);
- own.ownfield = wp;
+ if (own.(ownfield))
+ remove(own.(ownfield));
+ own.(ownfield) = wp;
wp.owned_by_field = ownfield;
}
wp.fade_rate = maxdistance;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/weapons/weapons.qh"
- #include "accuracy.qh"
- #include "../autocvars.qh"
- #include "../constants.qh"
- #include "../defs.qh"
- #include "../mutators/mutators_include.qh"
-#endif
+#include "accuracy.qh"
+#include "../_all.qh"
+
+#include "../mutators/mutators_include.qh"
+#include "../../common/constants.qh"
+#include "../../common/teams.qh"
+#include "../../common/util.qh"
+#include "../../common/weapons/all.qh"
float accuracy_byte(float n, float d)
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/weapons/weapons.qh"
- #include "common.qh"
- #include "../t_items.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
- #include "../../common/notifications.qh"
- #include "../../common/deathtypes.qh"
-#endif
+#include "common.qh"
+#include "../_all.qh"
+
+#include "../t_items.qh"
+#include "../../common/constants.qh"
+#include "../../common/deathtypes.qh"
+#include "../../common/notifications.qh"
+#include "../../common/util.qh"
+#include "../../common/weapons/all.qh"
void W_GiveWeapon (entity e, float wep)
{
player.prevstrengthsoundattempt = time;
}
-float W_CheckProjectileDamage(entity inflictor, entity projowner, float deathtype, float exception)
+float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
{
float is_from_contents = (deathtype == DEATH_SLIME || deathtype == DEATH_LAVA);
float is_from_owner = (inflictor == projowner);
.float prevstrengthsound;
.float prevstrengthsoundattempt;
void W_PlayStrengthSound(entity player);
-float W_CheckProjectileDamage(entity inflictor, entity projowner, float deathtype, float exception);
+float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception);
void W_PrepareExplosionByDamage(entity attacker, void() explode);
#endif
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../common/constants.qh"
- #include "../../common/weapons/weapons.qh"
- #include "csqcprojectile.qh"
- #include "../t_items.qh"
- #include "../constants.qh"
- #include "../defs.qh"
- #include "../command/common.qh"
-#endif
+#include "csqcprojectile.qh"
+#include "../_all.qh"
+
+#include "../t_items.qh"
+
+#include "../command/common.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/weapons/all.qh"
.float csqcprojectile_type;
-float CSQCProjectile_SendEntity(entity to, int sf)
+bool CSQCProjectile_SendEntity(entity to, int sf)
{
float ft, fr;
if(sf & 2)
WriteByte(MSG_ENTITY, self.csqcprojectile_type); // TODO maybe put this into sf?
- return 1;
+ return true;
}
.vector csqcprojectile_oldorigin;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/weapons/weapons.qh"
- #include "hitplot.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
- #include "../antilag.qh"
-#endif
+#include "hitplot.qh"
+#include "../_all.qh"
+
+#include "../antilag.qh"
+#include "../../common/weapons/all.qh"
vector W_HitPlotUnnormalizedUntransform(vector screenforward, vector screenright, vector screenup, vector v)
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/weapons/weapons.qh"
- #include "selection.qh"
- #include "weaponsystem.qh"
- #include "../t_items.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
-#endif
+#include "selection.qh"
+#include "../_all.qh"
+
+#include "weaponsystem.qh"
+#include "../t_items.qh"
+#include "../waypointsprites.qh"
+#include "../../common/constants.qh"
+#include "../../common/util.qh"
+#include "../../common/weapons/all.qh"
// switch between weapons
void Send_WeaponComplain(entity e, float wpn, float type)
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/weapons/weapons.qh"
- #include "spawning.qh"
- #include "weaponsystem.qh"
- #include "../t_items.qh"
- #include "../autocvars.qh"
- #include "../constants.qh"
- #include "../defs.qh"
- #include "../mutators/mutators_include.qh"
-#endif
+#include "spawning.qh"
+#include "../_all.qh"
+
+#include "weaponsystem.qh"
+#include "../mutators/mutators_include.qh"
+#include "../t_items.qh"
+#include "../../common/weapons/all.qh"
string W_Apply_Weaponreplace(string in)
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/util.qh"
- #include "../../common/weapons/weapons.qh"
- #include "throwing.qh"
- #include "weaponsystem.qh"
- #include "../t_items.qh"
- #include "../autocvars.qh"
- #include "../constants.qh"
- #include "../defs.qh"
- #include "../../common/notifications.qh"
- #include "../mutators/mutators_include.qh"
- #include "../../common/mapinfo.qh"
-#endif
+#include "throwing.qh"
+#include "../_all.qh"
+
+#include "weaponsystem.qh"
+#include "../mutators/mutators_include.qh"
+#include "../t_items.qh"
+#include "../g_damage.qh"
+#include "../../common/mapinfo.qh"
+#include "../../common/notifications.qh"
+#include "../../common/util.qh"
+#include "../../common/weapons/all.qh"
void thrown_wep_think()
{
entity oldself, wep;
float thisammo, i;
string s;
- var .float ammotype = (get_weaponinfo(wpn)).ammo_field;
+ var .int ammotype = (get_weaponinfo(wpn)).ammo_field;
wep = spawn();
// if our weapon is loaded, give its load back to the player
if(self.(weapon_load[self.weapon]) > 0)
{
- own.ammotype += self.(weapon_load[self.weapon]);
+ own.(ammotype) += self.(weapon_load[self.weapon]);
self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
}
- wep.ammotype = 0;
+ wep.(ammotype) = 0;
}
else if(doreduce)
{
// if our weapon is loaded, give its load back to the player
if(self.(weapon_load[self.weapon]) > 0)
{
- own.ammotype += self.(weapon_load[self.weapon]);
+ own.(ammotype) += self.(weapon_load[self.weapon]);
self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
}
- thisammo = min(own.ammotype, wep.ammotype);
- wep.ammotype = thisammo;
- own.ammotype -= thisammo;
+ thisammo = min(own.(ammotype), wep.(ammotype));
+ wep.(ammotype) = thisammo;
+ own.(ammotype) -= thisammo;
switch(ammotype)
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/weapons/weapons.qh"
- #include "tracing.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
- #include "../antilag.qh"
-#endif
+#include "tracing.qh"
+#include "../_all.qh"
+
+#include "accuracy.qh"
+#include "common.qh"
+#include "hitplot.qh"
+
+#include "../g_damage.qh"
+#include "../g_subs.qh"
+#include "../antilag.qh"
+
+#include "../../common/constants.qh"
+#include "../../common/util.qh"
+
+#include "../../common/weapons/all.qh"
+
+#include "../../warpzonelib/common.qh"
// 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.
// Ballistics Tracing
// ====================
-void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, float deathtype)
+void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype)
{
vector hitloc, force, endpoint, dir;
entity ent, endent;
.float railgundistance;
.vector railgunforce;
-void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, float deathtype);
+void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype);
float fireBullet_trace_callback_eff;
entity fireBullet_last_hit;
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/urllib.qh"
- #include "../../common/weapons/weapons.qh"
- #include "weaponstats.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
-#endif
+#include "weaponstats.qh"
+#include "../_all.qh"
+
+#include "../g_world.qh"
+
+#include "../../common/urllib.qh"
+#include "../../common/weapons/all.qh"
void WeaponStats_Init()
{
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../common/constants.qh"
- #include "../../common/util.qh"
- #include "../../common/animdecide.qh"
- #include "../../common/monsters/monsters.qh"
- #include "../../common/weapons/weapons.qh"
- #include "weaponsystem.qh"
- #include "../t_items.qh"
- #include "../autocvars.qh"
- #include "../defs.qh"
- #include "../../common/notifications.qh"
- #include "../mutators/mutators_include.qh"
- #include "../command/common.qh"
- #include "../../csqcmodellib/sv_model.qh"
- #include "../round_handler.qh"
-#endif
+#include "weaponsystem.qh"
+#include "../_all.qh"
+
+#include "selection.qh"
+
+#include "../command/common.qh"
+#include "../mutators/mutators_include.qh"
+#include "../round_handler.qh"
+#include "../t_items.qh"
+#include "../../common/animdecide.qh"
+#include "../../common/constants.qh"
+#include "../../common/monsters/all.qh"
+#include "../../common/notifications.qh"
+#include "../../common/util.qh"
+#include "../../common/weapons/all.qh"
+#include "../../csqcmodellib/sv_model.qh"
/*
===========================================================================
--- /dev/null
+#!/bin/bash
+set -eu
+cd "$(dirname "$0")"
+cd ..
+
+declare -a NOWARN=(
+ '-Wno-field-redeclared'
+ '-Wno-unused-variable'
+ '-Wno-implicit-function-pointer'
+)
+declare -a FEATURES=(
+ '-DVEHICLES_ENABLED=1'
+ '-DVEHICLES_USE_ODE=0'
+)
+declare QCC=../../../gmqcc/gmqcc
+
+function check() {
+ declare -l base="$1"
+ declare -la predefs=("${!2}")
+ find "$base" -type f -name '*.qc' -print0 | sort -z | while IFS= read -r -d '' file; do
+ echo "$file"
+ ${QCC} -std=gmqcc -fftepp -fftepp-predefs -Werror -Wall "${NOWARN[@]}" "${FEATURES[@]}" -futf8 -O3 "${predefs[@]}" "$file" >/dev/null
+ done
+}
+
+clientdefs=("-DCSQC" "common/util-pre.qh" "dpdefs/csprogsdefs.qh")
+check "client" clientdefs[@]
+
+serverdefs=("-DSVQC" "common/util-pre.qh" "server/sys-pre.qh" "dpdefs/progsdefs.qh" "dpdefs/dpextensions.qh" "server/sys-post.qh" "server/defs.qh" "server/autocvars.qh")
+check "server" serverdefs[@]
+
+menudefs=("-DMENUQC" "common/util-pre.qh" "dpdefs/menudefs.qh")
+check "menu" menudefs[@]
+#include "anglestransform.qh"
+
#if defined(CSQC)
#include "../dpdefs/csprogsdefs.qh"
- #include "anglestransform.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#include "../dpdefs/progsdefs.qh"
#include "../dpdefs/dpextensions.qh"
- #include "anglestransform.qh"
#endif
#ifdef POSITIVE_PITCH_IS_DOWN
+#include "client.qh"
+#include "common.qh"
+
#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "common.qh"
- #include "client.qh"
#include "../client/autocvars.qh"
#include "../csqcmodellib/cl_model.qh"
+ #include "../dpdefs/csprogsdefs.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#endif
+#include "common.qh"
+
#if defined(CSQC)
#include "../dpdefs/csprogsdefs.qh"
- #include "common.qh"
#include "../server/t_items.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
+ #include "../common/weapons/all.qh"
#include "../dpdefs/dpextensions.qh"
- #include "common.qh"
- #include "../common/weapons/weapons.qh"
+ #include "../dpdefs/progsdefs.qh"
#endif
void WarpZone_Accumulator_Clear(entity acc)
return nearest;
}
+float WarpZoneLib_BadClassname(string myclassname)
+{
+ switch(myclassname)
+ {
+ case "weapon_info":
+ case "monster_info":
+ case "deathtype":
+ case "callback":
+ case "callbackchain":
+ case "weaponentity":
+ case "exteriorweaponentity":
+ case "csqc_score_team":
+ case "pingplreport":
+ case "ent_client_scoreinfo":
+ case "saved_cvar_value":
+ case "accuracy":
+ case "entcs_sender_v2":
+ case "entcs_receiver_v2":
+ case "clientinit":
+ case "sprite_waypoint":
+ case "waypoint":
+ case "gibsplash":
+ //case "net_linked": // actually some real entities are linked without classname, fail
+ case "":
+ return true;
+ }
+
+ if(startsWith(myclassname, "msg_"))
+ return true;
+
+ if(startsWith(myclassname, "target_"))
+ return true;
+
+ if(startsWith(myclassname, "info_"))
+ return true;
+
+ return false;
+}
+
.float WarpZone_findradius_hit;
.entity WarpZone_findradius_next;
void WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift, float needlineofsight)
for(e = e0; e; e = e.chain)
{
+ if(WarpZoneLib_BadClassname(e.classname))
+ continue;
p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
if(needlineofsight)
{
}
for(e = wz; e; e = e.WarpZone_findradius_next)
{
+ if(WarpZoneLib_BadClassname(e.classname))
+ continue;
+
org0_new = WarpZone_TransformOrigin(e, org);
traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
org_new = trace_endpos;
WarpZone_RefSys_Copy(e, me);
return e;
}
+
+float WarpZoneLib_ExactTrigger_Touch()
+{
+ return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other);
+}
+
+
+void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
+{
+ float eps = 0.0625;
+ tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
+ if (trace_startsolid)
+ return;
+ if (trace_fraction < 1)
+ {
+ // hit something
+ // adjust origin in the other direction...
+ setorigin(e,e.origin - by * (1 - trace_fraction));
+ }
+}
+
+float WarpZoneLib_MoveOutOfSolid(entity e)
+{
+ vector o, m0, m1;
+
+ o = e.origin;
+ traceline(o, o, MOVE_WORLDONLY, e);
+ if (trace_startsolid)
+ return false;
+
+ tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
+ if (!trace_startsolid)
+ return true;
+
+ m0 = e.mins;
+ m1 = e.maxs;
+ e.mins = '0 0 0';
+ e.maxs = '0 0 0';
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x);
+ e.mins_x = m0_x;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x);
+ e.maxs_x = m1_x;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y);
+ e.mins_y = m0_y;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y);
+ e.maxs_y = m1_y;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z);
+ e.mins_z = m0_z;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z);
+ e.maxs_z = m1_z;
+ setorigin(e, e.origin);
+
+ tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
+ if (trace_startsolid)
+ {
+ setorigin(e, o);
+ return false;
+ }
+
+ return true;
+}
#ifndef BITXOR_ASSIGN
# define BITXOR_ASSIGN(a,b) ((a) = ((a) | (b)) - ((a) & (b)))
#endif
+float WarpZoneLib_MoveOutOfSolid(entity e);
+#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
+
+float WarpZoneLib_ExactTrigger_Touch();
+void WarpZoneLib_ExactTrigger_Init();
+
+// WARNING: this kills the trace globals
+#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
+#define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
#endif
+#include "mathlib.qh"
#if defined(CSQC)
#include "../dpdefs/csprogsdefs.qh"
- #include "mathlib.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
#include "../dpdefs/dpextensions.qh"
- #include "mathlib.qh"
+ #include "../dpdefs/progsdefs.qh"
#endif
int fpclassify(float x)
const float M_LOG10E = 0.43429448190325182765; /* log_10 e */
const float M_LN2 = 0.69314718055994530942; /* log_e 2 */
const float M_LN10 = 2.30258509299404568402; /* log_e 10 */
-const float M_PI = 3.14159265358979323846; /* pi */
+// -Wdouble-declaration
+#define M_PI 3.14159265358979323846 /* pi */
const float M_PI_2 = 1.57079632679489661923; /* pi/2 */
const float M_PI_4 = 0.78539816339744830962; /* pi/4 */
const float M_1_PI = 0.31830988618379067154; /* 1/pi */
+#include "server.qh"
+
+#include "common.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "common.qh"
- #include "server.qh"
#include "../common/constants.qh"
+ #include "../common/triggers/subs.qh"
#include "../common/util.qh"
+ #include "../dpdefs/dpextensions.qh"
+ #include "../dpdefs/progsdefs.qh"
+ #include "../server/command/common.qh"
#include "../server/constants.qh"
#include "../server/defs.qh"
- #include "../server/command/common.qh"
#endif
#ifdef WARPZONELIB_KEEPDEBUG
WarpZone_PostTeleportPlayer_Callback(player);
}
-float WarpZone_Teleported_Send(entity to, float sf)
+bool WarpZone_Teleported_Send(entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
WriteCoord(MSG_ENTITY, self.angles.x);
}
}
-float WarpZone_Send(entity to, float sendflags)
+bool WarpZone_Send(entity to, int sendflags)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
return true;
}
-float WarpZone_Camera_Send(entity to, float sendflags)
+bool WarpZone_Camera_Send(entity to, int sendflags)
{
int f = 0;
WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
+#include "util_server.qh"
+
+#include "common.qh"
+
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "common.qh"
- #include "util_server.qh"
#include "../csqcmodellib/sv_model.qh"
+ #include "../dpdefs/dpextensions.qh"
+ #include "../dpdefs/progsdefs.qh"
#endif
-
-void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
-{
- float eps = 0.0625;
- tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
- if (trace_startsolid)
- return;
- if (trace_fraction < 1)
- {
- // hit something
- // adjust origin in the other direction...
- setorigin(e,e.origin - by * (1 - trace_fraction));
- }
-}
-
-float WarpZoneLib_MoveOutOfSolid(entity e)
-{
- vector o, m0, m1;
-
- o = e.origin;
- traceline(o, o, MOVE_WORLDONLY, e);
- if (trace_startsolid)
- return false;
-
- tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
- if (!trace_startsolid)
- return true;
-
- m0 = e.mins;
- m1 = e.maxs;
- e.mins = '0 0 0';
- e.maxs = '0 0 0';
- WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x);
- e.mins_x = m0_x;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x);
- e.maxs_x = m1_x;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y);
- e.mins_y = m0_y;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y);
- e.maxs_y = m1_y;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z);
- e.mins_z = m0_z;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z);
- e.maxs_z = m1_z;
- setorigin(e, e.origin);
-
- tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
- if (trace_startsolid)
- {
- setorigin(e, o);
- return false;
- }
-
- return true;
-}
-
-float WarpZoneLib_ExactTrigger_Touch()
-{
- return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other);
-}
+#include "common.qh"
void WarpZoneLib_ExactTrigger_Init()
{
float WarpZoneLib_MoveOutOfSolid(entity e);
float WarpZoneLib_ExactTrigger_Touch();
+#ifdef SVQC
void WarpZoneLib_ExactTrigger_Init();
#endif
+#endif
**Extended Team
Antonio "terencehill" Piu
Archer
+BuddyFriendGuy
Debugger
GATTS
Halogene
IDWMaster
Jan "zykure" Behrens
JH0nny
+Luigi
Łukasz "kuniu the frogg" Polek
Matthias "matthiaskrgr" Krüger
Mattia "Melanosuchus" Basaglia
nifrek
*Level Design
+Amadeusz "amade/proraide" Sławiński
Ben "MooKow" Banker
Calinou
Cortez
Debugger
Jakob "tZork" Markström Gröhn
Konrad "Justin" Slawinski
+Maddin
+L0
Łukasz "kuniu the frogg" Polek
Maik "SavageX" Merten
Marvin "Mirio" Beck
Rasmus "FruitieX" Eskola
Ruszkai "CuBe0wL" Ákos
Severin "sev" Meyer
+ShadoW
*Music / Sound FX
+AquaNova (Archer)
blkrbt
chooksta
Independent.nu
{SC0RP} - Ian "ID" Dorrell
Stephan
unfa
-AquaNova (Archer)
*Game Code
Samual "Ares" Lenks
**Other Active Contributors
Erik "Ablu" Schilling
-Jope "Sless" Withers
Mircea "Taoki" Kitsune
-Robert "ai" Kuroto
+Penguinum
**Translators
*Asturian
Llumex03
+Tornes "Tornes.Llume" Ḷḷume
Ximielga
*Belarusian
lokster
set_killer
+*Chinese (China)
+Antonidas
+kalawore
+sapphireliu
+
*Czech
shogun assassin/woky
+Superovoce
Tomáš "CZHeron" Volavka
*Dutch
vegiburger
*English (Australia)
+Laurene "sunflowers" Albrand
Zac "Mario" Jardine
*Finnish
Yepoleb
*Greek
-Γιάννης "Evropi" Α.
+Γιάννης "Evropi" Ανθυμίδης
Konstantinos "LDinos" Mihalenas
Savoritias
Vindex
Ruszkai "CuBe0wL" Ákos
xaN1C4n3
-*Japanese
-Lento
-
*Italian
Antonio "terencehill" Piu
Felice "MaidenBeast" Sallustio
Amadeusz "amade/proraide" Sławiński
*Portuguese
-Ricardo "Hellgardia" Silva
+Ricardo Manuel "Hellgardia" da Cruz Coelho da Silva
xXxCHAOTICxXx
*Romanian
+Adrian-Ciprian "adrian.tinjala" Tînjală
BusterDBK
Mircea "Taoki" Kitsune
Tudor "TropiKo" Ionel
*Serbian
Саша "salepetronije" Петровић
Pendulla
-Ristovski
+Rafael "Ristovski"
*Spanish
0000simon
Innovati
Jitspoe
Jody Gallagher
+Jope "Sless" Withers
Juergen "LowDragon" Timm
KadaverJack
Kevin "Tyrann" Shanahan
Qantourisc
Oleh "BlaXpirit" Prypin
Rick "Rat" Kelley
+Robert "ai" Kuroto
Ronan
Sajt
Saulo "mand1nga" Gil