qcsrc/server/fteqcc.log
weapons.qc.tmp
*.lno
-qcsrc/qccversion.*
+qcsrc/qccversion*
+qcsrc/server/precache-for-csqc.inc
+.DS_Store
seta hud_panel_notify_fontsize "" "multiplier for the font size used for player names in the panel"
seta hud_panel_notify_fadetime "" "fade out time"
seta hud_panel_notify_time "" "time that a new entry stays until it fades out"
+seta hud_panel_notify_icon_aspect "" "aspect ratio of total drawing area per icon"
seta hud_panel_timer "" "enable/disable this panel"
seta hud_panel_timer_pos "" "position of this base of the panel"
seta hud_panel_centerprint_fade_subsequent_passtwo_minalpha "" "minimum factor that the second pass can fade to"
seta hud_panel_centerprint_fade_subsequent_minfontsize "" "minimum factor for the font size from the subsequent fading effects"
seta hud_panel_centerprint_fade_minfontsize "" "minimum factor for the font size from the fading in/out effects"
+
+seta hud_panel_buffs "" "enable/disable this panel"
+seta hud_panel_buffs_pos "" "position of this panel"
+seta hud_panel_buffs_size "" "size of this panel"
+seta hud_panel_buffs_bg "" "if set to something else than \"\" = override default background"
+seta hud_panel_buffs_bg_color "" "if set to something else than \"\" = override default panel background color"
+seta hud_panel_buffs_bg_color_team "" "override panel color with team color in team based games"
+seta hud_panel_buffs_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
+seta hud_panel_buffs_bg_border "" "if set to something else than \"\" = override default size of border around the background"
+seta hud_panel_buffs_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
r_mipskins 1
r_shadow_realtime_world_lightmaps 1
cl_decals_fadetime 5
-cl_decals_time 2
+cl_decals_time 1
seta cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
seta cl_nogibs 0 "reduce number of violence effects, or remove them totally"
seta cl_particlegibs 0 "simpler gibs"
seta cl_gibs_damageforcescale 3.5 "force to push around gibs"
-seta cl_gibs_lifetime 5 "average lifetime of gibs"
+seta cl_gibs_lifetime 2.5 "average lifetime of gibs"
seta cl_gibs_velocity_scale 1 "gib throw velocity force scale"
seta cl_gibs_velocity_random 1 "gib throw velocity randomness scale"
seta cl_gibs_velocity_up 1 "extra z velocity for gibs"
seta cl_casings_bronze_time 10 "bullet casings lifetime"
seta cl_casings_ticrate 0.1 "ticrate for casings"
seta cl_casings_sloppy 1 "sloppy casings, may temporarily penetrate walls"
-seta cl_projectiles_sloppy 0 "sloppy projectiles, may temporarily penetrate walls"
+seta cl_projectiles_sloppy 1 "sloppy projectiles, may temporarily penetrate walls"
cl_stainmaps 0
cl_particles_smoke 1
vid_gl20 1
seta g_maplist_votable_abstain 0 "when 1, you can abstain from your vote"
seta g_maplist_votable_screenshot_dir "maps levelshots" "where to look for map screenshots"
+set sv_vote_gametype 0 "show a vote screen for gametypes before map vote screen"
+set sv_vote_gametype_keeptwotime 10 "show only 2 options for this amount of time during gametype vote screen"
+set sv_vote_gametype_options "dm ctf ca lms tdm ft"
+set sv_vote_gametype_timeout 20
+set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
+
set g_chat_flood_spl 3 "normal chat: seconds between lines to not count as flooding"
set g_chat_flood_lmax 2 "normal chat: maximum number of lines per chat message at once"
set g_chat_flood_burst 2 "normal chat: allow bursts of so many chat lines"
set con_completion_vmap map
set con_completion_vnextmap map
set con_completion_vdomap map
-set con_completion_playermodel models/player/*.iqm
+set con_completion_playermodel "models/player/*.iqm"
// helper
// these non-saved engine cvars shall be saved
set cl_loddistance1 1024
set cl_loddistance2 3072
-seta cl_playerdetailreduction 1 "the higher, the less detailed player models are displayed (LOD)"
+seta cl_playerdetailreduction 4 "the higher, the less detailed player models are displayed (LOD)"
seta cl_modeldetailreduction 1 "the higher, the less detailed certain map models are displayed (LOD)"
set g_mapinfo_settemp_acl "+*" "ACL for mapinfo setting cvars"
r_fakelight 1
r_water_hideplayer 1 // hide your own feet/player model in refraction views, this way you don't see half of your body under water
+r_water_refractdistort 0.019
// strength sound settings
set sv_strengthsound_antispam_time 0.1 "minimum distance of strength sounds"
cl_decals 1
cl_decals_models 0
-cl_decals_time 4
-cl_particles_quality 1
+cl_decals_fadetime 4
+cl_particles 1
+cl_particles_quality 1.0
cl_damageeffect 1
cl_spawn_point_particles 1
-cl_playerdetailreduction 0.5
+cl_playerdetailreduction 4.0
gl_flashblend 0
gl_picmip -1
mod_q3bsp_nolightmaps 0
hud_powerup 0
r_depthfirst 2
r_drawdecals_drawdistance 500
-r_drawparticles_drawdistance 2000
+r_drawparticles_drawdistance 1500
r_glsl_deluxemapping 1
r_glsl_offsetmapping 0
r_glsl_offsetmapping_reliefmapping 0
cl_decals 1
cl_decals_models 0
-cl_decals_time 2
+cl_decals_fadetime 2
+cl_particles 1
cl_particles_quality 0.4
cl_damageeffect 0
cl_spawn_point_particles 0
-cl_playerdetailreduction 2
+cl_playerdetailreduction 4
gl_flashblend 1
gl_picmip 1
mod_q3bsp_nolightmaps 1
cl_decals 1
cl_decals_models 0
-cl_decals_time 2
-cl_particles_quality 1
+cl_decals_fadetime 2
+cl_particles 1
+cl_particles_quality 0.8
cl_damageeffect 0
cl_spawn_point_particles 0
-cl_playerdetailreduction 1
+cl_playerdetailreduction 4
gl_flashblend 0
gl_picmip 0
mod_q3bsp_nolightmaps 0
hud_powerup 0
r_depthfirst 0
r_drawdecals_drawdistance 300
-r_drawparticles_drawdistance 1000
+r_drawparticles_drawdistance 750
r_glsl_deluxemapping 0
r_glsl_offsetmapping 0
r_glsl_offsetmapping_reliefmapping 0
cl_decals 1
cl_decals_models 0
-cl_decals_time 2
-cl_particles_quality 1
+cl_decals_fadetime 2
+cl_particles 1
+cl_particles_quality 1.0
cl_damageeffect 1
cl_spawn_point_particles 1
-cl_playerdetailreduction 1
+cl_playerdetailreduction 4
gl_flashblend 0
gl_picmip 0
mod_q3bsp_nolightmaps 0
cl_decals 0
cl_decals_models 0
-cl_decals_time 2
+cl_decals_fadetime 2
+cl_particles 1
cl_particles_quality 0.4
cl_damageeffect 0
cl_spawn_point_particles 0
cl_decals 1
cl_decals_models 1
-cl_decals_time 10
-cl_particles_quality 1
+cl_decals_fadetime 10
+cl_particles 1
+cl_particles_quality 1.0
cl_damageeffect 2
cl_spawn_point_particles 1
cl_playerdetailreduction 0
hud_powerup 0.5
r_depthfirst 2
r_drawdecals_drawdistance 500
-r_drawparticles_drawdistance 2000
+r_drawparticles_drawdistance 3000
r_glsl_deluxemapping 1
r_glsl_offsetmapping 1
r_glsl_offsetmapping_reliefmapping 1
cl_decals 1
cl_decals_models 0
-cl_decals_time 10
-cl_particles_quality 1
-cl_damageeffect 1
+cl_decals_fadetime 10
+cl_particles 1
+cl_particles_quality 1.0
+cl_damageeffect 2
cl_spawn_point_particles 1
cl_playerdetailreduction 0
gl_flashblend 0
alias sv_hook_gameend
+// =====================
+// 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
+alias sv_vote_gametype_hook_as
+alias sv_vote_gametype_hook_ca
+alias sv_vote_gametype_hook_ctf
+alias sv_vote_gametype_hook_cts
+alias sv_vote_gametype_hook_dm
+alias sv_vote_gametype_hook_dom
+alias sv_vote_gametype_hook_ft
+alias sv_vote_gametype_hook_inv
+alias sv_vote_gametype_hook_ka
+alias sv_vote_gametype_hook_kh
+alias sv_vote_gametype_hook_lms
+alias sv_vote_gametype_hook_nb
+alias sv_vote_gametype_hook_ons
+alias sv_vote_gametype_hook_rc
+alias sv_vote_gametype_hook_tdm
+
+
// ===========
// leadlimit
// ===========
set g_tdm_teams 2 "how many teams are in team deathmatch (set by mapinfo)"
set g_tdm_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
seta g_tdm_teams_override 0 "how many teams are in team deathmatch"
+set g_tdm_point_limit -1 "TDM point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+set g_tdm_point_leadlimit -1 "TDM point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
// ============
set g_domination_point_rate 0 "override: how often to give those points"
set g_domination_point_capturetime 0.1 "how long it takes to capture a point (given no interference)"
set g_domination_point_glow 0 "domination point glow (warning, slow)"
+set g_domination_roundbased 0 "enable round-based domination (capture all control points to win the round)"
+set g_domination_roundbased_point_limit 5 "capture limit in round-based domination mode"
+set g_domination_round_timelimit 120
+set g_domination_warmup 5
//set g_domination_balance_team_points 1 "# of points received is based on team sizes"
set g_freezetag_revive_speed 0.4 "Speed for reviving a frozen teammate"
set g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets lost when out of range"
set g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a frozen teammate to keep reviving him"
+set g_freezetag_revive_nade 1 "Enable reviving from own nade explosion"
+set g_freezetag_revive_nade_health 40 "Amount of health player has if they revived from their own nade explosion"
set g_freezetag_revive_falldamage 0 "Enable reviving from this amount of fall damage"
set g_freezetag_revive_falldamage_health 40 "Amount of health player has if they revived from falling"
set g_freezetag_round_timelimit 180 "round time limit in seconds"
+set g_freezetag_frozen_damage_trigger 1 "if 1, frozen players falling into the void will die instead of teleporting to spawn"
set g_freezetag_frozen_force 0.6 "How much to multiply the force on a frozen player with"
set g_freezetag_frozen_maxtime 60 "frozen players will be automatically unfrozen after this time in seconds"
seta g_freezetag_teams_override 0
ALPHA_DISABLED 0.2
ALPHA_BEHIND 0.5
ALPHA_TEXT 0.7
+COLOR_TEXT '1 1 1'
// mouse
// uses "cursor" images
BORDER_TOOLTIP '16 16 0'
FONTSIZE_TOOLTIP 12
ALPHA_TOOLTIP 0.7
+COLOR_TOOLTIP '1 1 1'
WIDTH_TOOLTIP 0.3
AVOID_TOOLTIP '8 8 0'
ALPHA_SERVERLIST_HIGHPING 0.4
ALPHA_SERVERLIST_FAVORITE 0.8
COLOR_SERVERLIST_FAVORITE '1 1 1'
+ALPHA_SERVERLIST_CATEGORY 0.7
+COLOR_SERVERLIST_CATEGORY '1 1 1'
// item: skin list
COLOR_SKINLIST_TITLE '1 1 1'
// item: player color button
// uses "colorbutton" images
-// uses "color" images
// item: player name editor
// uses "charmap" images
ALPHA_DISABLED 0.2
ALPHA_BEHIND 0.5
ALPHA_TEXT 0.7
+COLOR_TEXT '1 1 1'
// mouse
// uses "cursor" images
BORDER_TOOLTIP '16 16 0'
FONTSIZE_TOOLTIP 12
ALPHA_TOOLTIP 0.7
+COLOR_TOOLTIP '1 1 1'
WIDTH_TOOLTIP 0.3
AVOID_TOOLTIP '8 8 0'
ALPHA_SERVERLIST_HIGHPING 0.4
ALPHA_SERVERLIST_FAVORITE 0.8
COLOR_SERVERLIST_FAVORITE '1 1 1'
+ALPHA_SERVERLIST_CATEGORY 0.7
+COLOR_SERVERLIST_CATEGORY '1 1 1'
// item: skin list
COLOR_SKINLIST_TITLE '1 1 1'
// item: player color button
// uses "colorbutton" images
-// uses "color" images
// item: player name editor
// uses "charmap" images
BORDER_TOOLTIP '1 1 0'
FONTSIZE_TOOLTIP 12
ALPHA_TOOLTIP 0.7
+COLOR_TOOLTIP '1 1 1'
WIDTH_TOOLTIP 0.3
AVOID_TOOLTIP '8 8 0'
ALPHA_DISABLED 0.2
ALPHA_BEHIND 1
ALPHA_TEXT 0.7
+COLOR_TEXT '1 1 1'
// item: button
// uses "button" images
// item: player color button
// uses "colorbutton" images
-// uses "color" images
// item: player model
COLOR_MODELTITLE '1 1 1'
ALPHA_SERVERLIST_HIGHPING 0.2
ALPHA_SERVERLIST_FAVORITE 0.8
COLOR_SERVERLIST_FAVORITE '1 1 1'
+ALPHA_SERVERLIST_CATEGORY 0.7
+COLOR_SERVERLIST_CATEGORY '1 1 1'
// item: server info
COLOR_SERVERINFO_NAME '1 1 1'
seta hud_panel_notify_fontsize "0.8"
seta hud_panel_notify_time "10"
seta hud_panel_notify_fadetime "3"
+seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer 1
seta hud_panel_timer_pos "0.800000 0.040000"
seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
seta hud_panel_centerprint_fade_minfontsize "0"
+seta hud_panel_buffs 1
+seta hud_panel_buffs_pos "0.450000 0.855000"
+seta hud_panel_buffs_size "0.050000 0.070000"
+seta hud_panel_buffs_bg "0"
+seta hud_panel_buffs_bg_color ""
+seta hud_panel_buffs_bg_color_team ""
+seta hud_panel_buffs_bg_alpha ""
+seta hud_panel_buffs_bg_border ""
+seta hud_panel_buffs_bg_padding ""
+
menu_sync
seta hud_panel_notify_fontsize "0.8"
seta hud_panel_notify_time "10"
seta hud_panel_notify_fadetime "3"
+seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer 1
seta hud_panel_timer_pos "0.435000 0"
seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
seta hud_panel_centerprint_fade_minfontsize "0"
+seta hud_panel_buffs 1
+seta hud_panel_buffs_pos "0.450000 0.855000"
+seta hud_panel_buffs_size "0.050000 0.070000"
+seta hud_panel_buffs_bg "0"
+seta hud_panel_buffs_bg_color ""
+seta hud_panel_buffs_bg_color_team ""
+seta hud_panel_buffs_bg_alpha ""
+seta hud_panel_buffs_bg_border ""
+seta hud_panel_buffs_bg_padding ""
+
menu_sync
seta hud_panel_notify_fontsize "0.8"
seta hud_panel_notify_time "10"
seta hud_panel_notify_fadetime "3"
+seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer 1
seta hud_panel_timer_pos "0.435000 0"
seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
seta hud_panel_centerprint_fade_minfontsize "0"
+seta hud_panel_buffs 1
+seta hud_panel_buffs_pos "0.450000 0.855000"
+seta hud_panel_buffs_size "0.050000 0.070000"
+seta hud_panel_buffs_bg "0"
+seta hud_panel_buffs_bg_color ""
+seta hud_panel_buffs_bg_color_team ""
+seta hud_panel_buffs_bg_alpha ""
+seta hud_panel_buffs_bg_border ""
+seta hud_panel_buffs_bg_padding ""
+
menu_sync
seta hud_panel_notify_fontsize "0.8"
seta hud_panel_notify_time "10"
seta hud_panel_notify_fadetime "3"
+seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer 1
seta hud_panel_timer_pos "0.870000 0"
seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
seta hud_panel_centerprint_fade_minfontsize "0"
+seta hud_panel_buffs 1
+seta hud_panel_buffs_pos "0.450000 0.855000"
+seta hud_panel_buffs_size "0.050000 0.070000"
+seta hud_panel_buffs_bg "0"
+seta hud_panel_buffs_bg_color ""
+seta hud_panel_buffs_bg_color_team ""
+seta hud_panel_buffs_bg_alpha ""
+seta hud_panel_buffs_bg_border ""
+seta hud_panel_buffs_bg_padding ""
+
menu_sync
seta hud_panel_notify_fontsize "1"
seta hud_panel_notify_time "10"
seta hud_panel_notify_fadetime "3"
+seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer 1
seta hud_panel_timer_pos "0.850000 0"
seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
seta hud_panel_centerprint_fade_minfontsize "0"
+seta hud_panel_buffs 1
+seta hud_panel_buffs_pos "0.450000 0.855000"
+seta hud_panel_buffs_size "0.050000 0.070000"
+seta hud_panel_buffs_bg "0"
+seta hud_panel_buffs_bg_color ""
+seta hud_panel_buffs_bg_color_team ""
+seta hud_panel_buffs_bg_alpha ""
+seta hud_panel_buffs_bg_border ""
+seta hud_panel_buffs_bg_padding ""
+
menu_sync
"dropweapon" "drop weapon"
"+use" "drop key / drop flag"
"+button8" "drag object"
+"toggle chase_active" "3rd person view"
"" ""
"" "User defined"
"+userbind 1" "$userbind1"
"messagemode2" "Nachricht ans Team"
"team_auto" "Team automatisch wählen"
"menu_showteamselect" "Team auswählen"
-"menu_showsandboxtools" "Sandbox-Menu"
+"menu_showsandboxtools" "Sandkasten menu"
"spec" "Zuschauen"
"dropweapon" "Waffe wegwerfen"
"+use" "Schlüssel oder Flagge wegwerfen"
"+button8" "Objekt ziehen"
+"toggle chase_active" "Schultercamera"
"" ""
"" "Benutzerdefiniert"
"+userbind 1" "$userbind1"
"dropweapon" "soltar arma"
"+use" "soltar llave / soltar bandera"
"+button8" "drag object (FIXME)"
+"toggle chase_active" "3rd person view (FIXME)"
"" ""
"" "Definido por el usuario"
"+userbind 1" "$userbind1"
"weaplast" "dernière utilisée"
"weapbest" "meilleure arme"
"reload" "recharger"
-"weapon_group_1" "laser"
-"weapon_group_2" "shotgun"
-"weapon_group_3" "machine gun / rifle"
-"weapon_group_4" "mortar"
-"weapon_group_5" "electro"
-"weapon_group_6" "crylink / hlac"
-"weapon_group_7" "nex / minstanex"
-"weapon_group_8" "hagar"
-"weapon_group_9" "rocket launcher / fireball"
-"weapon_group_0" "porto / hook"
+"weapon_group_1" "Laser"
+"weapon_group_2" "Fusil"
+"weapon_group_3" "Mitrailleuse"
+"weapon_group_4" "Mortier / Poseur de Mines"
+"weapon_group_5" "Electro"
+"weapon_group_6" "Crylink / HLAC"
+"weapon_group_7" "Nex / Fusil de précision"
+"weapon_group_8" "Hagar / Seeker"
+"weapon_group_9" "Lance-roquettes / Fireball"
+"weapon_group_0" "Port-O-Launch / Grappin"
"" ""
"" "Vue"
-"+zoom" "zoom clic enfoncé"
+"+zoom" "zoom"
"togglezoom" "zoom 2 clics"
-"+showscores" "montrer les scores (enfoncé)"
+"+showscores" "afficher les scores"
"screenshot" "capture d'écran"
-"+hud_panel_radar_maximized" "maximize radar (FIXME)"
+"+hud_panel_radar_maximized" "agrandir le radar"
"" ""
-"" "Communiquer"
-"messagemode" "chat public"
-"messagemode2" "chat d'équipe"
-"+con_chat_maximize" "historique du chat (enfoncé)"
+"" "Communication"
+"messagemode" "tchat public"
+"messagemode2" "tchat d'équipe"
+"+con_chat_maximize" "historique du tchat"
"vyes" "voter OUI"
"vno" "voter NON"
-"ready" "prêt (en mode échauffement)"
+"ready" "prêt"
"" ""
-"" "Joueur"
+"" "Client"
"+show_info" "information serveur"
"toggleconsole" "ouvrir la console"
"disconnect" "se déconnecter"
"menu_showquitdialog" "quitter"
"" ""
"" "Équipe"
-"messagemode2" "chat d'équipe"
+"messagemode2" "tchat d'équipe"
"team_auto" "auto-joindre une équipe"
-"menu_showteamselect" "séléction d'équipe"
-"menu_showsandboxtools" "sandbox menu (FIXME)"
+"menu_showteamselect" "sélection d'équipe"
+"menu_showsandboxtools" "menu bac à sable"
"spec" "mode spectateur"
"dropweapon" "lâcher l'arme"
-"+use" "lâcher la clé / lâcher le drapeau"
-"+button8" "drag object (FIXME)"
+"+use" "lâcher la clef / drapeau"
+"+button8" "traîner l'objet"
+"toggle chase_active" "vue à la 3ème personne"
"" ""
-"" "Utilisateur"
+"" "Raccourcis personnalisés"
"+userbind 1" "$userbind1"
"+userbind 2" "$userbind2"
"+userbind 3" "$userbind3"
"dropweapon" "fegyver eldobás"
"+use" "zászló eldobás, kiszállás"
"+button8" "drag object"
+"toggle chase_active" "3rd person view (FIXME)"
"" ""
"" "Felhasználói hozzárendelések"
"+userbind 1" "$userbind1"
"dropweapon" "abbandona arma"
"+use" "abbandona chiave / bandiera"
"+button8" "trascina oggetto"
+"toggle chase_active" "3rd person view (FIXME)"
"" ""
"" "Definiti dall'utente"
"+userbind 1" "$userbind1"
"dropweapon" "бросить оружие"
"+use" "бросить ключ или флаг"
"+button8" "drag object"
+"toggle chase_active" "3rd person view (FIXME)"
"" ""
"" "Определенно пользователем"
"+userbind 1" "$userbind1"
"dropweapon" "викинути зброю"
"+use" "викинути ключ / прапор"
"+button8" "drag object"
+"toggle chase_active" "3rd person view (FIXME)"
"" ""
"" "Визначені користувачем"
"+userbind 1" "$userbind1"
sex Male
weight 105
age 26
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim3 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Male
weight 85
age 16
+description Lightweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Lightweight Xonotic Solider
sex Male
weight 90
age 20
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Male
weight 87
age 18
+description Mediumweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Mediumweight Xonotic Solider
sex Male
weight 88
age 31
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim3 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Male
weight 90
age 31
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim3 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Male
weight 92
age 31
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim3 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Male
weight 210
age 26
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim3 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Female
weight 100
age 24
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Soldier
sex Female
weight 57
age 53
+description Necro Warrior
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Necro Warrior
sex Female
weight 89
age 31
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Female
weight 90
age 31
+description Heavyweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Heavyweight Xonotic Solider
sex Female
weight 61
age 25
+description Lightweight Xonotic Soldier
bone_upperbody spine2
bone_aim0 0.25 spine2
bone_aim1 0.4 spine4
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
-
-Lightweight Xonotic Solider
// =======
-// nades
+// Nades
// =======
set g_nades 0 "enable off-hand grenades"
set g_nades_spawn 1 "give nades right away when player spawns rather than delaying entire refire"
+set g_nades_client_select 0 "allow client side selection of nade type"
set g_nades_nade_lifetime 3.5
set g_nades_nade_minforce 400
set g_nades_nade_maxforce 2000
set g_nades_nade_radius 300
set g_nades_nade_force 650
set g_nades_nade_newton_style 0
+set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
+
+seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
+seta cl_nade_type 3
+seta cl_pokenade_type "zombie"
+
+// ------------
+// Nade bonus
+// ------------
+//
+// How the nade bonus system works:
+// Each player has a score counter that is increased by some actions (eg: capping, fragging...)
+// Once this counter reaches its maximum, the player will receive a bonus grenade and the score counter resets
+// If the player dies all the bonus nades will be lost and the score counter resets
+// If g_nades_bonus_score_time is not zero, this score will increase or decrease over time
+//
+set g_nades_bonus 0 "Enable bonus grenades"
+set g_nades_bonus_client_select 0 "Allow client side selection of bonus nade type"
+set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
+set g_nades_bonus_onstrength 1 "Always give bonus grenades to players that have the strength powerup"
+set g_nades_bonus_max 3 "Maximum number of bonus grenades"
+// Bonus score
+set g_nades_bonus_score_max 120 "Score value that will give a bonus nade"
+set g_nades_bonus_score_minor 5 "Score given for minor actions (pickups, regular frags etc.)"
+set g_nades_bonus_score_low 20 "Score given for frags and unfreezes"
+set g_nades_bonus_score_medium 30 "Score given for flag returns and flag carrier kills"
+set g_nades_bonus_score_high 60 "Score given for flag captures"
+set g_nades_bonus_score_spree 40 "Score given every spree of this many frags"
+set g_nades_bonus_score_time -1 "Bonus nade score given per second (negative to have the score decay)"
+set g_nades_bonus_score_time_flagcarrier 2 "Bonus nade score given per second as flag carrier (negative to have the score decay)"
+
+// Napalm (2)
+set g_nades_napalm_blast 1 "Whether the napalm grenades also give damage with the usual grenade explosion"
+set g_nades_napalm_burntime 0.5 "Time that the fire from napalm will stick to the player"
+set g_nades_napalm_selfdamage 1 "Whether the player that tossed the nade can be harmed by its fire"
+// Napalm fireballs
+set g_nades_napalm_ball_count 6 "Number of fireballs emitted during the explosion"
+set g_nades_napalm_ball_spread 500 "Maximum force which the fireballs will have on explosion"
+set g_nades_napalm_ball_damageforcescale 4
+set g_nades_napalm_ball_damage 40
+set g_nades_napalm_ball_lifetime 7
+set g_nades_napalm_ball_radius 100 "Distance from the fireball within which you may get burned"
+// Napalm Fire fountain
+set g_nades_napalm_fountain_lifetime 3 "Time period during which extra fire mines are ejected"
+set g_nades_napalm_fountain_delay 0.5 "Delay between emissions by the fountain"
+set g_nades_napalm_fountain_damage 50 "Damage caused by the center of the fountain"
+set g_nades_napalm_fountain_edgedamage 20 "Damage caused by the edge of the fountain"
+set g_nades_napalm_fountain_radius 130
+
+// Ice (3)
+set g_nades_ice_freeze_time 3 "How long the ice field will last"
+set g_nades_ice_health 0 "How much health the player will have after being unfrozen"
+set g_nades_ice_explode 0 "Whether the ice nade should explode again once the ice field dissipated"
+set g_nades_ice_teamcheck 0 "Don't freeze teammates"
+
+// Spawn (5)
+set g_nades_spawn_count 3 "Number of times player will spawn at their spawn nade explosion location"
+
+// Heal (6)
+set g_nades_heal_time 5 "How long the heling field will last"
+set g_nades_heal_rate 30 "Health given per second"
+set g_nades_heal_friend 1 "Multiplier of health given to team mates"
+set g_nades_heal_foe -2 "Multiplier of health given to enemies"
+
+// Pokenade (7)
+set g_nades_pokenade_monster_lifetime 150 "How long pokenade monster will survive"
+set g_nades_pokenade_monster_type "zombie" "Monster to spawn"
// ============
set g_campcheck_damage 100
set g_campcheck_distance 1800
+
+// =======
+// buffs
+// =======
+set cl_buffs_autoreplace 1 "automatically drop current buff when picking up another"
+set g_buffs 0 "enable buffs (requires buff items or powerups)"
+set g_buffs_waypoint_distance 1024 "maximum distance at which buff waypoint can be seen from item"
+set g_buffs_randomize 1 "randomize buff type when player drops buff"
+set g_buffs_random_lifetime 30 "re-spawn the buff again if it hasn't been touched after this time in seconds"
+set g_buffs_random_location 0 "randomize buff location on start and when reset"
+set g_buffs_random_location_attempts 10 "number of random locations a single buff will attempt to respawn at before giving up"
+set g_buffs_spawn_count 5 "how many buffs to spawn on the map if none exist already"
+set g_buffs_replace_powerups 1 "replace powerups on the map with random buffs"
+set g_buffs_cooldown_activate 5 "cooldown period when buff is first activated"
+set g_buffs_cooldown_respawn 3 "cooldown period when buff is reloading"
+set g_buffs_ammo 1 "ammo buff: infinite ammunition"
+set g_buffs_resistance 1 "resistance buff: greatly reduces damage taken"
+set g_buffs_resistance_blockpercent 0.7 "damage reduction multiplier, higher values mean less damage"
+set g_buffs_medic 1 "medic buff: increased regeneration speed, extra health, chance to survive a fatal attack"
+set g_buffs_medic_survive_chance 0.6 "multiplier chance of player surviving a fatal hit"
+set g_buffs_medic_survive_health 5 "amount of health player survives with after taking a fatal hit"
+set g_buffs_medic_rot 0.7 "health rot rate multiplier"
+set g_buffs_medic_max 1.5 "stable health medic limit multiplier"
+set g_buffs_medic_regen 1.7 "health medic rate multiplier"
+set g_buffs_vengeance 1 "vengeance buff: attackers also take damage"
+set g_buffs_vengeance_damage_multiplier 0.6 "amount of damage dealt the attacker takes when hitting a target with vengeance"
+set g_buffs_bash 1 "bash buff: increased knockback force and immunity to knockback"
+set g_buffs_bash_force 2 "bash force multiplier"
+set g_buffs_bash_force_self 1.2 "bash self force multiplier"
+set g_buffs_disability 1 "disability buff: attacks to players and monsters deal slowness (decreased movement/attack speed) for a few seconds"
+set g_buffs_disability_time 3 "time in seconds for target disability"
+set g_buffs_disability_speed 0.5 "player speed multiplier while disabled"
+set g_buffs_disability_rate 1.7 "player weapon rate multiplier while disabled"
+set g_buffs_speed 1 "speed buff: increased movement/attack/health regeneration speed, carrier takes slightly more damage"
+set g_buffs_speed_speed 1.7 "player speed multiplier while holding speed buff"
+set g_buffs_speed_rate 0.8 "player weapon rate multiplier while holding speed buff"
+set g_buffs_speed_damage_take 1.2 "damage taken multiplier while holding speed buff"
+set g_buffs_speed_regen 1.2 "regeneration speed multiplier while holding speed buff"
+set g_buffs_vampire 1 "vampire buff: attacks to players and monsters heal the carrier"
+set g_buffs_vampire_damage_steal 0.6 "damage stolen multiplier while holding vampire buff"
+set g_buffs_jump 1 "jump buff: greatly increased jump height"
+set g_buffs_jump_height 600 "jump height while holding jump buff"
+set g_buffs_flight 1 "flight buff: greatly decreased gravity"
+set g_buffs_flight_gravity 0.3 "player gravity multiplier while holding flight buff"
+set g_buffs_invisible 1 "invisible buff: carrier becomes invisible"
+set g_buffs_invisible_alpha 0.4 "player invisibility multiplier while holding invisible buff"
+
QCCFLAGS_WATERMARK ?= -DWATERMARK='"$(shell git describe)"'
QCC ?= gmqcc
-QCCVERSIONFILE := qccversion.$(shell $(QCC) --version > qccversion.txt && git hash-object qccversion.txt)
+QCCVERSIONFILE := qccversion.$(shell (cd server && $(QCC) --version) > qccversion.txt && git hash-object qccversion.txt)
# We eventually need to get rid of these.
QCCFLAGS_WTFS ?= \
registercvar("hud_usecsqc", "1");
registercvar("scoreboard_columns", "default");
+ registercvar("cl_nade_type", "3");
+ registercvar("cl_pokenade_type", "zombie");
+
gametype = 0;
// hud_fields uses strunzone on the titles!
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels);
+ CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
WaypointSprite_Load();
case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(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;
default:
//error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
//else
{
- if(gametype == MAPINFO_TYPE_FREEZETAG)
+ if(getstati(STAT_FROZEN))
+ drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+ else if (getstatf(STAT_HEALING_ORB)>time)
+ drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, Nade_Color(NADE_TYPE_HEAL), autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
+ if(!intermission)
+ if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
{
- if(getstati(STAT_FROZEN))
- drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
- if(getstatf(STAT_REVIVE_PROGRESS))
- {
- DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
- drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
- }
+ DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * getstatf(STAT_NADE_TIMER)) - ('0 1 1' * getstatf(STAT_NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+ drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
+ }
+ else if(getstatf(STAT_REVIVE_PROGRESS))
+ {
+ DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+ drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
}
if(autocvar_r_letterbox == 0)
float autocvar_hud_panel_notify_flip;
float autocvar_hud_panel_notify_fontsize;
float autocvar_hud_panel_notify_time;
+float autocvar_hud_panel_notify_icon_aspect;
float autocvar_hud_panel_physics;
float autocvar_hud_panel_physics_acceleration_progressbar_mode;
float autocvar_hud_panel_physics_acceleration_progressbar_scale;
float autocvar_hud_panel_powerups_flip;
float autocvar_hud_panel_powerups_iconalign;
float autocvar_hud_panel_powerups_progressbar;
+float autocvar_hud_panel_buffs;
+//float autocvar_hud_panel_buffs_iconalign;
string autocvar_hud_panel_powerups_progressbar_shield;
string autocvar_hud_panel_powerups_progressbar_strength;
string autocvar_hud_panel_powerups_progressbar_superweapons;
float autocvar_cl_deathglow;
float autocvar_developer_csqcentities;
float autocvar_g_jetpack_attenuation;
+float autocvar_cl_nade_timer;
const float VF_CL_VIEWANGLES_Y = 35; //(float)
const float VF_CL_VIEWANGLES_Z = 36; //(float)
-// Server Autosent Stat Constants
-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;
-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;
-
// Quake-style Point Contents
const float CONTENT_EMPTY = -1;
const float CONTENT_SOLID = -2;
}
}
+void DrawNadeScoreBar(vector myPos, vector mySize, vector color)
+{
+
+ HUD_Panel_DrawProgressBar(
+ myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x,
+ mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x,
+ autocvar_hud_panel_ammo_progressbar_name,
+ getstatf(STAT_NADE_BONUS_SCORE), 0, 0, color,
+ autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+
+}
+
+void DrawAmmoNades(vector myPos, vector mySize, float draw_expanding, float expand_time)
+{
+ float theAlpha = 1, a, b;
+ vector nade_color, picpos, numpos;
+
+ nade_color = Nade_Color(getstati(STAT_NADE_BONUS_TYPE));
+
+ a = getstatf(STAT_NADE_BONUS);
+ b = getstatf(STAT_NADE_BONUS_SCORE);
+
+ if(autocvar_hud_panel_ammo_iconalign)
+ {
+ numpos = myPos;
+ picpos = myPos + eX * 2 * mySize_y;
+ }
+ else
+ {
+ numpos = myPos + eX * mySize_y;
+ picpos = myPos;
+ }
+
+ DrawNadeScoreBar(myPos, mySize, nade_color);
+
+ if(b > 0 || a > 0)
+ {
+ if(autocvar_hud_panel_ammo_text)
+ drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+
+ if(draw_expanding)
+ drawpic_aspect_skin_expanding(picpos, "nade_nbg", '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, expand_time);
+
+ drawpic_aspect_skin(picpos, "nade_bg" , '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+ drawpic_aspect_skin(picpos, "nade_nbg" , '1 1 0' * mySize_y, nade_color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+ }
+}
+
void DrawAmmoItem(vector myPos, vector mySize, float itemcode, float currently_selected, float infinite_ammo)
{
float a;
drawpic_aspect_skin(picpos, GetAmmoPicture(itemcode), '1 1 0' * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
}
+float nade_prevstatus;
+float nade_prevframe;
+float nade_statuschange_time;
void HUD_Ammo(void)
{
if(hud != HUD_NORMAL) return;
mySize -= '2 2 0' * panel_bg_padding;
}
- const float AMMO_COUNT = 4;
float 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;
+
vector ammo_size;
+ float AMMO_COUNT = 4;
if (autocvar_hud_panel_ammo_onlycurrent)
- ammo_size = mySize;
+ total_ammo_count = 1;
else
+ total_ammo_count = AMMO_COUNT - 1; // fuel
+
+ if(draw_nades)
{
- rows = mySize_y/mySize_x;
- rows = bound(1, floor((sqrt(4 * (3/1) * rows * AMMO_COUNT + rows * rows) + rows + 0.5) / 2), AMMO_COUNT);
- // ^^^ ammo item aspect goes here
+ ++total_ammo_count;
+ if (nade_cnt != nade_prevframe)
+ {
+ nade_statuschange_time = time;
+ nade_prevstatus = nade_prevframe;
+ nade_prevframe = nade_cnt;
+ }
+ }
+ else
+ nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
+
+ rows = mySize_y/mySize_x;
+ rows = bound(1, floor((sqrt(4 * (3/1) * rows * (total_ammo_count) + rows * rows) + rows + 0.5) / 2), (total_ammo_count));
+ // ^^^ ammo item aspect goes here
- columns = ceil(AMMO_COUNT/rows);
+ columns = ceil((total_ammo_count)/rows);
- ammo_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
- }
+ ammo_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+
local vector offset = '0 0 0'; // fteqcc sucks
float newSize;
float i, stat_items, currently_selected, infinite_ammo;
infinite_ammo = FALSE;
+
+ row = column = 0;
+
if (autocvar_hud_panel_ammo_onlycurrent)
{
if(autocvar__hud_configure)
}
}
}
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ column = column + 1;
+ }
}
else
{
stat_items = getstati(STAT_ITEMS, 0, 24);
if (stat_items & IT_UNLIMITED_WEAPON_AMMO)
infinite_ammo = TRUE;
- row = column = 0;
for (i = 0; i < AMMO_COUNT; ++i) {
currently_selected = stat_items & GetAmmoItemCode(i);
DrawAmmoItem(pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y), ammo_size, i, currently_selected, infinite_ammo);
}
}
+ if (draw_nades)
+ {
+ nade_statuschange_elapsedtime = time - nade_statuschange_time;
+
+ float f = bound(0, nade_statuschange_elapsedtime*2, 1);
+
+ DrawAmmoNades(pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
+ }
+
draw_endBoldFont();
}
void HUD_Notify_Push(string icon, string attacker, string victim)
{
- if(icon != "")
- {
- --kn_index;
- if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
- notify_times[kn_index] = time;
+ if (icon == "")
+ return;
- // icon
- if(notify_icon[kn_index]) { strunzone(notify_icon[kn_index]); }
- notify_icon[kn_index] = strzone(icon);
+ ++notify_count;
+ --notify_index;
- // attacker
- if(notify_attackers[kn_index]) { strunzone(notify_attackers[kn_index]); }
- notify_attackers[kn_index] = strzone(attacker);
+ if (notify_index == -1)
+ notify_index = NOTIFY_MAX_ENTRIES-1;
- // victim
- if(notify_victims[kn_index]) { strunzone(notify_victims[kn_index]); }
- notify_victims[kn_index] = strzone(victim);
+ // Free old strings
+ if (notify_attackers[notify_index])
+ strunzone(notify_attackers[notify_index]);
+
+ if (notify_victims[notify_index])
+ strunzone(notify_victims[notify_index]);
+
+ if (notify_icons[notify_index])
+ strunzone(notify_icons[notify_index]);
+
+ // Allocate new strings
+ if (victim != "")
+ {
+ notify_attackers[notify_index] = strzone(attacker);
+ notify_victims[notify_index] = strzone(victim);
}
+ else
+ {
+ // In case of a notification without a victim, the attacker
+ // is displayed on the victim's side. Instead of special
+ // treatment later on, we can simply switch them here.
+ notify_attackers[notify_index] = string_null;
+ notify_victims[notify_index] = strzone(attacker);
+ }
+
+ notify_icons[notify_index] = strzone(icon);
+ notify_times[notify_index] = time;
}
void HUD_Notify(void)
{
- if(!autocvar__hud_configure)
- {
- if(!autocvar_hud_panel_notify) return;
- }
+ if (!autocvar__hud_configure)
+ if (!autocvar_hud_panel_notify)
+ return;
HUD_Panel_UpdateCvars();
- vector pos, mySize;
- pos = panel_pos;
- mySize = panel_size;
-
HUD_Panel_DrawBg(1);
- if(panel_bg_padding)
+
+ if (!autocvar__hud_configure)
+ if (notify_count == 0)
+ return;
+
+ vector pos, size;
+ pos = panel_pos;
+ size = panel_size;
+
+ if (panel_bg_padding)
{
- pos += '1 1 0' * panel_bg_padding;
- mySize -= '2 2 0' * panel_bg_padding;
+ pos += '1 1 0' * panel_bg_padding;
+ size -= '2 2 0' * panel_bg_padding;
}
- float entries, height;
- entries = bound(1, floor(KN_MAX_ENTRIES * mySize_y/mySize_x), KN_MAX_ENTRIES);
- height = mySize_y/entries;
+ float fade_start = max(0, autocvar_hud_panel_notify_time);
+ float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
+ float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
- vector fontsize;
- float fontheight = height * autocvar_hud_panel_notify_fontsize;
- fontsize = '0.5 0.5 0' * fontheight;
+ float entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size_y / size_x), NOTIFY_MAX_ENTRIES);
+ float entry_height = size_y / entry_count;
- float a;
- float when;
- when = autocvar_hud_panel_notify_time;
- float fadetime;
- fadetime = autocvar_hud_panel_notify_fadetime;
+ float panel_width_half = size_x * 0.5;
+ float icon_width_half = entry_height * icon_aspect / 2;
+ float name_maxwidth = panel_width_half - icon_width_half - size_x * NOTIFY_ICON_MARGIN;
- vector pos_attacker, pos_victim, pos_icon;
- float width_attacker;
+ vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
+ vector icon_size = (eX * icon_aspect + eY) * entry_height;
+ vector icon_left = eX * (panel_width_half - icon_width_half);
+ vector attacker_right = eX * name_maxwidth;
+ vector victim_left = eX * (size_x - name_maxwidth);
+
+ vector attacker_pos, victim_pos, icon_pos;
string attacker, victim, icon;
+ float i, j, count, step, limit, alpha;
- float i, j, step, limit;
- if(autocvar_hud_panel_notify_flip) //order items from the top down
+ if (autocvar_hud_panel_notify_flip)
{
+ // Order items from the top down
i = 0;
step = +1;
- limit = entries;
+ limit = entry_count;
}
- else //order items from the bottom up
+ else
{
- i = entries - 1;
+ // Order items from the bottom up
+ i = entry_count - 1;
step = -1;
limit = -1;
}
- for(j = kn_index; i != limit; i += step, ++j)
+ for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
{
if(autocvar__hud_configure)
{
- if (step == +1)
- a = i;
- else // inverse order
- a = entries - 1 - i;
- attacker = textShortenToWidth(sprintf(_("Player %d"), a+1), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
- victim = textShortenToWidth(sprintf(_("Player %d"), a+2), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
- icon = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname);
- a = bound(0, (when - a) / 4, 1);
- goto hud_config_notifyprint;
+ attacker = sprintf(_("Player %d"), count + 1);
+ victim = sprintf(_("Player %d"), count + 2);
+ icon = strcat("weapon", get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).netname);
+ alpha = bound(0, 1.2 - count / entry_count, 1);
}
else
{
- if (j == KN_MAX_ENTRIES)
+ if (j == NOTIFY_MAX_ENTRIES)
j = 0;
- if(notify_times[j] + when > time)
- a = 1;
- else if(fadetime)
+ if (notify_times[j] + fade_start > time)
+ alpha = 1;
+ else if (fade_time != 0)
{
- a = bound(0, (notify_times[j] + when + fadetime - time) / fadetime, 1);
- if(!a)
- {
+ alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
+ if (alpha == 0)
break;
- }
}
else
- {
break;
- }
attacker = notify_attackers[j];
victim = notify_victims[j];
- icon = notify_icon[j];
+ icon = notify_icons[j];
}
- //type = notify_deathtype[j];
- //w = DEATH_WEAPONOF(type);
-
- if(icon != "")
+ if (icon != "" && victim != "")
{
- if((attacker != "") && (victim == ""))
- {
- // Y [used by] X
- attacker = textShortenToWidth(attacker, 0.73 * mySize_x - height, fontsize, stringwidth_colors);
- pos_attacker = pos + eX * (0.27 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
- pos_icon = pos + eX * 0.25 * mySize_x - eX * height + eY * i * height;
+ vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size_y));
- drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- }
- else if((attacker != "") && (victim != ""))
+ icon_pos = pos + icon_left + eY * i * entry_height;
+ drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+ victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
+ victim_pos = pos + victim_left + name_top;
+ drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+ if (attacker != "")
{
- // X [did action to] Y
- attacker = textShortenToWidth(attacker, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
- victim = textShortenToWidth(victim, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-:hud_config_notifyprint
- width_attacker = stringwidth(attacker, TRUE, fontsize);
- pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
- pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
- pos_icon = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
-
- drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
- drawcolorcodedstring(pos_victim, victim, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+ attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
+ attacker_pos = pos + attacker_right - eX * stringwidth(attacker, TRUE, font_size) + name_top;
+ drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
}
}
}
+
+ notify_count = count;
}
// Timer (#5)
}
}
+// Buffs (#18)
+//
+void HUD_Buffs(void)
+{
+ float buffs = getstati(STAT_BUFFS, 0, 24);
+ if(!autocvar__hud_configure)
+ {
+ if(!autocvar_hud_panel_buffs) return;
+ if(spectatee_status == -1) return;
+ if(getstati(STAT_HEALTH) <= 0) return;
+ if(!buffs) return;
+ }
+ else
+ {
+ buffs = Buff_Type_first.items; // force first buff
+ }
+
+ float 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)
+ {
+ ++b;
+ string o = strcat(rgb_to_hexcolor(Buff_Color(e.items)), Buff_PrettyName(e.items));
+ if(s == "")
+ s = o;
+ else
+ s = strcat(s, " ", o);
+ }
+
+ HUD_Panel_UpdateCvars();
+
+ draw_beginBoldFont();
+
+ vector pos, mySize;
+ pos = panel_pos;
+ mySize = panel_size;
+
+ HUD_Panel_DrawBg(bound(0, b, 1));
+ if(panel_bg_padding)
+ {
+ pos += '1 1 0' * panel_bg_padding;
+ mySize -= '2 2 0' * panel_bg_padding;
+ }
+
+ //float panel_ar = mySize_x/mySize_y;
+ //float is_vertical = (panel_ar < 1);
+ //float buff_iconalign = autocvar_hud_panel_buffs_iconalign;
+ vector buff_offset = '0 0 0';
+
+ for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
+ {
+ //DrawNumIcon(pos + buff_offset, mySize, shield, "shield", is_vertical, buff_iconalign, '1 1 1', 1);
+ drawcolorcodedstring_aspect(pos + buff_offset, s, mySize, panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+ }
+
+ draw_endBoldFont();
+}
+
+
/*
==================
Main HUD system
HUD_PANEL(ENGINEINFO , HUD_EngineInfo , engineinfo) \
HUD_PANEL(INFOMESSAGES , HUD_InfoMessages , infomessages) \
HUD_PANEL(PHYSICS , HUD_Physics , physics) \
- HUD_PANEL(CENTERPRINT , HUD_CenterPrint , centerprint)
+ HUD_PANEL(CENTERPRINT , HUD_CenterPrint , centerprint) \
+ HUD_PANEL(BUFFS , HUD_Buffs , buffs)
#define HUD_PANEL(NAME,draw_func,name) \
float HUD_PANEL_##NAME; \
HUD_Panel_GetBorder() \
} ENDS_WITH_CURLY_BRACE
+#define NOTIFY_MAX_ENTRIES 10
+#define NOTIFY_ICON_MARGIN 0.02
-#define KN_MAX_ENTRIES 10
+float notify_index;
+float notify_count;
+float notify_times[NOTIFY_MAX_ENTRIES];
+string notify_attackers[NOTIFY_MAX_ENTRIES];
+string notify_victims[NOTIFY_MAX_ENTRIES];
+string notify_icons[NOTIFY_MAX_ENTRIES];
-float kn_index;
-float notify_times[KN_MAX_ENTRIES];
-string notify_icon[KN_MAX_ENTRIES];
-string notify_attackers[KN_MAX_ENTRIES];
-string notify_victims[KN_MAX_ENTRIES];
void HUD_Notify_Push(string icon, string attacker, string victim);
var void HUD_ModIcons_GameType(vector pos, vector size);
HUD_Write_PanelCvar_q("_fontsize");
HUD_Write_PanelCvar_q("_time");
HUD_Write_PanelCvar_q("_fadetime");
+ HUD_Write_PanelCvar_q("_icon_aspect");
break;
case HUD_PANEL_TIMER:
HUD_Write_PanelCvar_q("_increment");
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_maps_mask;
float mv_top2_time;
float mv_top2_alpha;
vector mv_mousepos;
float mv_selection;
+float mv_columns;
+float mv_mouse_selection;
+float mv_selection_keyboard;
+
+float gametypevote;
+string mapvote_chosenmap;
+vector gtv_text_size;
+vector gtv_text_size_small;
string MapVote_FormatMapItem(float id, string map, float count, float maxwidth, vector fontsize)
{
{
if(count == 1)
post = _(" (1 vote)");
- else if(count >= 0)
+ else if(count >= 0 && mv_avail[id] == GTV_AVAILABLE)
post = sprintf(_(" (%d votes)"), count);
else
post = "";
return strcat(pre, map, post);
}
-vector MapVote_RGB(float id, float count)
+string GameTypeVote_DescriptionByID(float id)
+{
+ return MapInfo_Type_Description(MapInfo_Type_FromString(mv_maps[id]));
+}
+
+vector MapVote_RGB(float id)
{
- if(count < 0)
+ if(mv_avail[id] != GTV_AVAILABLE)
return '1 1 1';
if(id == mv_ownvote)
return '0 1 0';
return '1 1 1';
}
+void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string gtype, string pic, float count, float id)
+{
+ float alpha;
+ float desc_padding = gtv_text_size_x * 3;
+ 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)
+ {
+ drawfill(rect_pos, rect_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
+ }
+ 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;
+
+ maxh -= gtv_text_size_y;
+
+ entity picent = spawn();
+ picent.origin = pos-offset;
+ picent.maxs = '1 1 0 ' * min(maxh, desc_padding) * 0.8;
+
+ pos_x += desc_padding;
+ tsize -= desc_padding;
+
+ string thelabel = GameTypeVote_DescriptionByID(id), ts;
+ entity last = title;
+ entity next = world;
+ if( thelabel != "")
+ {
+ float i,n = tokenizebyseparator(thelabel, "\n");
+ for(i = 0; i < n && maxh > (nlines+1)*gtv_text_size_small_y; ++i)
+ {
+ getWrappedLine_remaining = argv(i);
+ while(getWrappedLine_remaining && maxh > (nlines+1)*gtv_text_size_small_y)
+ {
+ ts = getWrappedLine(tsize, gtv_text_size_small, stringwidth_colors);
+ if (ts != "")
+ {
+ next = spawn();
+ next.message = ts;
+ next.origin = pos-offset;
+ last.chain = next;
+ last = next;
+ pos_y += gtv_text_size_small_y;
+ nlines++;
+ }
+ }
+ }
+ }
+
+ maxh -= max(nlines*gtv_text_size_small_y,picent.maxs_y);
+ if ( maxh > 0 )
+ offset_y += maxh/2;
+ drawstring(title.origin+offset, title.message, gtv_text_size, rgb, alpha, DRAWFLAG_NORMAL);
+
+ if(pic != "")
+ drawpic(picent.origin+offset, pic, picent.maxs, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ for ( last = title.chain; last ; )
+ {
+ drawstring(last.origin+offset, last.message, gtv_text_size_small, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ next = last;
+ last = last.chain;
+ remove(next);
+ }
+
+ remove(picent);
+ remove(title);
+}
+
void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float count, float id)
{
vector img_size = '0 0 0';
isize -= hud_fontsize_y; // respect the text when calculating the image size
- rgb = MapVote_RGB(id, count);
+ rgb = MapVote_RGB(id);
img_size_y = isize;
img_size_x = isize / 0.75; // 4:3 x can be stretched easily, height is defined in isize
text_size = stringwidth(label, false, hud_fontsize);
float theAlpha;
- if (count < 0 && mv_top2_alpha)
+ if (mv_avail[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 && count >= 0)
+ if(id == mv_selection && mv_avail[id] == GTV_AVAILABLE)
drawfill(pos, img_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
}
float text_size;
string label;
- rgb = MapVote_RGB(id, count);
+ rgb = MapVote_RGB(id);
pos_y = pos_y + hud_fontsize_y;
float MapVote_Selection(vector topleft, vector cellsize, float rows, float columns)
{
- float cell;
+
float c, r;
- cell = -1;
+ mv_mouse_selection = -1;
for (r = 0; r < rows; ++r)
for (c = 0; c < columns; ++c)
mv_mousepos_y >= topleft_y + cellsize_y * r &&
mv_mousepos_y <= topleft_y + cellsize_y * (r + 1))
{
- cell = r * columns + c;
+ mv_mouse_selection = r * columns + c;
break;
}
}
- if (cell >= mv_num_maps)
- cell = -1;
+ if (mv_mouse_selection >= mv_num_maps)
+ mv_mouse_selection = -1;
- if (mv_abstain && cell < 0)
- return mv_num_maps;
+ if (mv_abstain && mv_mouse_selection < 0)
+ mv_mouse_selection = mv_num_maps;
- return cell;
+ if ( mv_selection_keyboard )
+ return mv_selection;
+
+ return mv_mouse_selection;
}
void MapVote_Draw()
vector pos;
float isize;
float center;
- float columns, rows;
+ float rows;
float tsize;
vector dist = '0 0 0';
if (!autocvar_hud_cursormode)
{
- mv_mousepos = mv_mousepos + getmousepos();
+ vector mpos = mv_mousepos + getmousepos();
+ mpos_x = bound(0, mpos_x, vid_conwidth);
+ mpos_y = bound(0, mpos_y, vid_conheight);
+
+ if ( mpos_x != mv_mousepos_x || mpos_y != mv_mousepos_y )
+ mv_selection_keyboard = 0;
+ mv_mousepos = mpos;
- mv_mousepos_x = bound(0, mv_mousepos_x, vid_conwidth);
- mv_mousepos_y = bound(0, mv_mousepos_y, vid_conheight);
}
center = (vid_conwidth - 1)/2;
pos_z = 0;
draw_beginBoldFont();
- map = _("Vote for a map");
+ map = ((gametypevote) ? _("Decide the gametype") : _("Vote for a map"));
pos_x = center - stringwidth(map, false, '12 0 0');
drawstring(pos, map, '24 24 0', '1 1 1', 1, DRAWFLAG_NORMAL);
pos_y += 26;
+ if( mapvote_chosenmap != "" )
+ {
+ pos_x = center - stringwidth(mapvote_chosenmap, false, hud_fontsize*1.5/2);
+ drawstring(pos, mapvote_chosenmap, hud_fontsize*1.5, '1 1 1', 1, DRAWFLAG_NORMAL);
+ pos_y += hud_fontsize_y*2;
+ }
+
i = ceil(max(0, mv_timeout - time));
map = sprintf(_("%d seconds left"), i);
pos_x = center - stringwidth(map, false, '8 0 0');
if(mv_abstain)
mv_num_maps -= 1;
- if(mv_num_maps > 3)
- {
- columns = 3;
- } else {
- columns = mv_num_maps;
- }
- rows = ceil(mv_num_maps / columns);
+ rows = ceil(mv_num_maps / mv_columns);
- dist_x = (xmax - xmin) / columns;
+ dist_x = (xmax - xmin) / mv_columns;
dist_y = (ymax - pos_y) / rows;
- tsize = dist_x - 10;
- isize = min(dist_y - 10, 0.75 * tsize);
- mv_selection = MapVote_Selection(pos, dist, rows, columns);
+ if ( gametypevote )
+ {
+ tsize = dist_x - hud_fontsize_y;
+ isize = dist_y;
+ float maxheight = (ymax - pos_y) / 3;
+ if ( isize > maxheight )
+ {
+ pos_x += (isize - maxheight)/2;
+ isize = maxheight;
+ }
+ else
+ dist_y += hud_fontsize_y;
+ pos_x = ( vid_conwidth - dist_x * mv_columns ) / 2;
+ }
+ else
+ {
+ tsize = dist_x - 10;
+ isize = min(dist_y - 10, 0.75 * tsize);
+ }
+
+ mv_selection = MapVote_Selection(pos, dist, rows, mv_columns);
- pos_x += (xmax - xmin) / (2 * columns);
+ if ( !gametypevote )
+ pos_x += dist_x / 2;
pos_y += (dist_y - isize) / 2;
ymax -= isize;
if (mv_top2_time)
mv_top2_alpha = max(0.2, 1 - (time - mv_top2_time)*(time - mv_top2_time));
+ void (vector, float, float, string, string, float, float) DrawItem;
+
+ if(gametypevote)
+ DrawItem = GameTypeVote_DrawGameTypeItem;
+ else
+ DrawItem = MapVote_DrawMapItem;
+
for(i = 0; i < mv_num_maps; ++i)
{
tmp = mv_votes[i]; // FTEQCC bug: too many array accesses in the function call screw it up
map = mv_maps[i];
if(mv_preview[i])
- MapVote_DrawMapItem(pos + MapVote_GridVec(dist, i, columns), isize, tsize, map, mv_pics[i], tmp, i);
+ DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), isize, tsize, map, mv_pics[i], tmp, i);
else
- MapVote_DrawMapItem(pos + MapVote_GridVec(dist, i, columns), isize, tsize, map, "", tmp, i);
+ DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), isize, tsize, map, "", tmp, i);
}
if(mv_abstain)
MapVote_CheckPK3(pic, pk3, id);
}
+void MapVote_ReadMask()
+{
+ float i;
+ if ( mv_num_maps < 24 )
+ {
+ float mask, power;
+ if(mv_num_maps < 8)
+ mask = ReadByte();
+ else if(mv_num_maps < 16)
+ mask = ReadShort();
+ else
+ mask = ReadLong();
+
+ for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)
+ mv_avail[i] = (mask & power) ? GTV_AVAILABLE : GTV_FORBIDDEN;
+ }
+ else
+ {
+ for(i = 0; i < mv_num_maps; ++i )
+ mv_avail[i] = ReadByte();
+ }
+}
+
#define NUM_SSDIRS 4
string ssdirs[NUM_SSDIRS];
float n_ssdirs;
void MapVote_Init()
{
- float i, j, power;
+ float i, j;
string map, pk3, s;
precache_sound ("misc/invshot.wav");
if(autocvar_hud_cursormode) { setcursormode(1); }
else { mv_mousepos = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight; }
mv_selection = -1;
+ mv_selection_keyboard = 0;
for(n_ssdirs = 0; ; ++n_ssdirs)
{
mv_ownvote = -1;
mv_timeout = ReadCoord();
- if(mv_num_maps <= 8)
- mv_maps_mask = ReadByte();
- else
- mv_maps_mask = ReadShort();
+ gametypevote = ReadByte();
+
+ float mv_real_num_maps = mv_num_maps - mv_abstain;
+
+ if(gametypevote)
+ {
+ mapvote_chosenmap = strzone(ReadString());
+ if ( gametypevote == 2 )
+ gametypevote = 0;
+
+ gtv_text_size = hud_fontsize*1.4;
+ gtv_text_size_small = hud_fontsize*1.1;
+
+ if (mv_real_num_maps > 8 )
+ mv_columns = 3;
+ else
+ mv_columns = min(2, mv_real_num_maps);
+ }
+ else
+ {
+ if (mv_real_num_maps > 16)
+ mv_columns = 5;
+ else if (mv_real_num_maps > 9)
+ mv_columns = 4;
+ else if(mv_real_num_maps > 3)
+ mv_columns = 3;
+ else
+ mv_columns = mv_real_num_maps;
+ }
+
+ MapVote_ReadMask();
+ for(i = 0; i < mv_num_maps; ++i )
+ mv_avail_start[i] = mv_avail[i];
// Assume mv_pk3list is world, there should only be 1 mapvote per round
mv_pk3list = world; // I'm still paranoid!
- for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)
+ for(i = 0; i < mv_num_maps; ++i)
{
mv_votes[i] = 0;
- if(mv_maps_mask & power)
- {
- map = strzone(ReadString());
- pk3 = strzone(ReadString());
- j = bound(0, ReadByte(), n_ssdirs - 1);
-
- mv_maps[i] = map;
- mv_pk3[i] = pk3;
- map = strzone(strcat(ssdirs[j], "/", map));
- mv_pics[i] = map;
+ map = strzone(ReadString());
+ pk3 = strzone(ReadString());
+ j = bound(0, ReadByte(), n_ssdirs - 1);
- mv_preview[i] = false;
+ mv_maps[i] = map;
+ mv_pk3[i] = pk3;
+ mv_avail[i] = ReadByte();
- MapVote_CheckPic(map, pk3, i);
+ 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);
}
else
{
- mv_maps[i] = strzone("if-you-see-this-the-code-is-broken");
- mv_pk3[i] = strzone("if-you-see-this-the-code-is-broken");
- mv_pics[i] = strzone("if-you-see-this-the-code-is-broken");
+ map = strzone(strcat(ssdirs[j], "/", map));
+ mv_pics[i] = map;
mv_preview[i] = false;
+ MapVote_CheckPic(map, pk3, i);
}
}
n_ssdirs = 0;
}
+void MapVote_SendChoice(float index)
+{
+ localcmd(strcat("\nimpulse ", ftos(index+1), "\n"));
+}
+
+float MapVote_MoveLeft(float pos)
+{
+ float imp;
+ if ( pos < 0 )
+ imp = mv_num_maps - 1;
+ else
+ imp = pos < 1 ? mv_num_maps - 1 : pos - 1;
+ if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ imp = MapVote_MoveLeft(imp);
+ return imp;
+}
+float MapVote_MoveRight(float pos)
+{
+ float imp;
+ if ( pos < 0 )
+ imp = 0;
+ else
+ imp = pos >= mv_num_maps - 1 ? 0 : pos + 1;
+ if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ imp = MapVote_MoveRight(imp);
+ return imp;
+}
+float MapVote_MoveUp(float pos)
+{
+ float imp;
+ if ( pos < 0 )
+ imp = mv_num_maps - 1;
+ else
+ {
+ imp = pos - mv_columns;
+ if ( imp < 0 )
+ {
+ imp = floor(mv_num_maps/mv_columns)*mv_columns + pos % mv_columns;
+ if ( imp >= mv_num_maps )
+ imp -= mv_columns;
+ }
+ }
+ if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ imp = MapVote_MoveUp(imp);
+ return imp;
+}
+float MapVote_MoveDown(float pos)
+{
+ float imp;
+ if ( pos < 0 )
+ imp = 0;
+ else
+ {
+ imp = pos + mv_columns;
+ if ( imp >= mv_num_maps )
+ imp = imp % mv_columns;
+ }
+ if ( mv_avail[imp] != GTV_AVAILABLE && imp != mv_ownvote )
+ imp = MapVote_MoveDown(imp);
+ return imp;
+}
+
float MapVote_InputEvent(float bInputType, float nPrimary, float nSecondary)
{
float imp;
{
mv_mousepos_x = nPrimary;
mv_mousepos_y = nSecondary;
+ mv_selection_keyboard = 0;
return true;
}
case K_KP_8: localcmd("\nimpulse 8\n"); return true;
case K_KP_9: localcmd("\nimpulse 9\n"); return true;
case K_KP_0: localcmd("\nimpulse 10\n"); return true;
+
+ case K_RIGHTARROW:
+ mv_selection_keyboard = 1;
+ mv_selection = MapVote_MoveRight(mv_selection);
+ return true;
+ case K_LEFTARROW:
+ mv_selection_keyboard = 1;
+ mv_selection = MapVote_MoveLeft(mv_selection);
+ return true;
+ case K_DOWNARROW:
+ mv_selection_keyboard = 1;
+ mv_selection = MapVote_MoveDown(mv_selection);
+ return true;
+ case K_UPARROW:
+ mv_selection_keyboard = 1;
+ mv_selection = MapVote_MoveUp(mv_selection);
+ return true;
+ case K_KP_ENTER:
+ case K_ENTER:
+ case K_SPACE:
+ if ( mv_selection_keyboard )
+ MapVote_SendChoice(mv_selection);
+ return true;
}
if (nPrimary == K_MOUSE1)
+ {
+ mv_selection_keyboard = 0;
+ mv_selection = mv_mouse_selection;
if (mv_selection >= 0)
{
imp = min(mv_selection + 1, mv_num_maps);
localcmd(strcat("\nimpulse ", ftos(imp), "\n"));
return true;
}
+ }
return false;
}
void MapVote_UpdateMask()
{
- float i, power;
- float oldmask;
-
- oldmask = mv_maps_mask;
- if(mv_num_maps <= 8)
- mv_maps_mask = ReadByte();
- else
- mv_maps_mask = ReadShort();
-
- if((oldmask & mv_maps_mask) != oldmask)
- if((oldmask & mv_maps_mask) == mv_maps_mask)
- sound(world, CH_INFO, "misc_invshot.wav", VOL_BASE, ATTEN_NONE);
-
- // remove votes that no longer apply
- for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)
- if (!(mv_maps_mask & power))
- mv_votes[i] = -1;
-
+ MapVote_ReadMask();
mv_top2_time = time;
}
void MapVote_UpdateVotes()
{
- float i, power;
- for(i = 0, power = 1; i < mv_num_maps; ++i, power *= 2)
+ float i;
+ for(i = 0; i < mv_num_maps; ++i)
{
- if(mv_maps_mask & power)
+ if(mv_avail[i] == GTV_AVAILABLE)
{
if(mv_detail)
mv_votes[i] = ReadByte();
-const float STAT_MOVEFLAGS = 225;
const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
#define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
Defs.qc
../dpdefs/keycodes.qc
../common/constants.qh
+../common/stats.qh
../warpzonelib/anglestransform.qh
../warpzonelib/mathlib.qh
../common/teams.qh
../common/util.qh
+../common/nades.qh
+../common/buffs.qh
../common/test.qh
../common/counting.qh
../common/items.qh
../common/monsters/monsters.qc
+../common/nades.qc
+../common/buffs.qc
+
../warpzonelib/anglestransform.qc
../warpzonelib/mathlib.qc
../warpzonelib/common.qc
case PROJECTILE_GRENADE_BOUNCING:
rot = '0 -1000 0'; // sideways
break;
- case PROJECTILE_NADE_RED_BURN:
- case PROJECTILE_NADE_RED:
- case PROJECTILE_NADE_BLUE_BURN:
- case PROJECTILE_NADE_BLUE:
- case PROJECTILE_NADE_YELLOW_BURN:
- case PROJECTILE_NADE_YELLOW:
- case PROJECTILE_NADE_PINK_BURN:
- case PROJECTILE_NADE_PINK:
- case PROJECTILE_NADE_BURN:
- case PROJECTILE_NADE:
- rot = self.avelocity;
- break;
case PROJECTILE_HOOKBOMB:
rot = '1000 0 0'; // forward
break;
default:
break;
}
+
+ if(Nade_IDFromProjectile(self.cnt) != 0)
+ rot = self.avelocity;
+
self.angles = AnglesTransform_ToAngles(AnglesTransform_Multiply(AnglesTransform_FromAngles(self.angles), rot * (t - self.spawntime)));
}
trailorigin = self.origin;
switch(self.cnt)
{
- case PROJECTILE_NADE_RED_BURN:
- case PROJECTILE_NADE_RED:
- case PROJECTILE_NADE_BLUE_BURN:
- case PROJECTILE_NADE_BLUE:
- case PROJECTILE_NADE_YELLOW_BURN:
- case PROJECTILE_NADE_YELLOW:
- case PROJECTILE_NADE_PINK_BURN:
- case PROJECTILE_NADE_PINK:
- case PROJECTILE_NADE_BURN:
- case PROJECTILE_NADE:
- trailorigin += v_up * 4;
- break;
case PROJECTILE_GRENADE:
case PROJECTILE_GRENADE_BOUNCING:
trailorigin += v_right * 1 + v_forward * -10;
default:
break;
}
+
+ if(Nade_IDFromProjectile(self.cnt) != 0)
+ trailorigin += v_up * 4;
+
if(drawn)
Projectile_DrawTrail(trailorigin);
else
self.fade_time = 0;
self.fade_rate = 0;
}
+
+ self.team = ReadByte() - 1;
}
if(f & 2)
case PROJECTILE_HOOKBOMB: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_KNIGHTSPIKE"); break;
case PROJECTILE_HAGAR: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum("tr_hagar"); self.scale = 0.75; break;
case PROJECTILE_HAGAR_BOUNCING: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum("tr_hagar"); self.scale = 0.75; break;
+ case PROJECTILE_NAPALM_FOUNTAIN: //self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum("torch_small"); break;
case PROJECTILE_FIREBALL: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum("fireball"); break; // particle effect is good enough
case PROJECTILE_FIREMINE: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum("firemine"); break; // particle effect is good enough
case PROJECTILE_TAG: setmodel(self, "models/laser.mdl"); self.traileffect = particleeffectnum("TR_ROCKET"); break;
case PROJECTILE_BUMBLE_GUN: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum("TR_NEXUIZPLASMA"); break;
case PROJECTILE_BUMBLE_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum("TR_NEXUIZPLASMA"); break;
- case PROJECTILE_NADE_RED: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_red"); break;
- case PROJECTILE_NADE_RED_BURN: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_red_burn"); break;
- case PROJECTILE_NADE_BLUE: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_blue"); break;
- case PROJECTILE_NADE_BLUE_BURN: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_blue_burn"); break;
- case PROJECTILE_NADE_YELLOW: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_yellow"); break;
- case PROJECTILE_NADE_YELLOW_BURN: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_yellow_burn"); break;
- case PROJECTILE_NADE_PINK: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_pink"); break;
- case PROJECTILE_NADE_PINK_BURN: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_pink_burn"); break;
- case PROJECTILE_NADE: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade"); break;
- case PROJECTILE_NADE_BURN: setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum("nade_burn"); break;
-
default:
+ if(Nade_IDFromProjectile(self.cnt) != 0) { setmodel(self, "models/weapons/v_ok_grenade.md3");self.traileffect = particleeffectnum(Nade_TrailEffect(self.cnt, self.team)); break; }
error("Received invalid CSQC projectile, can't work with this!");
break;
}
self.mins = '-3 -3 -3';
self.maxs = '3 3 3';
break;
- case PROJECTILE_NADE_RED_BURN:
- case PROJECTILE_NADE_RED:
- case PROJECTILE_NADE_BLUE_BURN:
- case PROJECTILE_NADE_BLUE:
- self.mins = '-3 -3 -3';
- self.maxs = '3 3 3';
- self.move_movetype = MOVETYPE_BOUNCE;
- self.move_touch = func_null;
- self.scale = 1.5;
- self.avelocity = randomvec() * 720;
- break;
case PROJECTILE_GRENADE_BOUNCING:
self.mins = '-3 -3 -3';
self.maxs = '3 3 3';
self.move_bounce_factor = g_balance_grenadelauncher_bouncefactor;
self.move_bounce_stopspeed = g_balance_grenadelauncher_bouncestop;
break;
- case PROJECTILE_NADE_RED_BURN:
- case PROJECTILE_NADE_RED:
- case PROJECTILE_NADE_BLUE_BURN:
- case PROJECTILE_NADE_BLUE:
- case PROJECTILE_NADE_YELLOW_BURN:
- case PROJECTILE_NADE_YELLOW:
- case PROJECTILE_NADE_PINK_BURN:
- case PROJECTILE_NADE_PINK:
- case PROJECTILE_NADE_BURN:
- case PROJECTILE_NADE:
- self.mins = '-16 -16 -16';
- self.maxs = '16 16 16';
- self.move_movetype = MOVETYPE_BOUNCE;
- self.move_touch = func_null;
- self.scale = 1.5;
- self.avelocity = randomvec() * 720;
- break;
case PROJECTILE_SHAMBLER_LIGHTNING:
self.mins = '-8 -8 -8';
self.maxs = '8 8 8';
self.move_movetype = MOVETYPE_BOUNCE;
self.move_touch = func_null;
break;
+ case PROJECTILE_NAPALM_FOUNTAIN:
case PROJECTILE_FIREBALL:
loopsound(self, CH_SHOTS_SINGLE, "weapons/fireball_fly2.wav", VOL_BASE, ATTEN_NORM);
self.mins = '-16 -16 -16';
default:
break;
}
+
+ if(Nade_IDFromProjectile(self.cnt) != 0)
+ {
+ self.mins = '-16 -16 -16';
+ self.maxs = '16 16 16';
+ self.colormod = Nade_Color(Nade_IDFromProjectile(self.cnt));
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ self.move_movetype = MOVETYPE_BOUNCE;
+ self.move_touch = func_null;
+ self.scale = 1.5;
+ self.avelocity = randomvec() * 720;
+
+ if(Nade_IDFromProjectile(self.cnt) == NADE_TYPE_TRANSLOCATE)
+ self.solid = SOLID_TRIGGER;
+ }
+
setsize(self, self.mins, self.maxs);
}
precache_model("models/rocket.md3");
precache_model("models/tagrocket.md3");
precache_model("models/tracer.mdl");
+ precache_model("models/sphere/sphere.md3");
precache_model("models/weapons/v_ok_grenade.md3");
hud_field[hud_num_fields] = SP_PL;
} else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
hud_field[hud_num_fields] = SP_KDRATIO;
- } else if(str == "sum" || str == "diff" || str == "f-d") {
+ } else if(str == "sum" || str == "diff" || str == "k-d") {
hud_field[hud_num_fields] = SP_SUM;
} else if(str == "name" || str == "nick") {
hud_field[hud_num_fields] = SP_NAME;
if(!ent.sameteam || (ent.sv_entnum == player_localentnum))
ent.alpha *= getplayeralpha(ent.sv_entnum-1);
- if(ent.alpha < ALPHA_MIN_VISIBLE)
+ if(ent.alpha < ALPHA_MIN_VISIBLE && gametype != MAPINFO_TYPE_CTS)
return;
float dist;
snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
}
- sound7(e, CH_TUBA, snd1, e.cnt * f1, e.attenuate * autocvar_g_balance_tuba_attenuation, 100 * p1, 0);
+ sound7(e, CH_TUBA_SINGLE, snd1, e.cnt * f1, e.attenuate * autocvar_g_balance_tuba_attenuation, 100 * p1, 0);
if(f2)
- sound7(e.enemy, CH_TUBA, snd2, e.cnt * f2, e.attenuate * autocvar_g_balance_tuba_attenuation, 100 * p2, 0);
+ sound7(e.enemy, CH_TUBA_SINGLE, snd2, e.cnt * f2, e.attenuate * autocvar_g_balance_tuba_attenuation, 100 * p2, 0);
}
else
{
if(restart)
snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
- sound(e, CH_TUBA, snd1, e.cnt, e.attenuate * autocvar_g_balance_tuba_attenuation);
+ sound(e, CH_TUBA_SINGLE, snd1, e.cnt, e.attenuate * autocvar_g_balance_tuba_attenuation);
}
}
self.nextthink = time;
if(self.cnt <= 0)
{
- sound(self, CH_TUBA, "misc/null.wav", 0, 0);
+ sound(self, CH_TUBA_SINGLE, "misc/null.wav", 0, 0);
if(self.enemy)
{
- sound(self.enemy, CH_TUBA, "misc/null.wav", 0, 0);
+ sound(self.enemy, CH_TUBA_SINGLE, "misc/null.wav", 0, 0);
remove(self.enemy);
}
remove(self);
}
string spritelookuptext(string s)
{
+ if(substring(s, 0, 5) == "buff-") { return Buff_PrettyName(Buff_Type_FromSprite(s)); }
switch(s)
{
case "as-push": return _("Push");
case "item-shield": return _("Shield");
case "item-fuelregen": return _("Fuel regen");
case "item-jetpack": return _("Jet Pack");
- case "freezetag_frozen": return _("Frozen!");
+ case "frozen": return _("Frozen!");
case "tagged-target": return _("Tagged");
case "vehicle": return _("Vehicle");
default: return s;
--- /dev/null
+vector Buff_Color(float buff_id)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_id == e.items)
+ return e.colormod;
+ return '1 1 1';
+}
+
+string Buff_PrettyName(float buff_id)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_id == e.items)
+ return e.message;
+ return "";
+}
+
+string Buff_Name(float buff_id)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_id == e.items)
+ return e.netname;
+ return "";
+}
+
+float Buff_Type_FromName(string buff_name)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_name == e.netname)
+ return e.items;
+ return 0;
+}
+
+float Buff_Type_FromSprite(string buff_sprite)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_sprite == e.model2)
+ return e.items;
+ return 0;
+}
+
+
+float Buff_Skin(float buff_id)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_id == e.items)
+ return e.skin;
+ return 0;
+}
+
+string Buff_Sprite(float buff_id)
+{
+ entity e;
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_id == e.items)
+ return e.model2;
+ return "";
+}
--- /dev/null
+entity Buff_Type_first;
+entity Buff_Type_last;
+.entity enemy; // internal next pointer
+
+var float BUFF_LAST = 1;
+
+.float items; // buff ID
+.string netname; // buff name
+.string message; // human readable name
+.vector colormod; // buff color
+.string model2; // buff sprite
+.float skin; // buff skin
+
+#define REGISTER_BUFF(hname,sname,NAME,bskin,bcolor) \
+ var float BUFF_##NAME; \
+ var entity Buff_Type##sname; \
+ void RegisterBuffs_##sname() \
+ { \
+ BUFF_##NAME = BUFF_LAST * 2; \
+ BUFF_LAST = BUFF_##NAME; \
+ Buff_Type##sname = spawn(); \
+ Buff_Type##sname.items = BUFF_##NAME; \
+ Buff_Type##sname.netname = #sname; \
+ Buff_Type##sname.message = hname; \
+ Buff_Type##sname.skin = bskin; \
+ Buff_Type##sname.colormod = bcolor; \
+ Buff_Type##sname.model2 = strzone(strcat("buff-", #sname)); \
+ if(!Buff_Type_first) \
+ Buff_Type_first = Buff_Type##sname; \
+ if(Buff_Type_last) \
+ Buff_Type_last.enemy = Buff_Type##sname; \
+ Buff_Type_last = Buff_Type##sname; \
+ } \
+ ACCUMULATE_FUNCTION(RegisterBuffs, RegisterBuffs_##sname)
+
+REGISTER_BUFF(_("Ammo"),ammo,AMMO,3,'0.2 1 0.2');
+REGISTER_BUFF(_("Resistance"),resistance,RESISTANCE,0,'0.3 0.2 1');
+REGISTER_BUFF(_("Speed"),speed,SPEED,9,'1 1 0.2');
+REGISTER_BUFF(_("Medic"),medic,MEDIC,1,'1 0.3 1');
+REGISTER_BUFF(_("Bash"),bash,BASH,5,'1 0.4 0');
+REGISTER_BUFF(_("Vampire"),vampire,VAMPIRE,2,'1 0.15 0');
+REGISTER_BUFF(_("Disability"),disability,DISABILITY,7,'0.66 0.66 0.73');
+REGISTER_BUFF(_("Vengeance"),vengeance,VENGEANCE,15,'0.55 0.5 1');
+REGISTER_BUFF(_("Jump"),jump,JUMP,10,'0.7 0.2 1');
+REGISTER_BUFF(_("Flight"),flight,FLIGHT,11,'1 0.2 0.5');
+REGISTER_BUFF(_("Invisible"),invisible,INVISIBLE,12,'0.9 0.9 0.9');
+#undef REGISTER_BUFF
+
+#ifdef SVQC
+.float buffs;
+void buff_Init(entity ent);
+void buff_Init_Compat(entity ent, float replacement);
+
+#define BUFF_SPAWNFUNC(e,b,t) void spawnfunc_item_buff_##e() { self.buffs = b; self.team = t; buff_Init(self); }
+#define BUFF_SPAWNFUNC_Q3TA_COMPAT(o,r) void spawnfunc_item_##o() { buff_Init_Compat(self,r); }
+#define BUFF_SPAWNFUNCS(e,b) \
+ BUFF_SPAWNFUNC(e, b, 0) \
+ BUFF_SPAWNFUNC(e##_team1, b, NUM_TEAM_1) \
+ BUFF_SPAWNFUNC(e##_team2, b, NUM_TEAM_2) \
+ BUFF_SPAWNFUNC(e##_team3, b, NUM_TEAM_3) \
+ BUFF_SPAWNFUNC(e##_team4, b, NUM_TEAM_4)
+
+BUFF_SPAWNFUNCS(resistance, BUFF_RESISTANCE)
+BUFF_SPAWNFUNCS(ammo, BUFF_AMMO)
+BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
+BUFF_SPAWNFUNCS(medic, BUFF_MEDIC)
+BUFF_SPAWNFUNCS(bash, BUFF_BASH)
+BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
+BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
+BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
+BUFF_SPAWNFUNCS(jump, BUFF_JUMP)
+BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
+BUFF_SPAWNFUNCS(invisible, BUFF_INVISIBLE)
+BUFF_SPAWNFUNCS(random, 0)
+
+BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(resistance, BUFF_RESISTANCE)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
+
+// actually Q3
+BUFF_SPAWNFUNC_Q3TA_COMPAT(haste, BUFF_SPEED)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(invis, BUFF_INVISIBLE)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(medic, BUFF_MEDIC)
+#endif
+
+vector Buff_Color(float buff_id);
+string Buff_PrettyName(float buff_id);
+string Buff_Name(float buff_id);
+float Buff_Type_FromName(string buff_name);
+float Buff_Type_FromSprite(string buff_sprite);
+float Buff_Skin(float buff_id);
+string Buff_Sprite(float buff_id);
const float ENT_CLIENT_AUXILIARYXHAIR = 50;
const float ENT_CLIENT_VEHICLE = 60;
+const float ENT_CLIENT_HEALING_ORB = 80;
+
const float SPRITERULE_DEFAULT = 0;
const float SPRITERULE_TEAMPLAY = 1;
///////////////////////////
// csqc communication stuff
-const float STAT_KH_KEYS = 32;
-const float STAT_CTF_STATE = 33;
-const float STAT_WEAPONS = 35;
-const float STAT_SWITCHWEAPON = 36;
-const float STAT_GAMESTARTTIME = 37;
-const float STAT_STRENGTH_FINISHED = 38;
-const float STAT_INVINCIBLE_FINISHED = 39;
-const float STAT_PRESSED_KEYS = 42;
-const float STAT_ALLOW_OLDNEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config
-const float STAT_FUEL = 44;
-const float STAT_NB_METERSTART = 45;
-const float STAT_SHOTORG = 46; // compressShotOrigin
-const float STAT_LEADLIMIT = 47;
-const float STAT_WEAPON_CLIPLOAD = 48;
-const float STAT_WEAPON_CLIPSIZE = 49;
-const float STAT_NEX_CHARGE = 50;
-const float STAT_LAST_PICKUP = 51;
-const float STAT_HUD = 52;
-const float STAT_NEX_CHARGEPOOL = 53;
-const float STAT_HIT_TIME = 54;
-const float STAT_TYPEHIT_TIME = 55;
-const float STAT_LAYED_MINES = 56;
-const float STAT_HAGAR_LOAD = 57;
-const float STAT_SWITCHINGWEAPON = 58;
-const float STAT_SUPERWEAPONS_FINISHED = 59;
-
-const float STAT_VEHICLESTAT_HEALTH = 60;
-const float STAT_VEHICLESTAT_SHIELD = 61;
-const float STAT_VEHICLESTAT_ENERGY = 62;
-const float STAT_VEHICLESTAT_AMMO1 = 63;
-const float STAT_VEHICLESTAT_RELOAD1 = 64;
-const float STAT_VEHICLESTAT_AMMO2 = 65;
-const float STAT_VEHICLESTAT_RELOAD2 = 66;
-
-const float STAT_SECRETS_TOTAL = 70;
-const float STAT_SECRETS_FOUND = 71;
-
-const float STAT_RESPAWN_TIME = 72;
-const float STAT_ROUNDSTARTTIME = 73;
-
-const float STAT_WEAPONS2 = 74;
-const float STAT_WEAPONS3 = 75;
-
-const float STAT_MONSTERS_TOTAL = 76;
-const float STAT_MONSTERS_KILLED = 77;
-
-const float STAT_CTF_FLAGSTATUS = 78;
-
-// mod stats (1xx)
-const float STAT_REDALIVE = 100;
-const float STAT_BLUEALIVE = 101;
-const float STAT_YELLOWALIVE = 102;
-const float STAT_PINKALIVE = 103;
-
-// freeze tag
-const float STAT_FROZEN = 104;
-const float STAT_REVIVE_PROGRESS = 105;
-
-// domination
-const float STAT_DOM_TOTAL_PPS = 100;
-const float STAT_DOM_PPS_RED = 101;
-const float STAT_DOM_PPS_BLUE = 102;
-const float STAT_DOM_PPS_PINK = 103;
-const float STAT_DOM_PPS_YELLOW = 104;
-
-//const float STAT_SPIDERBOT_AIM 53 // compressShotOrigin
-//const float STAT_SPIDERBOT_TARGET 54 // compressShotOrigin
-
-// see DP source, quakedef.h
-const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222;
-const float STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223;
-const float STAT_MOVEVARS_MAXSPEED = 244;
-const float STAT_MOVEVARS_AIRACCEL_QW = 254;
-
const float CTF_STATE_ATTACK = 1;
const float CTF_STATE_DEFEND = 2;
const float CTF_STATE_COMMANDER = 3;
// moved that here so the client knows the max.
// # of maps, I'll use arrays for them :P
-#define MAPVOTE_COUNT 10
+#define MAPVOTE_COUNT 30
/**
* Lower scores are better (e.g. suicides)
#define SP_SCORE 3
// game mode specific indices are not in common/, but in server/scores_rules.qc!
-#ifdef COMPAT_XON010_CHANNELS
-const float CH_INFO = 0; // only on world and csqc
-const float CH_TRIGGER = 0; // only on players; compat: FALSELY CONTROLLED BY "Info"
-const float CH_WEAPON_A = 1; // only on players and entities
-const float CH_WEAPON_SINGLE = 5; // only on players and entities
-const float CH_VOICE = 2; // only on players
-const float CH_BGM_SINGLE = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice"
-const float CH_AMBIENT = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice"
-const float CH_TRIGGER_SINGLE = 3; // only on players, entities, csqc
-const float CH_SHOTS = 4; // only on players, entities, csqc
-const float CH_SHOTS_SINGLE = 4; // only on players, entities, csqc
-const float CH_WEAPON_B = 5; // only on players and entities
-const float CH_PAIN = 6; // only on players and csqc
-const float CH_PAIN_SINGLE = 6; // only on players and csqc
-const float CH_PLAYER = 7; // only on players and entities
-const float CH_TUBA = 5; // only on csqc
-#else
const float CH_INFO = 0;
const float CH_TRIGGER = -3;
const float CH_WEAPON_A = -1;
const float CH_PAIN = -6;
const float CH_PAIN_SINGLE = 6;
const float CH_PLAYER = -7;
-const float CH_TUBA = 5;
-#endif
+const float CH_PLAYER_SINGLE = 7;
+const float CH_TUBA_SINGLE = 5;
const float ATTEN_NONE = 0;
const float ATTEN_MIN = 0.015625;
const float PROJECTILE_MAGE_SPIKE = 32;
const float PROJECTILE_SHAMBLER_LIGHTNING = 33;
-const float PROJECTILE_NADE_RED = 50;
-const float PROJECTILE_NADE_RED_BURN = 51;
-const float PROJECTILE_NADE_BLUE = 52;
-const float PROJECTILE_NADE_BLUE_BURN = 53;
-const float PROJECTILE_NADE_YELLOW = 54;
-const float PROJECTILE_NADE_YELLOW_BURN = 55;
-const float PROJECTILE_NADE_PINK = 56;
-const float PROJECTILE_NADE_PINK_BURN = 57;
-const float PROJECTILE_NADE = 58;
-const float PROJECTILE_NADE_BURN = 59;
-
const float SPECIES_HUMAN = 0;
const float SPECIES_ROBOT_SOLID = 1;
const float SPECIES_ALIEN = 2;
#define URI_GET_UPDATENOTIFICATION 33
#define URI_GET_URLLIB 128
#define URI_GET_URLLIB_END 191
+
+// gametype votes
+#define GTV_AVAILABLE 0
+// for later use in per-map gametype filtering
+#define GTV_FORBIDDEN 2
#define DEATHTYPES \
DEATHTYPE(DEATH_AUTOTEAMCHANGE, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, DEATH_SPECIAL_START) \
+ DEATHTYPE(DEATH_BUFF_VENGEANCE, NO_MSG, DEATH_MURDER_VENGEANCE, NORMAL_POS) \
DEATHTYPE(DEATH_CAMP, DEATH_SELF_CAMP, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_CHEAT, DEATH_SELF_CHEAT, DEATH_MURDER_CHEAT, NORMAL_POS) \
DEATHTYPE(DEATH_CUSTOM, DEATH_SELF_CUSTOM, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_WYVERN, DEATH_SELF_MON_WYVERN, DEATH_MURDER_MONSTER, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_ZOMBIE_JUMP, DEATH_SELF_MON_ZOMBIE_JUMP, DEATH_MURDER_MONSTER, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_ZOMBIE_MELEE, DEATH_SELF_MON_ZOMBIE_MELEE, DEATH_MURDER_MONSTER, DEATH_MONSTER_LAST) \
- DEATHTYPE(DEATH_NADE, DEATH_SELF_NADE, DEATH_MURDER_NADE, NORMAL_POS) \
+ DEATHTYPE(DEATH_NADE, DEATH_SELF_NADE, DEATH_MURDER_NADE, NORMAL_POS) \
+ DEATHTYPE(DEATH_NADE_NAPALM, DEATH_SELF_NADE_NAPALM, DEATH_MURDER_NADE_NAPALM, NORMAL_POS) \
+ DEATHTYPE(DEATH_NADE_ICE, DEATH_SELF_NADE_ICE, DEATH_MURDER_NADE_ICE, NORMAL_POS) \
+ DEATHTYPE(DEATH_NADE_ICE_FREEZE, DEATH_SELF_NADE_ICE_FREEZE, DEATH_MURDER_NADE_ICE_FREEZE, NORMAL_POS) \
+ DEATHTYPE(DEATH_NADE_HEAL, DEATH_SELF_NADE_HEAL, DEATH_MURDER_NADE_HEAL, NORMAL_POS) \
DEATHTYPE(DEATH_NOAMMO, DEATH_SELF_NOAMMO, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_ROT, DEATH_SELF_ROT, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_SHOOTING_STAR, DEATH_SELF_SHOOTING_STAR, DEATH_MURDER_SHOOTING_STAR, NORMAL_POS) \
t = "inv";
print("'. Should use '", t, "'.\n");
}
+ if(t == "assault")
+ {
+ print("MapInfo_Type_FromString (probably ", MapInfo_Map_bspname, "): using deprecated name '", t);
+ t = "as";
+ print("'. Should use '", t, "'.\n");
+ }
+ if(t == "race")
+ {
+ print("MapInfo_Type_FromString (probably ", MapInfo_Map_bspname, "): using deprecated name '", t);
+ t = "rc";
+ print("'. Should use '", t, "'.\n");
+ }
if(t == "all")
return MAPINFO_TYPE_ALL;
for(e = MapInfo_Type_first; e; e = e.enemy)
return 0;
}
+string MapInfo_Type_Description(float t)
+{
+ entity e;
+ for(e = MapInfo_Type_first; e; e = e.enemy)
+ if(t == e.items)
+ return e.gametype_description;
+ return "";
+}
+
string MapInfo_Type_ToString(float t)
{
entity e;
{
t = car(s); s = cdr(s);
f = MapInfo_Type_FromString(t);
- print("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.\n");
+ dprint("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.\n");
if(f)
_MapInfo_Map_ApplyGametype (s, pGametypeToSet, f, TRUE);
else
localcmd(strcat("\nchangelevel ", s, "\n"));
}
-string MapInfo_ListAllowedMaps(float pRequiredFlags, float pForbiddenFlags)
+string MapInfo_ListAllowedMaps(float type, float pRequiredFlags, float pForbiddenFlags)
{
string out;
float i;
// to make absolutely sure:
MapInfo_Enumerate();
- MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), pRequiredFlags, pForbiddenFlags, 0);
+ MapInfo_FilterGametype(type, MapInfo_CurrentFeatures(), pRequiredFlags, pForbiddenFlags, 0);
out = "";
for(i = 0; i < MapInfo_count; ++i)
.string mdl; // game type short name
.string message; // human readable name
.string model2; // game type defaults
+.string gametype_description; // game type description
-#define REGISTER_GAMETYPE(hname,sname,g_name,NAME,defaults) \
+#define REGISTER_GAMETYPE(hname,sname,g_name,NAME,defaults,gdescription) \
var float MAPINFO_TYPE_##NAME; \
var entity MapInfo_Type##g_name; \
void RegisterGametypes_##g_name() \
MapInfo_Type##g_name.mdl = #sname; \
MapInfo_Type##g_name.message = hname; \
MapInfo_Type##g_name.model2 = defaults; \
+ MapInfo_Type##g_name.gametype_description = gdescription; \
if(!MapInfo_Type_first) \
MapInfo_Type_first = MapInfo_Type##g_name; \
if(MapInfo_Type_last) \
#define IS_GAMETYPE(NAME) \
(MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
-REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,"timelimit=20 pointlimit=30 leadlimit=0");
+REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,"timelimit=20 pointlimit=30 leadlimit=0",_("Kill all enemies"));
#define g_dm IS_GAMETYPE(DEATHMATCH)
-REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,"timelimit=20 lives=9 leadlimit=0");
+REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
#define g_lms IS_GAMETYPE(LMS)
-REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0");
+REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
#define g_race IS_GAMETYPE(RACE)
-REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,"timelimit=20 skill=-1");
+REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,"timelimit=20 skill=-1",_("Race for fastest time"));
#define g_cts IS_GAMETYPE(CTS)
-REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,"timelimit=20 pointlimit=50 teams=2 leadlimit=0");
+REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Kill all enemy teammates"));
#define g_tdm IS_GAMETYPE(TEAM_DEATHMATCH)
-REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,"timelimit=20 caplimit=10 leadlimit=0");
+REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,"timelimit=20 caplimit=10 leadlimit=0",_("Find and bring the enemy flag to your base to capture it"));
#define g_ctf IS_GAMETYPE(CTF)
-REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,"timelimit=20 pointlimit=10 leadlimit=0");
+REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,"timelimit=20 pointlimit=10 leadlimit=0",_("Kill all enemy teammates to win the round"));
#define g_ca IS_GAMETYPE(CA)
-REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,"timelimit=20 pointlimit=200 teams=2 leadlimit=0");
+REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture all the control points to win"));
#define g_domination IS_GAMETYPE(DOMINATION)
-REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0");
+REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
#define g_keyhunt IS_GAMETYPE(KEYHUNT)
-REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,"timelimit=20");
+REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
#define g_assault IS_GAMETYPE(ASSAULT)
-REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,"timelimit=20");
+REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,"timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
#define g_onslaught IS_GAMETYPE(ONSLAUGHT)
-REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,"timelimit=20 pointlimit=5 leadlimit=0");
+REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,"timelimit=20 pointlimit=5 leadlimit=0",_("XonSports"));
#define g_nexball IS_GAMETYPE(NEXBALL)
-REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,"timelimit=20 pointlimit=10 teams=2 leadlimit=0");
+REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them"));
#define g_freezetag IS_GAMETYPE(FREEZETAG)
-REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,"timelimit=20 pointlimit=30");
+REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
#define g_keepaway IS_GAMETYPE(KEEPAWAY)
-REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,"pointlimit=50 teams=0");
+REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,"pointlimit=50 teams=0",_("Survive against waves of monsters"));
#define g_invasion IS_GAMETYPE(INVASION)
const float MAPINFO_FEATURE_WEAPONS = 1; // not defined for minstagib-only maps
void MapInfo_LoadMap(string s, float reinit);
// list all maps for the current game type
-string MapInfo_ListAllowedMaps(float pFlagsRequired, float pFlagsForbidden);
+string MapInfo_ListAllowedMaps(float type, float pFlagsRequired, float pFlagsForbidden);
// list all allowed maps (for any game type)
string MapInfo_ListAllAllowedMaps(float pFlagsRequired, float pFlagsForbidden);
// gets a gametype from a string
string _MapInfo_GetDefaultEx(float t);
float MapInfo_Type_FromString(string t);
+string MapInfo_Type_Description(float t);
string MapInfo_Type_ToString(float t);
string MapInfo_Type_ToText(float t);
void MapInfo_SwitchGameType(float t);
return FALSE;
if(DIFF_TEAM(e, self) && e != self.monster_owner)
return FALSE;
- if(e.freezetag_frozen)
+ if(e.frozen)
return FALSE;
if(!IS_PLAYER(e))
return ((e.flags & FL_MONSTER) && e.health < e.max_health);
if(SAME_TEAM(targ, ent))
return FALSE; // enemy is on our team
- if (targ.freezetag_frozen)
+ if (targ.frozen)
return FALSE; // ignore frozen
if(autocvar_g_monsters_target_infront || (ent.spawnflags & MONSTERFLAG_INFRONT))
if((self.enemy == world)
|| (self.enemy.deadflag != DEAD_NO || self.enemy.health < 1)
- || (self.enemy.freezetag_frozen)
+ || (self.enemy.frozen)
|| (self.enemy.flags & FL_NOTARGET)
|| (self.enemy.alpha < 0.5)
|| (self.enemy.takedamage == DAMAGE_NO)
entity targ;
+ if(self.frozen == 2)
+ {
+ self.revive_progress = bound(0, self.revive_progress + self.ticrate * self.revive_speed, 1);
+ self.health = max(1, self.revive_progress * self.max_health);
+ self.iceblock.alpha = bound(0.2, 1 - self.revive_progress, 1);
+
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+
+ movelib_beak_simple(stopspeed);
+ self.frame = manim_idle;
+
+ self.enemy = world;
+ self.nextthink = time + self.ticrate;
+
+ if(self.revive_progress >= 1)
+ Unfreeze(self);
+
+ return;
+ }
+ else if(self.frozen == 3)
+ {
+ self.revive_progress = bound(0, self.revive_progress - self.ticrate * self.revive_speed, 1);
+ self.health = max(0, autocvar_g_nades_ice_health + (self.max_health-autocvar_g_nades_ice_health) * self.revive_progress );
+
+ WaypointSprite_UpdateHealth(self.sprite, self.health);
+
+ movelib_beak_simple(stopspeed);
+ self.frame = manim_idle;
+
+ self.enemy = world;
+ self.nextthink = time + self.ticrate;
+
+ if(self.health < 1)
+ {
+ Unfreeze(self);
+ self.health = 0;
+ self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE, self.origin, '0 0 0');
+ }
+
+ else if ( self.revive_progress <= 0 )
+ Unfreeze(self);
+
+ return;
+ }
+
if(self.flags & FL_SWIM)
{
if(self.waterlevel < WATERLEVEL_WETFEET)
if(mon.weaponentity)
remove(mon.weaponentity);
+ if(mon.iceblock)
+ remove(mon.iceblock);
+
WaypointSprite_Kill(mon.sprite);
remove(mon);
setorigin(self, self.pos1);
self.angles = self.pos2;
+ Unfreeze(self); // remove any icy remains
+
self.health = self.max_health;
self.velocity = '0 0 0';
self.enemy = world;
self.nextthink = time;
self.monster_lifetime = time + 5;
+ if(self.frozen)
+ {
+ Unfreeze(self); // remove any icy remains
+ self.health = 0; // reset by Unfreeze
+ }
+
monster_dropitem();
MonsterSound(monstersound_death, 0, FALSE, CH_VOICE);
void monsters_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
+ if(self.frozen && deathtype != DEATH_KILL && deathtype != DEATH_NADE_ICE_FREEZE)
+ return;
+
if((self.spawnflags & MONSTERFLAG_INVINCIBLE) && deathtype != DEATH_KILL)
return;
--- /dev/null
+.float healer_lifetime;
+.float healer_radius;
+
+#ifdef SVQC
+float healer_send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_HEALING_ORB);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & 1)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+
+ WriteByte(MSG_ENTITY, self.healer_lifetime);
+ //WriteByte(MSG_ENTITY, self.ltime - time + 1);
+ WriteShort(MSG_ENTITY, self.healer_radius);
+ // round time delta to a 1/10th of a second
+ WriteByte(MSG_ENTITY, (self.ltime - time)*10.0+0.5);
+ }
+
+ return TRUE;
+}
+#endif // SVQC
+
+#ifdef CSQC
+.float ltime;
+void healer_draw()
+{
+ float dt = time - self.move_time;
+ self.move_time = time;
+ if(dt <= 0)
+ return;
+
+ self.alpha = (self.ltime - time) / self.healer_lifetime;
+ self.scale = min((1 - self.alpha)*self.healer_lifetime*4,1)*self.healer_radius;
+
+}
+
+void healer_setup()
+{
+ setmodel(self, "models/ctf/shield.md3");
+
+ setorigin(self, self.origin);
+
+ float model_radius = self.maxs_x;
+ vector size = '1 1 1' * self.healer_radius / 2;
+ setsize(self,-size,size);
+ self.healer_radius = self.healer_radius/model_radius*0.6;
+
+ self.draw = healer_draw;
+ self.health = 255;
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_NOT;
+ self.drawmask = MASK_NORMAL;
+ self.scale = 0.01;
+ self.avelocity = self.move_avelocity = '7 0 11';
+ self.colormod = '1 0 0';
+ self.renderflags |= RF_ADDITIVE;
+}
+
+void ent_healer()
+{
+ float sf = ReadByte();
+
+ if(sf & TNSF_SETUP)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ setorigin(self, self.origin);
+
+ self.healer_lifetime = ReadByte();
+ self.healer_radius = ReadShort();
+ self.ltime = time + ReadByte()/10.0;
+ //self.ltime = time + self.healer_lifetime;
+
+ healer_setup();
+ }
+}
+#endif // CSQC
\ No newline at end of file
--- /dev/null
+// use slots 70-100
+const float PROJECTILE_NADE = 71;
+const float PROJECTILE_NADE_BURN = 72;
+const float PROJECTILE_NADE_NAPALM = 73;
+const float PROJECTILE_NADE_NAPALM_BURN = 74;
+const float PROJECTILE_NAPALM_FOUNTAIN = 75;
+const float PROJECTILE_NADE_ICE = 76;
+const float PROJECTILE_NADE_ICE_BURN = 77;
+const float PROJECTILE_NADE_TRANSLOCATE = 78;
+const float PROJECTILE_NADE_SPAWN = 79;
+const float PROJECTILE_NADE_HEAL = 80;
+const float PROJECTILE_NADE_HEAL_BURN = 81;
+const float PROJECTILE_NADE_MONSTER = 82;
+const float PROJECTILE_NADE_MONSTER_BURN = 83;
+
+const float NADE_TYPE_NORMAL = 1;
+const float NADE_TYPE_NAPALM = 2;
+const float NADE_TYPE_ICE = 3;
+const float NADE_TYPE_TRANSLOCATE = 4;
+const float NADE_TYPE_SPAWN = 5;
+const float NADE_TYPE_HEAL = 6;
+const float NADE_TYPE_MONSTER = 7;
+
+const float NADE_TYPE_LAST = 7; // a check to prevent using higher values & crashing
+
+vector Nade_Color(float nadeid)
+{
+ switch(nadeid)
+ {
+ case NADE_TYPE_NORMAL: return '1 1 1';
+ case NADE_TYPE_NAPALM: return '2 0.5 0';
+ case NADE_TYPE_ICE: return '0 0.5 2';
+ case NADE_TYPE_TRANSLOCATE: return '1 0.0625 1';
+ case NADE_TYPE_SPAWN: return '1 0.9 0.06';
+ case NADE_TYPE_HEAL: return '1 0 0';
+ case NADE_TYPE_MONSTER: return '1 0.5 0';
+ }
+
+ return '0 0 0';
+}
+
+float Nade_IDFromProjectile(float proj)
+{
+ switch(proj)
+ {
+ case PROJECTILE_NADE:
+ case PROJECTILE_NADE_BURN: return NADE_TYPE_NORMAL;
+ case PROJECTILE_NADE_NAPALM:
+ case PROJECTILE_NADE_NAPALM_BURN: return NADE_TYPE_NAPALM;
+ case PROJECTILE_NADE_ICE:
+ case PROJECTILE_NADE_ICE_BURN: return NADE_TYPE_ICE;
+ case PROJECTILE_NADE_TRANSLOCATE: return NADE_TYPE_TRANSLOCATE;
+ case PROJECTILE_NADE_SPAWN: return NADE_TYPE_SPAWN;
+ case PROJECTILE_NADE_HEAL:
+ case PROJECTILE_NADE_HEAL_BURN: return NADE_TYPE_HEAL;
+ case PROJECTILE_NADE_MONSTER:
+ case PROJECTILE_NADE_MONSTER_BURN: return NADE_TYPE_MONSTER;
+ }
+
+ return 0;
+}
+
+float Nade_ProjectileFromID(float proj, float burn)
+{
+ switch(proj)
+ {
+ case NADE_TYPE_NORMAL: return (burn) ? PROJECTILE_NADE_BURN : PROJECTILE_NADE;
+ case NADE_TYPE_NAPALM: return (burn) ? PROJECTILE_NADE_NAPALM_BURN : PROJECTILE_NADE_NAPALM;
+ case NADE_TYPE_ICE: return (burn) ? PROJECTILE_NADE_ICE_BURN : PROJECTILE_NADE_ICE;
+ case NADE_TYPE_TRANSLOCATE: return PROJECTILE_NADE_TRANSLOCATE;
+ case NADE_TYPE_SPAWN: return PROJECTILE_NADE_SPAWN;
+ case NADE_TYPE_HEAL: return (burn) ? PROJECTILE_NADE_HEAL_BURN : PROJECTILE_NADE_HEAL;
+ case NADE_TYPE_MONSTER: return (burn) ? PROJECTILE_NADE_MONSTER_BURN : PROJECTILE_NADE_MONSTER;
+ }
+
+ return 0;
+}
+
+string Nade_TrailEffect(float proj, float nade_team)
+{
+ switch(proj)
+ {
+ case PROJECTILE_NADE: return strcat("nade_", Static_Team_ColorName_Lower(nade_team));
+ case PROJECTILE_NADE_BURN: return strcat("nade_", Static_Team_ColorName_Lower(nade_team), "_burn");
+ case PROJECTILE_NADE_NAPALM: return "TR_ROCKET";
+ case PROJECTILE_NADE_NAPALM_BURN: return "spiderbot_rocket_thrust";
+ case PROJECTILE_NADE_ICE: return "TR_NEXUIZPLASMA";
+ case PROJECTILE_NADE_ICE_BURN: return "wakizashi_rocket_thrust";
+ case PROJECTILE_NADE_TRANSLOCATE: return "TR_CRYLINKPLASMA";
+ case PROJECTILE_NADE_SPAWN: return "nade_yellow";
+ case PROJECTILE_NADE_HEAL: return "nade_red";
+ case PROJECTILE_NADE_HEAL_BURN: return "nade_red_burn";
+ case PROJECTILE_NADE_MONSTER: return "nade_red";
+ case PROJECTILE_NADE_MONSTER_BURN: return "nade_red_burn";
+ }
+
+ return "";
+}
+
+#ifdef CSQC
+// misc functions
+void ent_healer();
+#endif // CSQC
#define RECURSE_FROM_CHOICE(ent,action) \
if(notif.nent_challow_var && (warmup_stage || (notif.nent_challow_var == 2))) \
{ \
- switch(ent.msg_choice_choices[net_name]) \
+ switch(ent.msg_choice_choices[net_name - 1]) \
{ \
case 1: found_choice = notif.nent_optiona; break; \
case 2: found_choice = notif.nent_optionb; break; \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FIRE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"), _("^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s")) \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_LAVA, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_lava", _("^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_MONSTER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was pushed infront of a monster by ^BG%s^K1%s%s"), "") \
- MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_NAPALM, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_napalm", _("^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"), _("^BG%s%s^K1 got too close to a napalm explosion%s%s")) \
+ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_ICE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_ice", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_ICE_FREEZE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_ice", _("^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_HEAL, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_heal", _("^BG%s%s^K1 has not been healed by ^BG%s^K1's Healing Nade%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SHOOTING_STAR, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_shootingstar", _("^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SLIME, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was slimed by ^BG%s^K1%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SWAMP, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was preserved by ^BG%s^K1%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_GUN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_ROCKET, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VENGEANCE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was destroyed by the vengeful ^BG%s^K1%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VOID, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_void", _("^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_AUTOTEAMCHANGE, 2, 1, "s1 s2loc death_team", "", "", _("^BG%s^K1 was moved into the %s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_BETRAYAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_teamkill_red", _("^BG%s^K1 became enemies with the Lord of Teamplay%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_FIRE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 became a bit too crispy%s%s"), _("^BG%s^K1 felt a little hot%s%s")) \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_GENERIC, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 died%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_LAVA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_lava", _("^BG%s^K1 turned into hot slag%s%s"), _("^BG%s^K1 found a hot place%s%s")) \
- MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_MAGE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was exploded by a Mage%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_SHAMBLER_CLAW, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1's innards became outwards by a Shambler%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_SHAMBLER_SMASH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was smashed by a Shambler%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_WYVERN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was fireballed by a Wyvern%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 joins the Zombies%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_ZOMBIE_MELEE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was given kung fu lessons by a Zombie%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_NAPALM, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_napalm", _("^BG%s^K1 was burned to death by their own Napalm Nade%s%s"), _("^BG%s^K1 decided to take a look at the results of their napalm explosion%s%s")) \
+ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_ICE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_ice", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_ICE_FREEZE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_ice", _("^BG%s^K1 was frozen to death by their own Ice Nade%s%s"), _("^BG%s^K1 felt a little chilly%s%s")) \
+ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_HEAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_heal", _("^BG%s^K1's Healing Nade didn't quite heal them%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NOAMMO, 2, 1, "s1 s2loc spree_lost", "s1", "notify_outofammo", _("^BG%s^K1 died%s%s. What's the point of living without ammo?"), _("^BG%s^K1 ran out of ammo%s%s")) \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_ROT, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 rotted away%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SHOOTING_STAR, 2, 1, "s1 s2loc spree_lost", "s1", "notify_shootingstar", _("^BG%s^K1 became a shooting star%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_WAKI_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VOID, 2, 1, "s1 s2loc spree_lost", "s1", "notify_void", _("^BG%s^K1 was in the wrong place%s%s"), "") \
MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_DOMINATION_CAPTURE_TIME, 2, 2, "s1 s2 f1 f2", "", "", _("^BG%s^BG%s^BG (%s points every %s seconds)"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_FREEZE, 2, 0, "s1 s2", "", "", _("^BG%s^K1 was frozen by ^BG%s"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED, 2, 0, "s1 s2", "", "", _("^BG%s^K3 was revived by ^BG%s"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED_FALL, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by falling"), "") \
+ MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED_NADE, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by their Nade explosion"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_AUTO_REVIVED, 1, 1, "s1 f1", "", "", _("^BG%s^K3 was automatically revived after %s second(s)"), "") \
MULTITEAM_INFO(1, INFO_ROUND_TEAM_WIN_, 4, 0, 0, "", "", "", _("^TC^TT^BG team wins the round"), "") \
MSG_INFO_NOTIF(1, INFO_ROUND_PLAYER_WIN, 1, 0, "s1", "", "", _("^BG%s^BG wins the round"), "") \
MSG_INFO_NOTIF(1, INFO_ROUND_OVER, 0, 0, "", "", "", _("^BGRound over, there's no winner"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_SELF, 1, 0, "s1", "", "", _("^BG%s^K1 froze themself"), "") \
MSG_INFO_NOTIF(1, INFO_GODMODE_OFF, 0, 1, "f1", "", "", _("^BGGodmode saved you %s units of damage, cheater!"), "") \
+ MSG_INFO_NOTIF(1, INFO_ITEM_BUFF, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG got the %s^BG Buff!"), "") \
+ MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_LOST, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG lost the %s^BG Buff!"), "") \
+ MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_DROP, 0, 1, "item_buffname", "", "", _("^BGYou dropped the %s^BG Buff!"), "") \
+ MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_GOT, 0, 1, "item_buffname", "", "", _("^BGYou got the %s^BG Buff!"), "") \
MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", "", "", _("^BGYou do not have the ^F1%s"), "") \
MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", "", "", _("^BGYou dropped the ^F1%s^BG%s"), "") \
MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_GOT, 0, 1, "item_wepname", "", "", _("^BGYou got the ^F1%s"), "") \
MSG_INFO_NOTIF(1, INFO_RACE_NEW_SET, 1, 2, "s1 race_col f1ord race_col f2race_time", "s1 f2race_time", "race_newrecordserver", _("^BG%s^BG set the %s%s^BG place record with %s%s"), "") \
MULTITEAM_INFO(1, INFO_SCORES_, 4, 0, 0, "", "", "", _("^TC^TT ^BGteam scores!"), "") \
MSG_INFO_NOTIF(1, INFO_SPECTATE_WARNING, 0, 1, "f1secs", "", "", _("^F2You have to become a player within the next %s, otherwise you will be kicked, because spectating isn't allowed at this time!"), "") \
- MSG_INFO_NOTIF(1, INFO_SUPERWEAPON_PICKUP, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up a Superweapon"), "") \
+ MSG_INFO_NOTIF(1, INFO_SUPERWEAPON_PICKUP, 1, 0, "s1", "s1", "superweapons", _("^BG%s^K1 picked up a Superweapon"), "") \
+ MSG_INFO_NOTIF(1, INFO_TEAMCHANGE_LARGERTEAM, 0, 0, "", "", "", _("^BGYou cannot change to a larger team"), "") \
+ MSG_INFO_NOTIF(1, INFO_TEAMCHANGE_NOTALLOWED, 0, 0, "", "", "", _("^BGYou are not allowed to change teams"), "") \
MSG_INFO_NOTIF(2, INFO_VERSION_BETA, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s"), "") \
MSG_INFO_NOTIF(2, INFO_VERSION_OLD, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"), "") \
MSG_INFO_NOTIF(2, INFO_VERSION_OUTDATED, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get the update from ^F3http://www.xonotic.org/^BG!"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, 1, 4, "spree_cen s1 frag_stats", NO_CPID, "0 0", _("^K1%sYou were typefragged by ^BG%s^BG%s"), _("^K1%sYou were scored against by ^BG%s^K1 while typing^BG%s")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, 1, 2, "spree_cen s1 frag_ping", NO_CPID, "0 0", _("^K1%sYou typefragged ^BG%s^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing^BG%s")) \
MSG_CENTER_NOTIF(1, CENTER_NADE_THROW, 0, 0, "", CPID_NADES, "0 0", _("^BGPress ^F2DROPWEAPON^BG again to toss the nade!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_NADE_BONUS, 0, 0, "", CPID_NADES, "0 0", _("^F2You got a ^K1BONUS GRENADE^F2!"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_AUTOTEAMCHANGE, 0, 1, "death_team", NO_CPID, "0 0", _("^BGYou have been moved into a different team\nYou are now on: %s"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_BETRAYAL, 0, 0, "", NO_CPID, "0 0", _("^K1Don't shoot your team mates!"), _("^K1Don't go against your team mates!")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_CAMP, 0, 0, "", NO_CPID, "0 0", _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_LAVA, 0, 0, "", NO_CPID, "0 0", _("^K1You couldn't stand the heat!"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_MONSTER, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed by a monster!"), _("^K1You need to watch out for monsters!")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE, 0, 0, "", NO_CPID, "0 0", _("^K1You forgot to put the pin back in!"), _("^K1Tastes like chicken!")) \
+ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_NAPALM, 0, 0, "", NO_CPID, "0 0", _("^K1Hanging around a napalm explosion is bad!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_ICE_FREEZE, 0, 0, "", NO_CPID, "0 0", _("^K1You got a little bit too cold!"), _("^K1You felt a little chilly!")) \
+ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_HEAL, 0, 0, "", NO_CPID, "0 0", _("^K1Your Healing Nade is a bit defective"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NOAMMO, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed for running out of ammo..."), _("^K1You are respawning for running out of ammo...")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_ROT, 0, 0, "", NO_CPID, "0 0", _("^K1You grew too old without taking your medicine"), _("^K1You need to preserve your health")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SHOOTING_STAR, 0, 0, "", NO_CPID, "0 0", _("^K1You became a shooting star!"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAG, 1, 0, "s1", NO_CPID, "0 0", _("^K1Moron! You fragged ^BG%s^K1, a team mate!"), _("^K1Moron! You went against ^BG%s^K1, a team mate!")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAGGED, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were fragged by ^BG%s^K1, a team mate"), _("^K1You were scored against by ^BG%s^K1, a team mate")) \
MSG_CENTER_NOTIF(1, CENTER_DISCONNECT_IDLING, 0, 1, "", CPID_IDLING, "1 f1", _("^K1Stop idling!\n^BGDisconnecting in ^COUNT..."), "") \
+ MSG_CENTER_NOTIF(1, CENTER_DOOR_LOCKED_NEED, 0, 0, "", NO_CPID, "0 0", _("^BGYou need %s^BG!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_DOOR_LOCKED_ALSONEED, 0, 0, "", NO_CPID, "0 0", _("^BGYou also need %s^BG!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_DOOR_UNLOCKED, 0, 0, "", NO_CPID, "0 0", _("^BGDoor unlocked!"), "") \
MSG_CENTER_NOTIF(1, CENTER_EXTRALIVES, 0, 0, "", NO_CPID, "0 0", _("^F2You picked up some extra lives"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FREEZE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You froze ^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FROZEN, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were frozen by ^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You revived ^BG%s"), "") \
- MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_FALL, 0, 0, "", NO_CPID, "0 0", _("^K3You revived yourself"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_SELF, 0, 0, "", NO_CPID, "0 0", _("^K3You revived yourself"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVED, 1, 0, "s1", NO_CPID, "0 0", _("^K3You were revived by ^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_AUTO_REVIVED, 0, 1, "f1", NO_CPID, "0 0", _("^K3You were automatically revived after %s second(s)"), "") \
MULTITEAM_CENTER(1, CENTER_ROUND_TEAM_WIN_, 4, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team wins the round"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SELF, 0, 0, "", NO_CPID, "0 0", _("^K1You froze yourself"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SPAWN_LATE, 0, 0, "", NO_CPID, "0 0", _("^K1Round already started, you spawn as frozen"), "") \
MSG_CENTER_NOTIF(1, CENTER_INVASION_SUPERMONSTER, 1, 0, "s1", NO_CPID, "0 0", _("^K1A %s has arrived!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_ITEM_BUFF_DROP, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou dropped the %s^BG Buff!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_ITEM_BUFF_GOT, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou got the %s^BG Buff!"), "") \
MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_GOT, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERUP_SPEED, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You are on speed"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERUP_STRENGTH, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Strength infuses your weapons with devastating power"), "") \
MSG_CENTER_NOTIF(1, CENTER_RACE_FINISHLAP, 0, 0, "", CPID_RACE_FINISHLAP, "0 0", _("^F2The race is over, finish your lap!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_SEQUENCE_COMPLETED, 0, 0, "", NO_CPID, "0 0", _("^BGSequence completed!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_SEQUENCE_COUNTER, 0, 0, "", NO_CPID, "0 0", _("^BGThere are more to go..."), "") \
+ MSG_CENTER_NOTIF(1, CENTER_SEQUENCE_COUNTER_FEWMORE, 0, 1, "f1", NO_CPID, "0 0", _("^BGOnly %s^BG more to go..."), "") \
MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_BROKEN, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have broken down"), "") \
MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_LOST, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have been lost"), "") \
MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_PICKUP, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You now have a superweapon"), "") \
MSG_MULTI_NOTIF(1, DEATH_MURDER_LAVA, NO_MSG, INFO_DEATH_MURDER_LAVA, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_MONSTER, NO_MSG, INFO_DEATH_MURDER_MONSTER, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE, NO_MSG, INFO_DEATH_MURDER_NADE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_NAPALM, NO_MSG, INFO_DEATH_MURDER_NADE_NAPALM, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_ICE, NO_MSG, INFO_DEATH_MURDER_NADE_ICE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_ICE_FREEZE, NO_MSG, INFO_DEATH_MURDER_NADE_ICE_FREEZE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_HEAL, NO_MSG, INFO_DEATH_MURDER_NADE_HEAL, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_SHOOTING_STAR, NO_MSG, INFO_DEATH_MURDER_SHOOTING_STAR, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_SLIME, NO_MSG, INFO_DEATH_MURDER_SLIME, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_SWAMP, NO_MSG, INFO_DEATH_MURDER_SWAMP, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_DEATH, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_GUN, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_GUN, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VENGEANCE, NO_MSG, INFO_DEATH_MURDER_VENGEANCE, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_MURDER_VOID, NO_MSG, INFO_DEATH_MURDER_VOID, NO_MSG) \
MSG_MULTI_NOTIF(1, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
MSG_MULTI_NOTIF(1, DEATH_SELF_BETRAYAL, NO_MSG, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_ZOMBIE_JUMP, NO_MSG, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_ZOMBIE_MELEE, NO_MSG, INFO_DEATH_SELF_MON_ZOMBIE_MELEE, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_NADE, NO_MSG, INFO_DEATH_SELF_NADE, CENTER_DEATH_SELF_NADE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_NAPALM, NO_MSG, INFO_DEATH_SELF_NADE_NAPALM, CENTER_DEATH_SELF_NADE_NAPALM) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_ICE, NO_MSG, INFO_DEATH_SELF_NADE_ICE, CENTER_DEATH_SELF_NADE_ICE_FREEZE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_ICE_FREEZE, NO_MSG, INFO_DEATH_SELF_NADE_ICE_FREEZE, CENTER_DEATH_SELF_NADE_ICE_FREEZE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_HEAL, NO_MSG, INFO_DEATH_SELF_NADE_HEAL, CENTER_DEATH_SELF_NADE_HEAL) \
MSG_MULTI_NOTIF(1, DEATH_SELF_NOAMMO, NO_MSG, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \
MSG_MULTI_NOTIF(1, DEATH_SELF_ROT, NO_MSG, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \
MSG_MULTI_NOTIF(1, DEATH_SELF_SHOOTING_STAR, NO_MSG, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \
MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_SELF_VH_WAKI_DEATH, CENTER_DEATH_SELF_VH_WAKI_DEATH) \
MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_SELF_VH_WAKI_ROCKET, CENTER_DEATH_SELF_VH_WAKI_ROCKET) \
MSG_MULTI_NOTIF(1, DEATH_SELF_VOID, NO_MSG, INFO_DEATH_SELF_VOID, CENTER_DEATH_SELF_VOID) \
+ MSG_MULTI_NOTIF(1, ITEM_BUFF_DROP, NO_MSG, INFO_ITEM_BUFF_DROP, CENTER_ITEM_BUFF_DROP) \
+ MSG_MULTI_NOTIF(1, ITEM_BUFF_GOT, NO_MSG, INFO_ITEM_BUFF_GOT, CENTER_ITEM_BUFF_GOT) \
MSG_MULTI_NOTIF(1, ITEM_WEAPON_DONTHAVE, NO_MSG, INFO_ITEM_WEAPON_DONTHAVE, CENTER_ITEM_WEAPON_DONTHAVE) \
MSG_MULTI_NOTIF(1, ITEM_WEAPON_DROP, NO_MSG, INFO_ITEM_WEAPON_DROP, CENTER_ITEM_WEAPON_DROP) \
MSG_MULTI_NOTIF(1, ITEM_WEAPON_GOT, NO_MSG, INFO_ITEM_WEAPON_GOT, CENTER_ITEM_WEAPON_GOT) \
item_wepname: return full name of a weapon from weaponid
item_wepammo: ammo display for weapon from string
item_centime: amount of time to display weapon message in centerprint
+ item_buffname: return full name of a buff from buffid
death_team: show the full name of the team a player is switching from
*/
ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
ARG_CASE(ARG_CS_SV, "item_wepname", W_Name(f1)) \
+ ARG_CASE(ARG_CS_SV, "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buff_Color(f1)), Buff_PrettyName(f1))) \
ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \
ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \
#endif
printf("Beginning notification initialization on %s%s program...\n", dedi, PROGNAME);
+ #undef dedi
// maybe do another implementation of this with checksums? for now, we don't need versioning
/*if(autocvar_notification_version != NOTIF_VERSION)
--- /dev/null
+// Full list of all stat constants, icnluded in a single location for easy reference
+// 255 is the current limit (MAX_CL_STATS - 1), engine will need to be modified if you wish to add more stats
+
+const float MAX_CL_STATS = 256;
+const float STAT_HEALTH = 0;
+// 1 empty?
+const float STAT_WEAPON = 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;
+// 17 empty?
+// 18 empty?
+// 19 empty?
+// 20 empty?
+const float STAT_VIEWZOOM = 21;
+// 22 empty?
+// 23 empty?
+// 24 empty?
+// 25 empty?
+// 26 empty?
+// 27 empty?
+// 28 empty?
+// 29 empty?
+// 30 empty?
+// 31 empty?
+const float STAT_KH_KEYS = 32;
+const float STAT_CTF_STATE = 33;
+// 34 empty?
+const float STAT_WEAPONS = 35;
+const float STAT_SWITCHWEAPON = 36;
+const float STAT_GAMESTARTTIME = 37;
+const float STAT_STRENGTH_FINISHED = 38;
+const float STAT_INVINCIBLE_FINISHED = 39;
+// 40 empty?
+// 41 empty?
+const float STAT_PRESSED_KEYS = 42;
+const float STAT_ALLOW_OLDNEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config
+const float STAT_FUEL = 44;
+const float STAT_NB_METERSTART = 45;
+const float STAT_SHOTORG = 46; // compressShotOrigin
+const float STAT_LEADLIMIT = 47;
+const float STAT_WEAPON_CLIPLOAD = 48;
+const float STAT_WEAPON_CLIPSIZE = 49;
+const float STAT_NEX_CHARGE = 50;
+const float STAT_LAST_PICKUP = 51;
+const float STAT_HUD = 52;
+const float STAT_NEX_CHARGEPOOL = 53;
+const float STAT_HIT_TIME = 54;
+const float STAT_TYPEHIT_TIME = 55;
+const float STAT_LAYED_MINES = 56;
+const float STAT_HAGAR_LOAD = 57;
+const float STAT_SWITCHINGWEAPON = 58;
+const float STAT_SUPERWEAPONS_FINISHED = 59;
+const float STAT_VEHICLESTAT_HEALTH = 60;
+const float STAT_VEHICLESTAT_SHIELD = 61;
+const float STAT_VEHICLESTAT_ENERGY = 62;
+const float STAT_VEHICLESTAT_AMMO1 = 63;
+const float STAT_VEHICLESTAT_RELOAD1 = 64;
+const float STAT_VEHICLESTAT_AMMO2 = 65;
+const float STAT_VEHICLESTAT_RELOAD2 = 66;
+const float STAT_VEHICLESTAT_W2MODE = 67;
+// 68 empty?
+const float STAT_NADE_TIMER = 69;
+const float STAT_SECRETS_TOTAL = 70;
+const float STAT_SECRETS_FOUND = 71;
+const float STAT_RESPAWN_TIME = 72;
+const float STAT_ROUNDSTARTTIME = 73;
+const float STAT_WEAPONS2 = 74;
+const float STAT_WEAPONS3 = 75;
+const float STAT_MONSTERS_TOTAL = 76;
+const float STAT_MONSTERS_KILLED = 77;
+const float STAT_BUFFS = 78;
+const float STAT_NADE_BONUS = 79;
+const float STAT_NADE_BONUS_TYPE = 80;
+const float STAT_NADE_BONUS_SCORE = 81;
+const float STAT_HEALING_ORB = 82;
+const float STAT_HEALING_ORB_ALPHA = 83;
+const float STAT_CTF_FLAGSTATUS = 84;
+// 85 empty?
+// 86 empty?
+// 87 empty?
+// 88 empty?
+// 89 empty?
+// 90 empty?
+// 91 empty?
+// 92 empty?
+// 93 empty?
+// 94 empty?
+// 95 empty?
+// 96 empty?
+// 97 empty?
+// 98 empty?
+// 99 empty?
+
+
+/* The following stats change depending on the gamemode, so can share the same ID */
+// IDs 100 to 104 reserved for gamemodes
+
+// freeze tag, clan arena, jailbreak
+const float STAT_REDALIVE = 100;
+const float STAT_BLUEALIVE = 101;
+const float STAT_YELLOWALIVE = 102;
+const float STAT_PINKALIVE = 103;
+
+// domination
+const float STAT_DOM_TOTAL_PPS = 100;
+const float STAT_DOM_PPS_RED = 101;
+const float STAT_DOM_PPS_BLUE = 102;
+const float STAT_DOM_PPS_YELLOW = 103;
+const float STAT_DOM_PPS_PINK = 104;
+
+// vip
+const float STAT_VIP = 100;
+const float STAT_VIP_RED = 101;
+const float STAT_VIP_BLUE = 102;
+const float STAT_VIP_YELLOW = 103;
+const float STAT_VIP_PINK = 104;
+
+// key hunt
+const float STAT_KH_REDKEY_TEAM = 100;
+const float STAT_KH_BLUEKEY_TEAM = 101;
+const float STAT_KH_YELLOWKEY_TEAM = 102;
+const float STAT_KH_PINKKEY_TEAM = 103;
+
+/* Gamemode-specific stats end here */
+
+
+const float STAT_FROZEN = 105;
+const float 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?
+// 120 empty?
+// 121 empty?
+// 122 empty?
+// 123 empty?
+// 124 empty?
+// 125 empty?
+// 126 empty?
+// 127 empty?
+// 128 empty?
+// 129 empty?
+// 130 empty?
+// 131 empty?
+// 132 empty?
+// 133 empty?
+// 134 empty?
+// 135 empty?
+// 136 empty?
+// 137 empty?
+// 138 empty?
+// 139 empty?
+// 140 empty?
+// 141 empty?
+// 142 empty?
+// 143 empty?
+// 144 empty?
+// 145 empty?
+// 146 empty?
+// 147 empty?
+// 148 empty?
+// 149 empty?
+// 150 empty?
+// 151 empty?
+// 152 empty?
+// 153 empty?
+// 154 empty?
+// 155 empty?
+// 156 empty?
+// 157 empty?
+// 158 empty?
+// 159 empty?
+// 160 empty?
+// 161 empty?
+// 162 empty?
+// 162 empty?
+// 163 empty?
+// 164 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 float STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220;
+const float STAT_MOVEVARS_AIRCONTROL_PENALTY = 221;
+const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222;
+const float STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223;
+const float STAT_MOVEVARS_AIRCONTROL_POWER = 224;
+const float STAT_MOVEFLAGS = 225;
+const float STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL = 226;
+const float STAT_MOVEVARS_WARSOWBUNNY_ACCEL = 227;
+const float STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED = 228;
+const float STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL = 229;
+const float STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO = 230;
+const float STAT_MOVEVARS_AIRSTOPACCELERATE = 231;
+const float STAT_MOVEVARS_AIRSTRAFEACCELERATE = 232;
+const float STAT_MOVEVARS_MAXAIRSTRAFESPEED = 233;
+const float STAT_MOVEVARS_AIRCONTROL = 234;
+const float STAT_FRAGLIMIT = 235;
+const float STAT_TIMELIMIT = 236;
+const float STAT_MOVEVARS_WALLFRICTION = 237;
+const float STAT_MOVEVARS_FRICTION = 238;
+const float STAT_MOVEVARS_WATERFRICTION = 239;
+const float STAT_MOVEVARS_TICRATE = 240;
+const float STAT_MOVEVARS_TIMESCALE = 241;
+const float STAT_MOVEVARS_GRAVITY = 242;
+const float STAT_MOVEVARS_STOPSPEED = 243;
+const float STAT_MOVEVARS_MAXSPEED = 244;
+const float STAT_MOVEVARS_SPECTATORMAXSPEED = 245;
+const float STAT_MOVEVARS_ACCELERATE = 246;
+const float STAT_MOVEVARS_AIRACCELERATE = 247;
+const float STAT_MOVEVARS_WATERACCELERATE = 248;
+const float STAT_MOVEVARS_ENTGRAVITY = 249;
+const float STAT_MOVEVARS_JUMPVELOCITY = 250;
+const float STAT_MOVEVARS_EDGEFRICTION = 251;
+const float STAT_MOVEVARS_MAXAIRSPEED = 252;
+const float STAT_MOVEVARS_STEPHEIGHT = 253;
+const float STAT_MOVEVARS_AIRACCEL_QW = 254;
+const float STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION = 255;
#ifndef NOCOMPAT
//# define WORKAROUND_XON010
-//# define COMPAT_XON010_CHANNELS
//# define COMPAT_XON050_ENGINE
# define COMPAT_NO_MOD_IS_XONOTIC
# define COMPAT_XON060_DONTCRASH_CHECKPVS
get_model_parameters_weight = stof(s);
if(c == "age")
get_model_parameters_age = stof(s);
+ if(c == "description")
+ get_model_parameters_description = s;
if(c == "bone_upperbody")
get_model_parameters_bone_upperbody = s;
if(c == "bone_weapon")
string get_model_parameters_sex;
float get_model_parameters_weight;
float get_model_parameters_age;
+string get_model_parameters_description;
string get_model_parameters_bone_upperbody;
string get_model_parameters_bone_weapon;
#define MAX_AIM_BONES 4
string xencode(float f);
float xdecode(string s);
-#ifndef COMPAT_XON010_CHANNELS
+// Play all sounds via sound7, for access to the extra channels.
+// 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)
-#endif
float lowestbit(float f);
#include "xonotic/dialog_hudpanel_weapons.c"
#include "xonotic/dialog_hudpanel_physics.c"
#include "xonotic/dialog_hudpanel_centerprint.c"
+#include "xonotic/dialog_hudpanel_buffs.c"
#include "xonotic/slider_picmip.c"
+#include "xonotic/slider_particles.c"
METHOD(Container, moveItemAfter, void(entity, entity, entity))
METHOD(Container, removeItem, void(entity, entity))
METHOD(Container, setFocus, void(entity, entity))
+ METHOD(Container, saveFocus, void(entity))
METHOD(Container, setAlphaOf, void(entity, entity, float))
METHOD(Container, itemFromPoint, entity(entity, vector))
METHOD(Container, showNotify, void(entity))
ATTRIB(Container, firstChild, entity, NULL)
ATTRIB(Container, lastChild, entity, NULL)
ATTRIB(Container, focusedChild, entity, NULL)
+ ATTRIB(Container, savedFocus, entity, NULL)
ATTRIB(Container, shown, float, 0)
METHOD(Container, enterSubitem, void(entity, entity))
void Container_setFocus(entity me, entity other)
{
- if(other)
- if (!me.focused)
- error("Trying to set focus in a non-focused control!");
if(me.focusedChild == other)
return;
- //print(etos(me), ": focus changes from ", etos(me.focusedChild), " to ", etos(other), "\n");
+
if(me.focusedChild)
{
me.focusedChild.focused = 0;
me.focusedChild.focusLeave(me.focusedChild);
+ me.focusedChild = NULL;
}
+
if(other)
{
- other.focused = 1;
- other.focusEnter(other);
+ if(!me.focused)
+ error("Trying to set focus in a non-focused control!");
+
+ if(me.savedFocus)
+ {
+ me.focusedChild = me.savedFocus;
+ me.savedFocus = NULL;
+ me.focusedChild.focused = 1;
+ me.focusedChild.focusEnter(me.focusedChild);
+
+ if(me.focusedChild.instanceOfContainer)
+ me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+ }
+ else
+ {
+ me.focusedChild = other;
+ me.focusedChild.focused = 1;
+ me.focusedChild.focusEnter(me.focusedChild);
+ }
}
- me.focusedChild = other;
+}
+
+void Container_saveFocus(entity me)
+{
+ me.savedFocus = me.focusedChild;
+
+ if(me.focusedChild.instanceOfContainer)
+ me.focusedChild.saveFocus(me.focusedChild);
}
void Container_moveItemAfter(entity me, entity other, entity dest)
ATTRIB(Label, realFontSize, vector, '0 0 0')
ATTRIB(Label, realOrigin, vector, '0 0 0')
ATTRIB(Label, alpha, float, 0.7)
- ATTRIB(Label, colorL, vector, '1 1 1')
+ ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT)
ATTRIB(Label, disabled, float, 0)
ATTRIB(Label, disabledAlpha, float, 0.3)
ATTRIB(Label, textEntity, entity, NULL)
return;
if(button)
button.forcePressed = 1;
+ if(tab.parent.focusedChild)
+ tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
tab.ModalController_controllingButton = button;
tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
}
while(getWrappedLine_remaining)
{
s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
- draw_Text(p, s, fontsize, '1 1 1', SKINALPHA_TOOLTIP * menuTooltipAlpha, FALSE);
+ draw_Text(p, s, fontsize, SKINCOLOR_TOOLTIP, SKINALPHA_TOOLTIP * menuTooltipAlpha, FALSE);
p_y += fontsize_y;
}
}
SKINSTRING(GFX_TOOLTIP, "tooltip");
SKINVECTOR(MARGIN_TOOLTIP, '5 5 0');
SKINVECTOR(BORDER_TOOLTIP, '1 1 0');
+ SKINVECTOR(AVOID_TOOLTIP, '8 8 0');
+ SKINFLOAT(WIDTH_TOOLTIP, 0.3);
SKINFLOAT(FONTSIZE_TOOLTIP, 12);
SKINFLOAT(ALPHA_TOOLTIP, 0.7);
- SKINFLOAT(WIDTH_TOOLTIP, 0.3);
- SKINVECTOR(AVOID_TOOLTIP, '8 8 0');
+ SKINVECTOR(COLOR_TOOLTIP, '1 1 1');
// the individual dialog background colors
SKINVECTOR(COLOR_DIALOG_FIRSTRUN, '0.7 0.7 1');
SKINFLOAT(ALPHA_DISABLED, 0.2);
SKINFLOAT(ALPHA_BEHIND, 0.5);
SKINFLOAT(ALPHA_TEXT, 0.7);
-
+ SKINVECTOR(COLOR_TEXT, '1 1 1');
+
// item: button
SKINSTRING(GFX_BUTTON, "button");
SKINSTRING(GFX_BUTTON_GRAY, "buttongray");
// item: player color button
SKINSTRING(GFX_COLORBUTTON, "colorbutton");
- SKINSTRING(GFX_COLORBUTTON_COLOR, "color");
// item: player model
SKINVECTOR(COLOR_MODELTITLE, '1 1 1');
SKINFLOAT(WIDTH_SCROLLBAR, 16);
// item: server list
+ SKINFLOAT(ALPHA_SERVERLIST_CATEGORY, 0.7);
+ SKINVECTOR(COLOR_SERVERLIST_CATEGORY, '1 1 1');
SKINFLOAT(ALPHA_SERVERLIST_FULL, 0.4);
SKINFLOAT(ALPHA_SERVERLIST_EMPTY, 0.7);
SKINVECTOR(COLOR_SERVERLIST_LOWPING, '0 1 0');
METHOD(XonoticColorButton, configureXonoticColorButton, void(entity, float, float, float))
METHOD(XonoticColorButton, setChecked, void(entity, float))
METHOD(XonoticColorButton, draw, void(entity))
- ATTRIB(XonoticColorButton, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(XonoticColorButton, fontSize, float, 0)
ATTRIB(XonoticColorButton, image, string, SKINGFX_COLORBUTTON)
- ATTRIB(XonoticColorButton, image2, string, SKINGFX_COLORBUTTON_COLOR)
ATTRIB(XonoticColorButton, useDownAsChecked, float, 1)
me.cvarPart = theColor;
me.loadCvars(me);
me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
- me.srcMulti = 1;
- me.src2 = me.image2;
}
void XonoticColorButton_setChecked(entity me, float val)
{
}
void XonoticColorButton_draw(entity me)
{
- me.color2 = colormapPaletteColor(me.cvarValueFloat, me.cvarPart);
+ me.color = colormapPaletteColor(me.cvarValueFloat, me.cvarPart);
+ me.colorC = me.color;
+ me.colorF = me.color;
+ me.colorD = me.color;
SUPER(XonoticColorButton).draw(me);
}
#endif
s = me.demoName(me,i);
s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
- draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+ draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
}
void XonoticDemoList_showNotify(entity me)
--- /dev/null
+#ifdef INTERFACE
+CLASS(XonoticHUDBuffsDialog) EXTENDS(XonoticRootDialog)
+ METHOD(XonoticHUDBuffsDialog, fill, void(entity))
+ ATTRIB(XonoticHUDBuffsDialog, title, string, _("Buffs Panel"))
+ ATTRIB(XonoticHUDBuffsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+ ATTRIB(XonoticHUDBuffsDialog, intendedWidth, float, 0.4)
+ ATTRIB(XonoticHUDBuffsDialog, rows, float, 15)
+ ATTRIB(XonoticHUDBuffsDialog, columns, float, 4)
+ ATTRIB(XonoticHUDBuffsDialog, name, string, "HUDbuffs")
+ ATTRIB(XonoticHUDBuffsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDBuffsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDBuffsDialog_fill(entity me)
+{
+ entity e;
+ string panelname = "buffs";
+
+ DIALOG_HUDPANEL_COMMON();
+}
+#endif
CLASS(XonoticServerCreateTab) EXTENDS(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, 22)
me.mapListBox.refilter(me.mapListBox);
}
+void XonoticServerCreateTab_gameTypeSelectNotify(entity me)
+{
+ me.setFocus(me, me.mapListBox);
+}
+
#endif
s = cvar_string("g_weaponarena");
if(s == "0")
return "";
- if(s == "all")
+ if(s == "all" || s == "1")
return _("All Weapons Arena");
if(s == "most")
return _("Most Weapons Arena");
return 0;
if(cvar_string("g_weaponarena") == "most")
return 1;
- if(cvar_string("g_weaponarena") == "all")
+ if(cvar_string("g_weaponarena") == "all" || cvar_string("g_weaponarena") == "1")
return 1;
if(cvar_string("g_weaponarena") != "0")
return 0;
return 0;
if(cvar_string("g_weaponarena") == "most")
return 0;
- if(cvar_string("g_weaponarena") == "all")
+ if(cvar_string("g_weaponarena") == "all" || cvar_string("g_weaponarena") == "1")
return 0;
if(cvar_string("g_weaponarena") == "0")
return 0;
if(cvar("developer"))
me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Ultimate")), '0.5 0 0', "exec effects-ultimate.cfg", 0));
- me.TR(me);
- me.TR(me);
+ me.gotoRC(me, 1.25, 0);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Geometry detail:")));
me.TD(me, 1, 2, e = makeXonoticTextSlider("r_subdivisions_tolerance"));
e.addValue(e, ZCTX(_("DET^Lowest")), "16");
e.configureXonoticTextSliderValues(e);
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Player detail:")));
- me.TD(me, 1, 2, e = makeXonoticSlider(4, 0, -0.1, "cl_playerdetailreduction"));
+ me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_playerdetailreduction"));
+ e.addValue(e, ZCTX(_("PDET^Low")), "4");
+ e.addValue(e, ZCTX(_("PDET^Medium")), "3");
+ e.addValue(e, ZCTX(_("PDET^Normal")), "2");
+ e.addValue(e, ZCTX(_("PDET^Good")), "1");
+ e.addValue(e, ZCTX(_("PDET^Best")), "0");
+ e.configureXonoticTextSliderValues(e);
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Texture resolution:")));
setDependent(e, "r_showsurfaces", 0, 0);
setDependentAND(e, "vid_gl20", 1, 1, "r_water", 1, 1);
me.TR(me);
me.TR(me);
- me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Particles quality:")));
- me.TD(me, 1, 2, e = makeXonoticSlider(0.2, 1.0, 0.1, "cl_particles_quality"));
- me.TR(me);
- me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Particles distance:")));
- me.TD(me, 1, 2, e = makeXonoticSlider(500, 2000, 100, "r_drawparticles_drawdistance"));
+ me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals")));
+ me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
+ setDependent(e, "cl_decals", 1, 1);
me.TR(me);
- me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Damage effects:")));
- me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_damageeffect"));
- e.addValue(e, ZCTX(_("DMGPRTCLS^Disabled")), "0");
- e.addValue(e, ZCTX(_("DMGPRTCLS^Skeletal")), "1");
- e.addValue(e, ZCTX(_("DMGPRTCLS^All")), "2");
- e.configureXonoticTextSliderValues(e);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
+ setDependent(e, "cl_decals", 1, 1);
+ me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance"));
+ setDependent(e, "cl_decals", 1, 1);
me.TR(me);
- me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Particle effects for spawnpoints")));
- makeMulti(e, "cl_spawn_event_particles");
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
+ setDependent(e, "cl_decals", 1, 1);
+ me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_fadetime"));
+ setDependent(e, "cl_decals", 1, 1);
- me.gotoRC(me, 2, 3.2); me.setFirstColumn(me, me.currentColumn);
+ me.gotoRC(me, 1.25, 3.2); me.setFirstColumn(me, me.currentColumn);
me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "r_coronas", "0", _("No dynamic lighting")));
me.TR(me);
me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "gl_flashblend", string_null, _("Fake corona lighting")));
me.TD(me, 1, 2, s);
me.TR(me);
me.TR(me);
- me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals")));
- me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
- setDependent(e, "cl_decals", 1, 1);
+ me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_particles", _("Particles")));
+ me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Spawnpoint effects")));
+ makeMulti(e, "cl_spawn_event_particles");
+ setDependent(e, "cl_particles", 1, 1);
me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
+ setDependent(e, "cl_particles", 1, 1);
+ me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
+ setDependent(e, "cl_particles", 1, 1);
+ me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
setDependent(e, "cl_decals", 1, 1);
me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance"));
setDependent(e, "cl_decals", 1, 1);
- me.TR(me);
+ me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
- setDependent(e, "cl_decals", 1, 1);
- me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_time"));
- setDependent(e, "cl_decals", 1, 1);
+ me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
+ setDependent(e, "cl_decals", 1, 1);
+ me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_fadetime"));
+ setDependent(e, "cl_decals", 1, 1);
me.gotoRC(me, me.rows - 1, 0);
me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "vid_restart", COMMANDBUTTON_APPLY));
METHOD(XonoticGametypeList, setSelected, void(entity, float))
METHOD(XonoticGametypeList, loadCvars, void(entity))
METHOD(XonoticGametypeList, saveCvars, void(entity))
+ METHOD(XonoticGametypeList, keyDown, float(entity, float, float, float))
ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0')
ATTRIB(XonoticGametypeList, realUpperMargin1, float, 0)
draw_Picture(me.columnIconOrigin * eX, GameType_GetIcon(i), me.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED);
s = GameType_GetName(i);
- draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.5 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+ draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.5 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
//s = GameType_GetTeams(i);
- //draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+ //draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
}
void XonoticGametypeList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize;
me.columnNameSize = 1 - me.columnIconSize - 2 * me.realFontSize_x;
}
+
+float XonoticGametypeList_keyDown(entity me, float scan, float ascii, float shift)
+{
+ if(scan == K_ENTER || scan == K_KP_ENTER)
+ {
+ me.parent.gameTypeSelectNotify(me.parent);
+ return 1;
+ }
+
+ return SUPER(XonoticGametypeList).keyDown(me, scan, ascii, shift);
+}
#endif
s = me.languageParameter(me, i, LANGPARM_NAME_LOCALIZED);
s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
- draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+ draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
p = me.languageParameter(me, i, LANGPARM_PERCENTAGE);
if(p != "")
{
p = draw_TextShortenToWidth(p, me.columnPercentageSize, 0, me.realFontSize);
- draw_Text(me.realUpperMargin * eY + (me.columnPercentageOrigin + (me.columnPercentageSize - draw_TextWidth(p, 0, me.realFontSize))) * eX, p, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+ draw_Text(me.realUpperMargin * eY + (me.columnPercentageOrigin + (me.columnPercentageSize - draw_TextWidth(p, 0, me.realFontSize))) * eX, p, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
}
}
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ i = spawnXonoticHUDBuffsDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
// dialogs used by settings
me.userbindEditDialog = i = spawnXonoticUserbindEditDialog();
void XonoticMapList_clickListBoxItem(entity me, float i, vector where)
{
if(where_x <= me.columnPreviewOrigin + me.columnPreviewSize)
- {
if(where_x >= 0)
me.g_maplistCacheToggle(me, i);
- }
+
if(where_x >= me.columnNameOrigin)
if(where_x <= 1)
- {
- if(i == me.lastClickedMap)
- if(time < me.lastClickedTime + 0.3)
- {
- // DOUBLE CLICK!
- // pop up map info screen
- main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, i, me);
- DialogOpenButton_Click_withCoords(NULL, main.mapInfoDialog, me.origin + eX * (me.columnNameOrigin * me.size_x) + eY * ((me.itemHeight * i - me.scrollPos) * me.size_y), eY * me.itemAbsSize_y + eX * (me.itemAbsSize_x * me.columnNameSize));
- return;
- }
- me.lastClickedMap = i;
- me.lastClickedTime = time;
- }
+ {
+ if(i == me.lastClickedMap)
+ if(time < me.lastClickedTime + 0.3)
+ {
+ // DOUBLE CLICK!
+ // pop up map info screen
+ main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, i, me);
+ DialogOpenButton_Click_withCoords(NULL, main.mapInfoDialog, me.origin + eX * (me.columnNameOrigin * me.size_x) + eY * ((me.itemHeight * i - me.scrollPos) * me.size_y), eY * me.itemAbsSize_y + eX * (me.itemAbsSize_x * me.columnNameSize));
+ return;
+ }
+ me.lastClickedMap = i;
+ me.lastClickedTime = time;
+ }
}
void XonoticMapList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
string ch, save;
if(me.nItems <= 0)
return SUPER(XonoticMapList).keyDown(me, scan, ascii, shift);
- if(scan == K_ENTER || scan == K_KP_ENTER)
+ if(scan == K_MOUSE2 || scan == K_SPACE || scan == K_ENTER || scan == K_KP_ENTER)
{
// pop up map info screen
main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, me.selectedItem, me);
DialogOpenButton_Click_withCoords(NULL, main.mapInfoDialog, me.origin + eX * (me.columnNameOrigin * me.size_x) + eY * ((me.itemHeight * me.selectedItem - me.scrollPos) * me.size_y), eY * me.itemAbsSize_y + eX * (me.itemAbsSize_x * me.columnNameSize));
}
- else if(scan == K_SPACE)
+ else if(scan == K_MOUSE3 || scan == K_INS || scan == K_KP_INS)
{
me.g_maplistCacheToggle(me, me.selectedItem);
}
else if(t == 4)
rgb = colormapPaletteColor(9, 0);
else
- rgb = '1 1 1';
+ rgb = SKINCOLOR_TEXT;
s = me.getPlayerList(me, i, PLAYERPARM_NAME);
score = me.getPlayerList(me, i, PLAYERPARM_SCORE);
METHOD(XonoticPlayerModelSelector, saveCvars, void(entity))
METHOD(XonoticPlayerModelSelector, draw, void(entity))
METHOD(XonoticPlayerModelSelector, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(XonoticPlayerModelSelector, showNotify, void(entity))
ATTRIB(XonoticPlayerModelSelector, currentModel, string, string_null)
ATTRIB(XonoticPlayerModelSelector, currentSkin, float, 0)
ATTRIB(XonoticPlayerModelSelector, currentModelImage, string, string_null)
#define BUFMODELS_DESC 4
#define BUFMODELS_COUNT 5
+#define XONVOTE186 1 // (nyov) removal of model text description
+
void XonoticPlayerModelSelector_configureXonoticPlayerModelSelector(entity me)
{
float sortbuf, glob, i;
bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_MODEL, get_model_parameters_modelname);
bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_SKIN, ftos(get_model_parameters_modelskin));
get_model_parameters_desc = strcat(get_model_parameters_desc, "\n");
+#if XONVOTE186
+ if(get_model_parameters_sex)
+ get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\n%s", get_model_parameters_sex));
+#else
+ if(get_model_parameters_description)
+ get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\n%s\n", get_model_parameters_description));
if(get_model_parameters_sex)
get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nSex: %s", get_model_parameters_sex));
if(get_model_parameters_weight)
get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nWeight: %g kg", get_model_parameters_weight));
if(get_model_parameters_age)
get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nAge: %g", get_model_parameters_age));
+#endif
while(substring(get_model_parameters_desc, -1, 1) == "\n")
get_model_parameters_desc = substring(get_model_parameters_desc, 0, -2);
bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_DESC, get_model_parameters_desc);
if (me.numModels <= 0)
{
- draw_CenterText('0.5 0.5 0', _("<no model found>"), me.realFontSize, '1 1 1', 0.6, FALSE);
+ draw_CenterText('0.5 0.5 0', _("<no model found>"), me.realFontSize, SKINCOLOR_TEXT, 0.6, FALSE);
return;
}
draw_beginBoldFont();
+#if XONVOTE186 // (nyov) lower name display looks better when there is no description text
+ draw_CenterText('0.5 0.8 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
+#else
draw_CenterText('0.5 0 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
+#endif
draw_endBoldFont();
o = '0.5 1 0' - eY * me.realFontSize_y * ((n = tokenizebyseparator(me.currentModelDescription, "\n")) + 0.5);
for(i = 0; i < n; ++i)
{
- draw_CenterText(o, argv(i), me.realFontSize, '1 1 1', 1, FALSE);
+ draw_CenterText(o, argv(i), me.realFontSize, SKINCOLOR_TEXT, 1, FALSE);
o += eY * me.realFontSize_y;
}
}
me.realFontSize_y = me.fontSize / absSize_y;
me.realFontSize_x = me.fontSize / absSize_x;
}
+
+void XonoticPlayerModelSelector_showNotify(entity me)
+{
+ me.configureXonoticPlayerModelSelector(me);
+}
#endif
strcat(catent.cat_string, ":"),
#endif
me.realFontSize,
- '1 1 1',
- SKINALPHA_TEXT,
+ SKINCOLOR_SERVERLIST_CATEGORY,
+ SKINALPHA_SERVERLIST_CATEGORY,
0
);
SET_YRANGE(me.categoriesHeight / (me.categoriesHeight + 1), 1);
s = me.skinParameter(me, i, SKINPARM_PREVIEW);
draw_Picture(me.columnPreviewOrigin * eX, s, me.columnPreviewSize * eX + eY, '1 1 1', 1);
- s = me.skinParameter(me, i, SKINPARM_NAME);
- s = sprintf(_("%s: %s"), s, me.skinParameter(me, i, SKINPARM_TITLE));
+ s = me.skinParameter(me, i, SKINPARM_TITLE);
s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_SKINLIST_TITLE, SKINALPHA_TEXT, 0);
}
void XonoticSlider_configureXonoticSlider(entity me, float theValueMin, float theValueMax, float theValueStep, string theCvar)
{
- float v, vk, vp;
- v = theValueMin;
- vk = theValueStep;
+ float vp;
vp = theValueStep * 10;
while(fabs(vp) < fabs(theValueMax - theValueMin) / 40)
vp *= 10;
+
me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
- me.configureSliderValues(me, theValueMin, v, theValueMax, theValueStep, vk, vp);
+
if(theCvar)
{
+ // Prevent flickering of the slider button by initialising the
+ // slider out of bounds to hide the button before loading the cvar
+ me.configureSliderValues(me, theValueMin, theValueMin-theValueStep, theValueMax, theValueStep, theValueStep, vp);
me.cvarName = theCvar;
me.loadCvars(me);
me.tooltip = getZonedTooltipForIdentifier(theCvar);
}
+ else
+ me.configureSliderValues(me, theValueMin, theValueMin, theValueMax, theValueStep, theValueStep, vp);
}
void XonoticSlider_setValue(entity me, float val)
{
--- /dev/null
+#ifdef INTERFACE
+CLASS(XonoticParticlesSlider) EXTENDS(XonoticTextSlider)
+ METHOD(XonoticParticlesSlider, configureXonoticParticlesSlider, void(entity))
+ METHOD(XonoticParticlesSlider, loadCvars, void(entity))
+ METHOD(XonoticParticlesSlider, saveCvars, void(entity))
+ENDCLASS(XonoticParticlesSlider)
+entity makeXonoticParticlesSlider();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticParticlesSlider()
+{
+ entity me;
+ me = spawnXonoticParticlesSlider();
+ me.configureXonoticParticlesSlider(me);
+ return me;
+}
+void XonoticParticlesSlider_configureXonoticParticlesSlider(entity me)
+{
+ me.configureXonoticTextSlider(me, "cl_particles_quality");
+ if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")), "0.4 250 0"); }
+ me.addValue(me, ZCTX(_("PART^Low")), "0.4 500 0");
+ me.addValue(me, ZCTX(_("PART^Medium")), "0.8 750 0");
+ me.addValue(me, ZCTX(_("PART^Normal")), "1.0 1000 1");
+ me.addValue(me, ZCTX(_("PART^High")), "1.0 1500 1");
+ me.addValue(me, ZCTX(_("PART^Ultra")), "1.0 2000 2");
+ if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "1.0 3000 2"); }
+ me.configureXonoticTextSliderValues(me);
+}
+void XonoticParticlesSlider_loadCvars(entity me)
+{
+ me.setValueFromIdentifier(me, sprintf("%s %s %s",
+ cvar_string("cl_particles_quality"),
+ cvar_string("r_drawparticles_drawdistance"),
+ cvar_string("cl_damageeffect")
+ ));
+}
+void XonoticParticlesSlider_saveCvars(entity me)
+{
+ if(me.value >= 0 || me.value < me.nValues)
+ {
+ tokenize_console(me.getIdentifier(me));
+ cvar_set("cl_particles_quality", argv(0));
+ cvar_set("r_drawparticles_drawdistance", argv(1));
+ cvar_set("cl_damageeffect", argv(2));
+ }
+}
+#endif
string msg = e.message;
if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
msg = sprintf(_("%s (mutator weapon)"), msg);
- draw_Text(me.realUpperMargin * eY, msg, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+ draw_Text(me.realUpperMargin * eY, msg, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
}
float XonoticWeaponsList_keyDown(entity me, float scan, float ascii, float shift)
void anticheat_physics()
{
- float f, wishspeed;
- vector wishvel;
+ float f;
// div0_evade -> SPECTATORS
makevectors(self.v_angle);
self.anticheat_speedhack_accu = 1;
self.anticheat_speedhack_lasttime = servertime;
}
-
- // race/CTS: force kbd movement for fairness
- if(g_race || g_cts)
- {
- // if record times matter
- // ensure nothing EVIL is being done (i.e. div0_evade)
- // this hinders joystick users though
- // but it still gives SOME analog control
- wishvel_x = fabs(self.movement_x);
- wishvel_y = fabs(self.movement_y);
- if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y)
- {
- wishvel_z = 0;
- wishspeed = vlen(wishvel);
- if(wishvel_x >= 2 * wishvel_y)
- {
- // pure X motion
- if(self.movement_x > 0)
- self.movement_x = wishspeed;
- else
- self.movement_x = -wishspeed;
- self.movement_y = 0;
- }
- else if(wishvel_y >= 2 * wishvel_x)
- {
- // pure Y motion
- self.movement_x = 0;
- if(self.movement_y > 0)
- self.movement_y = wishspeed;
- else
- self.movement_y = -wishspeed;
- }
- else
- {
- // diagonal
- if(self.movement_x > 0)
- self.movement_x = M_SQRT1_2 * wishspeed;
- else
- self.movement_x = -M_SQRT1_2 * wishspeed;
- if(self.movement_y > 0)
- self.movement_y = M_SQRT1_2 * wishspeed;
- else
- self.movement_y = -M_SQRT1_2 * wishspeed;
- }
- }
- }
}
void anticheat_spectatecopy(entity spectatee)
return;
// TODO(divVerent): Use xonstat to acquire good thresholds.
GameLogEcho(strcat(":anticheat:_time:", ftos(self.playerid), ":", ftos(servertime - self.anticheat_jointime)));
- GameLogEcho(strcat(":anticheat:speedhack:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack), 240, 0.1, 0.15)));
- GameLogEcho(strcat(":anticheat:speedhack_m1:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m1), 240, 0.1, 0.15)));
- GameLogEcho(strcat(":anticheat:speedhack_m2:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m2), 240, 0.1, 0.15)));
- GameLogEcho(strcat(":anticheat:speedhack_m3:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m3), 240, 0.1, 0.15)));
- GameLogEcho(strcat(":anticheat:speedhack_m4:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m4), 240, 0.1, 0.15)));
- GameLogEcho(strcat(":anticheat:speedhack_m5:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m5), 240, 0.1, 0.15)));
- GameLogEcho(strcat(":anticheat:div0_strafebot_old:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_div0_strafebot_old), 120, 0.3, 0.4)));
- GameLogEcho(strcat(":anticheat:div0_strafebot_new:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_div0_strafebot_new), 120, 0.3, 0.4)));
- GameLogEcho(strcat(":anticheat:div0_evade:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_div0_evade), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_signal) - MEAN_EVALUATE(anticheat_idle_snapaim_noise), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_signal:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_signal), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_noise:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_noise), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m2:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m2), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m3:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m3), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m4:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m4), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m7:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m7), 120, 0.1, 0.2)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m10:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m10), 120, 0.1, 0.2)));
+ GameLogEcho(strcat(":anticheat:speedhack:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack), 240, 0, 9999))); // Actually this one seems broken.
+ GameLogEcho(strcat(":anticheat:speedhack_m1:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m1), 240, 1.01, 1.25)));
+ GameLogEcho(strcat(":anticheat:speedhack_m2:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m2), 240, 1.01, 1.25)));
+ GameLogEcho(strcat(":anticheat:speedhack_m3:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m3), 240, 1.01, 1.25)));
+ GameLogEcho(strcat(":anticheat:speedhack_m4:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m4), 240, 1.01, 1.25)));
+ GameLogEcho(strcat(":anticheat:speedhack_m5:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_speedhack_m5), 240, 1.01, 1.25)));
+ GameLogEcho(strcat(":anticheat:div0_strafebot_old:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_div0_strafebot_old), 120, 0.15, 0.4)));
+ GameLogEcho(strcat(":anticheat:div0_strafebot_new:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_div0_strafebot_new), 120, 0.25, 0.8)));
+ GameLogEcho(strcat(":anticheat:div0_evade:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_div0_evade), 120, 0.2, 0.5)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_signal) - MEAN_EVALUATE(anticheat_idle_snapaim_noise), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_signal:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_signal), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_noise:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_noise), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_m2:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m2), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_m3:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m3), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_m4:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m4), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_m7:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m7), 120, 0, 9999)));
+ GameLogEcho(strcat(":anticheat:idle_snapaim_m10:", ftos(self.playerid), ":", anticheat_display(MEAN_EVALUATE(anticheat_idle_snapaim_m10), 120, 0, 9999)));
}
float anticheat_getvalue(string id)
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;
+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;
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;
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;
+float autocvar_g_freezetag_revive_nade_health;
float autocvar_g_freezetag_point_leadlimit;
float autocvar_g_freezetag_point_limit;
float autocvar_g_freezetag_revive_extra_size;
#define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
#define autocvar_g_start_weapon_laser cvar("g_start_weapon_laser")
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;
float autocvar_g_teamdamage_resetspeed;
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_vote_call;
float autocvar_sv_vote_change;
string autocvar_sv_vote_commands;
+float 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;
float autocvar_sv_vote_majority_factor;
float autocvar_sv_vote_majority_factor_of_voted;
float autocvar_g_random_gravity_delay;
float autocvar_g_nades;
float autocvar_g_nades_spawn;
+float autocvar_g_nades_spawn_count;
+float 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_radius;
float autocvar_g_nades_nade_force;
float autocvar_g_nades_nade_newton_style;
+float 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;
+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;
+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;
+float autocvar_g_nades_heal_time;
+float autocvar_g_nades_heal_rate;
+float autocvar_g_nades_heal_friend;
+float autocvar_g_nades_heal_foe;
+string autocvar_g_nades_pokenade_monster_type;
+float autocvar_g_nades_pokenade_monster_lifetime;
float autocvar_g_campcheck_damage;
float autocvar_g_campcheck_distance;
float autocvar_g_campcheck_interval;
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;
+float autocvar_g_buffs_waypoint_distance;
+float 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;
+float autocvar_g_buffs_cooldown_activate;
+float autocvar_g_buffs_cooldown_respawn;
+float autocvar_g_buffs_resistance_blockpercent;
+float autocvar_g_buffs_medic_survive_chance;
+float autocvar_g_buffs_medic_survive_health;
+float autocvar_g_buffs_medic_rot;
+float autocvar_g_buffs_medic_max;
+float autocvar_g_buffs_medic_regen;
+float autocvar_g_buffs_vengeance_damage_multiplier;
+float autocvar_g_buffs_bash_force;
+float autocvar_g_buffs_bash_force_self;
+float autocvar_g_buffs_disability_time;
+float autocvar_g_buffs_disability_speed;
+float autocvar_g_buffs_disability_rate;
+float autocvar_g_buffs_speed_speed;
+float autocvar_g_buffs_speed_rate;
+float autocvar_g_buffs_speed_damage_take;
+float autocvar_g_buffs_speed_regen;
+float autocvar_g_buffs_vampire_damage_steal;
+float autocvar_g_buffs_invisible_alpha;
+float autocvar_g_buffs_flight_gravity;
+float autocvar_g_buffs_jump_height;
+
return FALSE;
}
- if(e.freezetag_frozen)
+ if(e.frozen)
return FALSE;
// If neither player has ball then don't attack unless the ball is on the
}
}
-//Race:
-//go to next checkpoint, and annoy enemies
-.float race_checkpoint;
-void havocbot_role_race()
-{
- if(self.deadflag != DEAD_NO)
- return;
-
- entity e;
- if (self.bot_strategytime < time)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
- /*
- havocbot_goalrating_items(100, self.origin, 10000);
- havocbot_goalrating_enemyplayers(500, self.origin, 20000);
- */
-
- for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
- {
- if(e.cnt == self.race_checkpoint)
- {
- navigation_routerating(e, 1000000, 5000);
- }
- else if(self.race_checkpoint == -1)
- {
- navigation_routerating(e, 1000000, 5000);
- }
- }
-
- navigation_goalrating_end();
- }
-}
-
void havocbot_chooserole_dm()
{
self.havocbot_role = havocbot_role_dm;
}
-void havocbot_chooserole_race()
-{
- self.havocbot_role = havocbot_role_race;
-}
-
void havocbot_chooserole()
{
dprint("choosing a role...\n");
return;
else if (g_keyhunt)
havocbot_chooserole_kh();
- else if (g_race || g_cts)
- havocbot_chooserole_race();
else if (g_onslaught)
havocbot_chooserole_ons();
else // assume anything else is deathmatch
-void race_send_recordtime(float msg);
-void race_SendRankings(float pos, float prevpos, float del, float msg);
-
void send_CSQC_teamnagger() {
WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
{
entity spot;
self.hud = HUD_NORMAL;
- race_PreSpawnObserver();
+
+ if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); }
spot = SelectSpawnPoint (TRUE);
if(!spot)
WriteEntity(MSG_ONE, self);
}
- if((g_race && g_race_qualifying) || g_cts)
- {
- if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
- self.frags = FRAGS_LMS_LOSER;
- else
- self.frags = FRAGS_SPECTATOR;
- }
- else
- self.frags = FRAGS_SPECTATOR;
+ self.frags = FRAGS_SPECTATOR;
MUTATOR_CALLHOOK(MakePlayerObserver);
Portal_ClearAll(self);
+ Unfreeze(self);
+
if(self.alivetime)
{
if(!warmup_stage)
self.angles_z = 0;
self.fixangle = TRUE;
self.crouch = FALSE;
+ self.revival_time = 0;
setorigin (self, (spot.origin + PL_VIEW_OFS)); // offset it so that the spectator spawns higher off the ground, looks better this way
self.prevorigin = self.origin;
if(self.team < 0)
JoinBestTeam(self, FALSE, TRUE);
- race_PreSpawn();
-
spot = SelectSpawnPoint (FALSE);
if(!spot)
{
self.punchvector = '0 0 0';
self.oldvelocity = self.velocity;
self.fire_endtime = -1;
+ self.revival_time = 0;
entity spawnevent = spawn();
spawnevent.owner = self;
Net_LinkEntity(spawnevent, FALSE, 0.5, SpawnEvent_Send);
+ // Cut off any still running player sounds.
+ stopsound(self, CH_PLAYER_SINGLE);
+
self.model = "";
FixPlayermodel();
self.drawonlytoclient = world;
self.speedrunning = FALSE;
- race_PostSpawn(spot);
-
//stuffcmd(self, "chase_active 0");
//stuffcmd(self, "set viewsize $tmpviewsize \n");
activator = world;
self = oldself;
+ Unfreeze(self);
+
spawn_spot = spot;
MUTATOR_CALLHOOK(PlayerSpawn);
{
if(gameover) return;
if(self.player_blocked) return;
- if(self.freezetag_frozen) return;
+ if(self.frozen) return;
ClientKill_TeamChange(0);
}
anticheat_init();
- race_PreSpawnObserver();
-
// identify the right forced team
if(autocvar_g_campaign)
{
else
self.hitplotfh = -1;
- if(g_race || g_cts) {
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- msg_entity = self;
- race_send_recordtime(MSG_ONE);
- race_send_speedaward(MSG_ONE);
-
- speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
- speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
- race_send_speedaward_alltimebest(MSG_ONE);
-
- float i;
- for (i = 1; i <= RANKINGS_CNT; ++i) {
- race_SendRankings(i, 0, 0, MSG_ONE);
- }
- }
- else if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca
+ if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
send_CSQC_teamnagger();
CheatInitClient();
return;
}
+ if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); }
+
PlayerStats_AddGlobalInfo(self);
CheatShutdownClient();
Portal_ClearAll(self);
+ Unfreeze(self);
+
RemoveGrapplingHook(self);
// Here, everything has been done that requires this player to be a client.
void player_regen (void)
{
+ float max_mod, regen_mod, rot_mod, limit_mod;
+ max_mod = regen_mod = rot_mod = limit_mod = 1;
+ regen_mod_max = max_mod;
+ regen_mod_regen = regen_mod;
+ regen_mod_rot = rot_mod;
+ regen_mod_limit = limit_mod;
if(!MUTATOR_CALLHOOK(PlayerRegen))
+ if(!self.frozen)
{
- float minh, mina, maxh, maxa, limith, limita, max_mod, regen_mod, rot_mod, limit_mod;
+ float minh, mina, maxh, maxa, limith, limita;
maxh = autocvar_g_balance_health_rotstable;
maxa = autocvar_g_balance_armor_rotstable;
minh = autocvar_g_balance_health_regenstable;
mina = autocvar_g_balance_armor_regenstable;
limith = autocvar_g_balance_health_limit;
limita = autocvar_g_balance_armor_limit;
-
- max_mod = regen_mod = rot_mod = limit_mod = 1;
+
+ max_mod = regen_mod_max;
+ regen_mod = regen_mod_regen;
+ rot_mod = regen_mod_rot;
+ limit_mod = regen_mod_limit;
maxh = maxh * max_mod;
minh = minh * max_mod;
self.dmg_inflictor = spectatee.dmg_inflictor;
self.v_angle = spectatee.v_angle;
self.angles = spectatee.v_angle;
+ self.frozen = spectatee.frozen;
+ self.revive_progress = spectatee.revive_progress;
if(!self.BUTTON_USE)
self.fixangle = TRUE;
setorigin(self, spectatee.origin);
if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
{
self.classname = "player";
+ nades_RemoveBonus(self);
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(self, FALSE, TRUE); }
return;
#endif
+ if(self.frozen == 2)
+ {
+ self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1);
+ self.health = max(1, self.revive_progress * start_health);
+ self.iceblock.alpha = bound(0.2, 1 - self.revive_progress, 1);
+
+ if(self.revive_progress >= 1)
+ Unfreeze(self);
+ }
+ else if(self.frozen == 3)
+ {
+ self.revive_progress = bound(0, self.revive_progress - frametime * self.revive_speed, 1);
+ self.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * self.revive_progress );
+
+ if(self.health < 1)
+ {
+ if(self.vehicle)
+ vehicles_exit(VHEF_RELESE);
+ self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE, self.origin, '0 0 0');
+ }
+ else if ( self.revive_progress <= 0 )
+ Unfreeze(self);
+ }
+
MUTATOR_CALLHOOK(PlayerPreThink);
if(!self.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
do_crouch = 0;
if(self.vehicle)
do_crouch = 0;
- if(self.freezetag_frozen)
+ if(self.frozen)
do_crouch = 0;
if(self.weapon == WEP_SHOTGUN && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
do_crouch = 0;
if(self.spectatee_status != oldspectatee_status)
{
ClientData_Touch(self);
- if(g_race || g_cts)
- race_InitSpectator();
}
if(self.teamkill_soundtime)
playerdemo_write();
- if((g_cts || g_race) && self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
- {
- if (!self.stored_netname)
- self.stored_netname = strzone(uid2name(self.crypto_idfp));
- if(self.stored_netname != self.netname)
- {
- db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
- strunzone(self.stored_netname);
- self.stored_netname = strzone(self.netname);
- }
- }
-
- /*
- if(g_race)
- dprintf("%f %.6f\n", time, race_GetFractionalLapCount(self));
- */
-
CSQCMODEL_AUTOUPDATE();
}
*/
void PlayerJump (void)
{
+ if(self.frozen)
+ return; // no jumping in freezetag when frozen
+
if(self.player_blocked)
return; // no jumping while blocked
float doublejump = FALSE;
+ float mjumpheight = autocvar_sv_jumpvelocity;
player_multijump = doublejump;
+ player_jumpheight = mjumpheight;
if(MUTATOR_CALLHOOK(PlayerJump))
return;
doublejump = player_multijump;
-
- float mjumpheight;
+ mjumpheight = player_jumpheight;
if (autocvar_sv_doublejump)
{
}
}
- mjumpheight = autocvar_sv_jumpvelocity;
if (self.waterlevel >= WATERLEVEL_SWIMMING)
{
self.velocity_z = self.stat_sv_maxspeed * 0.7;
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)
PM_Accelerate(wishdir, wishspeed, wishspeed, autocvar_sv_accelerate*maxspd_mod, 1, 0, 0, 0);
}
}
- else if ((self.items & IT_JETPACK) && self.BUTTON_HOOK && (!autocvar_g_jetpack_fuel || self.ammo_fuel >= 0.01 || self.items & IT_UNLIMITED_WEAPON_AMMO) && !self.freezetag_frozen)
+ else if ((self.items & IT_JETPACK) && self.BUTTON_HOOK && (!autocvar_g_jetpack_fuel || self.ammo_fuel >= 0.01 || self.items & IT_UNLIMITED_WEAPON_AMMO) && !self.frozen)
{
//makevectors(self.v_angle_y * '0 1 0');
makevectors(self.v_angle);
}
}
- if((g_cts || g_race) && !IS_OBSERVER(self)) {
- if(vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed) {
+ 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;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
+ 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 != "") {
+ if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
+ {
speedaward_alltimebest = speedaward_speed;
speedaward_alltimebest_holder = speedaward_holder;
speedaward_alltimebest_uid = speedaward_uid;
void player_anim (void)
{
float deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
- if(self.deadflag && !deadbits)
- if(random() < 0.5)
- deadbits = ANIMSTATE_DEAD1;
- else
- deadbits = ANIMSTATE_DEAD2;
+ if(self.deadflag) {
+ if (!deadbits) {
+ // Decide on which death animation to use.
+ if(random() < 0.5)
+ deadbits = ANIMSTATE_DEAD1;
+ else
+ deadbits = ANIMSTATE_DEAD2;
+ }
+ } else {
+ // Clear a previous death animation.
+ deadbits = 0;
+ }
float animbits = deadbits;
- if(self.freezetag_frozen)
+ if(self.frozen)
animbits |= ANIMSTATE_FROZEN;
if(self.crouch)
animbits |= ANIMSTATE_DUCK;
else
self.respawn_countdown = -1; // do not count down
- if(g_cts || autocvar_g_forced_respawn)
+ if(autocvar_g_forced_respawn)
self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
}
// print an obituary message
Obituary (attacker, inflictor, self, deathtype);
- race_PreDie();
// increment frag counter for used weapon type
float w;
// when we get here, player actually dies
+ Unfreeze(self); // remove any icy remains
+ self.health = 0; // Unfreeze resets health, so we need to set it back
+
// clear waypoints
WaypointSprite_PlayerDead();
// throw a weapon
return 0;
if (g_weaponarena)
return 0;
- if (g_cts)
- return 0;
if (g_nexball && w == WEP_GRENADE_LAUNCHER)
return 0;
if(w == 0)
w = self.weapon;
if (w == 0)
return; // just in case
+ if(self.frozen)
+ return;
if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon))
return;
if(!autocvar_g_weapon_throwable)
return 1;
if(self.player_blocked)
return 1;
- if(self.freezetag_frozen)
+ if(self.frozen)
return 1;
return 0;
}
float t;
t = 1.0 / g_weaponratefactor;
+ weapon_rate = t;
+ MUTATOR_CALLHOOK(WeaponRateFactor);
+ t = weapon_rate;
+
return t;
}
else if(MUTATOR_CALLHOOK(AllowMobSpawning)) { sprint(self, "Monster spawning is currently disabled by a mutator.\n"); return; }
else if(!autocvar_g_monsters) { Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_MONSTERS_DISABLED); return; }
else if(self.vehicle) { sprint(self, "You can't spawn monsters while driving a vehicle.\n"); return; }
- else if(self.freezetag_frozen) { sprint(self, "You can't spawn monsters while frozen.\n"); return; }
+ else if(self.frozen) { sprint(self, "You can't spawn monsters while frozen.\n"); return; }
else if(autocvar_g_campaign) { sprint(self, "You can't spawn monsters in campaign mode.\n"); return; }
else if(self.deadflag != DEAD_NO) { sprint(self, "You can't spawn monsters while dead.\n"); return; }
else if(monstercount >= autocvar_g_monsters_max_perplayer) { sprint(self, "You have spawned too many monsters, kill some before trying to spawn any more.\n"); return; }
float i, j, k, uidcnt = 0, thiscnt;
string s, temp_s, rr, myuid, thisuid;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
+ rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
for(k = 0; k < MapInfo_count; ++k)
{
if(time <= game_starttime && round_handler_IsActive())
round_handler_Reset(game_starttime);
- if(g_race || g_cts)
- race_ReadyRestart();
- else MUTATOR_CALLHOOK(reset_map_global);
+ MUTATOR_CALLHOOK(reset_map_global);
for(self = world; (self = nextent(self)); )
if(IS_NOT_A_CLIENT(self))
WriteByte(MSG_ENTITY, ft);
WriteByte(MSG_ENTITY, fr);
}
+
+ WriteByte(MSG_ENTITY, self.realowner.team);
}
if(sf & 2)
float g_warmup_limit;
float g_warmup_allguns;
float g_warmup_allow_timeout;
-float g_race_qualifying;
float warmup_stage;
float g_pickup_respawntime_weapon;
float g_pickup_respawntime_superweapon;
.float player_blocked;
-.float freezetag_frozen;
+.float frozen; // for freeze attacks
+.float revive_progress;
+.float revival_time; // time at which player was last revived
+.float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
+.entity iceblock;
+.entity frozen_by; // for ice fields
.entity muzzle_flash;
.float misc_bulletcounter; // replaces uzi & hlac bullet counter.
if(targ.killcount) { targ.killcount = 0; }
}
+void Ice_Think()
+{
+ if(!self.owner.frozen || self.owner.iceblock != self)
+ {
+ remove(self);
+ return;
+ }
+ setorigin(self, self.owner.origin - '0 0 16');
+ self.nextthink = time;
+}
+
+void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint)
+{
+ if(!IS_PLAYER(targ) && !(targ.flags & FL_MONSTER)) // only specified entities can be freezed
+ return;
+
+ if(targ.frozen)
+ return;
+
+ float targ_maxhealth = ((targ.flags & FL_MONSTER) ? targ.max_health : start_health);
+
+ targ.frozen = frozen_type;
+ targ.revive_progress = ((frozen_type == 3) ? 1 : 0);
+ targ.health = ((frozen_type == 3) ? targ_maxhealth : 1);
+ targ.revive_speed = freeze_time;
+
+ entity ice, head;
+ ice = spawn();
+ ice.owner = targ;
+ ice.classname = "ice";
+ ice.scale = targ.scale;
+ ice.think = Ice_Think;
+ ice.nextthink = time;
+ ice.frame = floor(random() * 21); // ice model has 20 different looking frames
+ setmodel(ice, "models/ice/ice.md3");
+ ice.alpha = 1;
+ ice.colormod = Team_ColorRGB(targ.team);
+ ice.glowmod = ice.colormod;
+ targ.iceblock = ice;
+ targ.revival_time = 0;
+
+ entity oldself;
+ oldself = self;
+ self = ice;
+ Ice_Think();
+ self = oldself;
+
+ RemoveGrapplingHook(targ);
+
+ FOR_EACH_PLAYER(head)
+ if(head.hook.aiment == targ)
+ RemoveGrapplingHook(head);
+
+ // add waypoint
+ if(show_waypoint)
+ WaypointSprite_Spawn("frozen", 0, 0, targ, '0 0 64', world, targ.team, targ, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
+}
+
+void Unfreeze (entity targ)
+{
+ if(targ.frozen && targ.frozen != 3) // only reset health if target was frozen
+ targ.health = ((IS_PLAYER(targ)) ? start_health : targ.max_health);
+
+ entity head;
+ targ.frozen = 0;
+ targ.revive_progress = 0;
+ targ.revival_time = time;
+
+ WaypointSprite_Kill(targ.waypointsprite_attached);
+
+ FOR_EACH_PLAYER(head)
+ if(head.hook.aiment == targ)
+ RemoveGrapplingHook(head);
+
+ // remove the ice block
+ if(targ.iceblock)
+ remove(targ.iceblock);
+ targ.iceblock = world;
+}
+
// these are updated by each Damage call for use in button triggering and such
entity damage_targ;
entity damage_inflictor;
mirrordamage = frag_mirrordamage;
force = frag_force;
- if (!g_minstagib)
+ if(targ.frozen)
+ if(deathtype != DEATH_HURTTRIGGER && deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_AUTOTEAMCHANGE)
+ {
+ if(autocvar_g_freezetag_revive_falldamage > 0)
+ if(deathtype == DEATH_FALL)
+ if(damage >= autocvar_g_freezetag_revive_falldamage)
+ {
+ Unfreeze(targ);
+ targ.health = autocvar_g_freezetag_revive_falldamage_health;
+ pointparticles(particleeffectnum("iceorglass"), targ.origin, '0 0 0', 3);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, targ.netname);
+ Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
+ }
+
+ damage = 0;
+ force *= autocvar_g_freezetag_frozen_force;
+ }
+
+ if(targ.frozen && deathtype == DEATH_HURTTRIGGER && !autocvar_g_freezetag_frozen_damage_trigger)
+ {
+ pointparticles(particleeffectnum("teleport"), targ.origin, '0 0 0', 1);
+
+ entity oldself = self;
+ self = targ;
+ entity spot = SelectSpawnPoint (FALSE);
+
+ if(spot)
+ {
+ damage = 0;
+ self.deadflag = DEAD_NO;
+
+ self.angles = spot.angles;
+
+ self.effects = 0;
+ self.effects |= EF_TELEPORT_BIT;
+
+ self.angles_z = 0; // never spawn tilted even if the spot says to
+ self.fixangle = TRUE; // turn this way immediately
+ self.velocity = '0 0 0';
+ self.avelocity = '0 0 0';
+ self.punchangle = '0 0 0';
+ self.punchvector = '0 0 0';
+ self.oldvelocity = self.velocity;
+
+ self.spawnorigin = spot.origin;
+ setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24));
+ // don't reset back to last position, even if new position is stuck in solid
+ self.oldorigin = self.origin;
+ self.prevorigin = self.origin;
+
+ pointparticles(particleeffectnum("teleport"), self.origin, '0 0 0', 1);
+ }
+
+ self = oldself;
+ }
+
+ if(!g_minstagib)
{
// apply strength multiplier
if (attacker.items & IT_STRENGTH)
}
if (targ == attacker)
- {
- if(g_cts && !autocvar_g_cts_selfdamage)
- damage = 0;
- else
- damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
- }
+ damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
// count the damage
if(attacker)
e.fire_endtime = 0;
// ice stops fire
- if(e.freezetag_frozen)
+ if(e.frozen)
e.fire_endtime = 0;
t = min(frametime, e.fire_endtime - time);
e.fire_hitsound = TRUE;
if (!IS_INDEPENDENT_PLAYER(e))
- if(!e.freezetag_frozen)
+ if(!e.frozen)
FOR_EACH_PLAYER(other) if(e != other)
{
if(IS_PLAYER(other))
string redirection_target;
float world_initialized;
-string GetMapname();
string GetGametype();
void GotoNextMap(float reinit);
void ShuffleMaplist();
// private
BADCVAR("developer");
BADCVAR("log_dest_udp");
- BADCVAR("log_file");
BADCVAR("net_address");
BADCVAR("net_address_ipv6");
BADCVAR("port");
BADPREFIX("g_playerstats_");
BADPREFIX("g_respawn_ghosts");
BADPREFIX("g_voice_flood_");
+ BADPREFIX("log_file");
BADPREFIX("rcon_");
BADPREFIX("sv_allowdownloads");
BADPREFIX("sv_autodemo");
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
+ CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
MapInfo_Enumerate();
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
+ CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
+ // freeze attacks
+ 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);
return MapInfo_Type_ToString(MapInfo_LoadedGametype);
}
-string getmapname_stored;
string GetMapname()
{
return mapname;
return TRUE;
}
if(autocvar_nextmap != "")
- if(MapInfo_CheckMap(autocvar_nextmap))
+ {
+ string m;
+ m = GameTypeVote_MapInfo_FixName(autocvar_nextmap);
+ cvar_set("nextmap",m);
+
+ if(!m || gametypevote)
+ return FALSE;
+ if(autocvar_sv_vote_gametype)
+ {
+ Map_Goto_SetStr(m);
+ return FALSE;
+ }
+
+ if(MapInfo_CheckMap(m))
{
- Map_Goto_SetStr(autocvar_nextmap);
+ Map_Goto_SetStr(m);
Map_Goto(reinit);
alreadychangedlevel = TRUE;
return TRUE;
}
+ }
if(!reinit && autocvar_lastlevel)
{
cvar_settemp_restore();
============
*/
.float autoscreenshot;
-void() MapVote_Start;
-void() MapVote_Think;
-float mapvote_initialized;
void IntermissionThink()
{
FixIntermissionClient(self);
SetDefaultAlpha();
- /*
- MapVote_Think should now do that part
- if (intermission_running)
- if (time >= intermission_exittime + 60)
- {
- if(!DoNextMapOverride())
- GotoNextMap();
- return;
- }
- */
-
if (gameover) // someone else quit the game already
{
if(player_count == 0) // Nobody there? Then let's go to the next map
}
}
-float mapvote_nextthink;
-float mapvote_initialized;
-float mapvote_keeptwotime;
-float mapvote_timeout;
-string mapvote_message;
-#define 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_run;
-float mapvote_detail;
-float mapvote_abstain;
-.float mapvote;
-
-void MapVote_ClearAllVotes()
-{
- FOR_EACH_CLIENT(other)
- other.mapvote = 0;
-}
-
-string MapVote_Suggest(string m)
+string GotoMap(string m)
{
- float i;
- if(m == "")
- return "That's not how to use this command.";
- if(!autocvar_g_maplist_votable_suggestions)
- return "Suggestions are not accepted on this server.";
- if(mapvote_initialized)
- return "Can't suggest - voting is already in progress!";
- m = MapInfo_FixName(m);
+ m = GameTypeVote_MapInfo_FixName(m);
if (!m)
return "The map you suggested is not available on this server.";
- if(!autocvar_g_maplist_votable_suggestions_override_mostrecent)
- if(Map_IsRecent(m))
- return "This server does not allow for recent maps to be played again. Please be patient for some rounds.";
-
+ if (!autocvar_sv_vote_gametype)
if(!MapInfo_CheckMap(m))
return "The map you suggested does not support the current game mode.";
- for(i = 0; i < mapvote_suggestion_ptr; ++i)
- if(mapvote_suggestions[i] == m)
- return "This map was already suggested.";
- if(mapvote_suggestion_ptr >= MAPVOTE_COUNT)
- {
- i = floor(random() * mapvote_suggestion_ptr);
- }
- else
- {
- i = mapvote_suggestion_ptr;
- mapvote_suggestion_ptr += 1;
- }
- if(mapvote_suggestions[i] != "")
- strunzone(mapvote_suggestions[i]);
- mapvote_suggestions[i] = strzone(m);
- if(autocvar_sv_eventlog)
- GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid)));
- return strcat("Suggestion of ", m, " accepted.");
-}
-
-void MapVote_AddVotable(string nextMap, float isSuggestion)
-{
- float j, i, o;
- string pakfile, mapfile;
-
- if(nextMap == "")
- return;
- for(j = 0; j < mapvote_count; ++j)
- if(mapvote_maps[j] == nextMap)
- return;
- // suggestions might be no longer valid/allowed after gametype switch!
- if(isSuggestion)
- if(!MapInfo_CheckMap(nextMap))
- return;
- mapvote_maps[mapvote_count] = strzone(nextMap);
- mapvote_maps_suggested[mapvote_count] = isSuggestion;
-
- pakfile = string_null;
- for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
- {
- mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]);
- pakfile = whichpack(strcat(mapfile, ".tga"));
- if(pakfile == "")
- pakfile = whichpack(strcat(mapfile, ".jpg"));
- if(pakfile == "")
- pakfile = whichpack(strcat(mapfile, ".png"));
- if(pakfile != "")
- break;
- }
- if(i >= mapvote_screenshot_dirs_count)
- i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server?
- for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1)
- pakfile = substring(pakfile, o, -1);
-
- mapvote_maps_screenshot_dir[mapvote_count] = i;
- mapvote_maps_pakfile[mapvote_count] = strzone(pakfile);
-
- mapvote_count += 1;
-}
-
-void MapVote_Spawn();
-void MapVote_Init()
-{
- float i;
- float nmax, smax;
-
- MapVote_ClearAllVotes();
-
- mapvote_count = 0;
- mapvote_detail = !autocvar_g_maplist_votable_nodetail;
- mapvote_abstain = autocvar_g_maplist_votable_abstain;
-
- if(mapvote_abstain)
- nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable);
- else
- nmax = min(MAPVOTE_COUNT, autocvar_g_maplist_votable);
- smax = min3(nmax, autocvar_g_maplist_votable_suggestions, mapvote_suggestion_ptr);
-
- // we need this for AddVotable, as that cycles through the screenshot dirs
- mapvote_screenshot_dirs_count = tokenize_console(autocvar_g_maplist_votable_screenshot_dir);
- if(mapvote_screenshot_dirs_count == 0)
- mapvote_screenshot_dirs_count = tokenize_console("maps levelshots");
- mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT);
- for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
- mapvote_screenshot_dirs[i] = strzone(argv(i));
-
- if(mapvote_suggestion_ptr)
- for(i = 0; i < 100 && mapvote_count < smax; ++i)
- MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE);
-
- for(i = 0; i < 100 && mapvote_count < nmax; ++i)
- MapVote_AddVotable(GetNextMap(), FALSE);
-
- if(mapvote_count == 0)
- {
- bprint( "Maplist contains no single playable map! Resetting it to default map list.\n" );
- cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
- if(autocvar_g_maplist_shuffle)
- ShuffleMaplist();
- localcmd("\nmenu_cmd sync\n");
- for(i = 0; i < 100 && mapvote_count < nmax; ++i)
- MapVote_AddVotable(GetNextMap(), FALSE);
- }
-
- mapvote_count_real = mapvote_count;
- if(mapvote_abstain)
- MapVote_AddVotable("don't care", 0);
-
- //dprint("mapvote count is ", ftos(mapvote_count), "\n");
-
- mapvote_keeptwotime = time + autocvar_g_maplist_votable_keeptwotime;
- mapvote_timeout = time + autocvar_g_maplist_votable_timeout;
- if(mapvote_count_real < 3 || mapvote_keeptwotime <= time)
- mapvote_keeptwotime = 0;
- mapvote_message = "Choose a map and press its key!";
-
- MapVote_Spawn();
-}
-
-void MapVote_SendPicture(float id)
-{
- msg_entity = self;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_PICTURE);
- WriteByte(MSG_ONE, id);
- WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
-}
-
-float MapVote_GetMapMask()
-{
- float mask, i, power;
- mask = 0;
- for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
- if(mapvote_maps[i] != "")
- mask |= power;
- return mask;
-}
-
-entity mapvote_ent;
-float MapVote_SendEntity(entity to, float sf)
-{
- float i;
-
- if(sf & 1)
- sf &= ~2; // if we send 1, we don't need to also send 2
-
- WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
- WriteByte(MSG_ENTITY, sf);
-
- if(sf & 1)
- {
- // flag 1 == initialization
- for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
- WriteString(MSG_ENTITY, mapvote_screenshot_dirs[i]);
- WriteString(MSG_ENTITY, "");
- WriteByte(MSG_ENTITY, mapvote_count);
- WriteByte(MSG_ENTITY, mapvote_abstain);
- WriteByte(MSG_ENTITY, mapvote_detail);
- WriteCoord(MSG_ENTITY, mapvote_timeout);
- if(mapvote_count <= 8)
- WriteByte(MSG_ENTITY, MapVote_GetMapMask());
- else
- WriteShort(MSG_ENTITY, MapVote_GetMapMask());
- for(i = 0; i < mapvote_count; ++i)
- if(mapvote_maps[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
- }
- else
- {
- WriteString(MSG_ENTITY, mapvote_maps[i]);
- WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]);
- WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]);
- }
- }
- }
-
- if(sf & 2)
- {
- // flag 2 == update of mask
- if(mapvote_count <= 8)
- WriteByte(MSG_ENTITY, MapVote_GetMapMask());
- else
- WriteShort(MSG_ENTITY, MapVote_GetMapMask());
- }
-
- if(sf & 4)
- {
- if(mapvote_detail)
- for(i = 0; i < mapvote_count; ++i)
- if(mapvote_maps[i] != "")
- WriteByte(MSG_ENTITY, mapvote_selections[i]);
-
- WriteByte(MSG_ENTITY, to.mapvote);
- }
-
- return TRUE;
-}
-
-void MapVote_Spawn()
-{
- Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity);
-}
-
-void MapVote_TouchMask()
-{
- mapvote_ent.SendFlags |= 2;
-}
-
-void MapVote_TouchVotes(entity voter)
-{
- mapvote_ent.SendFlags |= 4;
-}
-
-float MapVote_Finished(float mappos)
-{
- string result;
- float i;
- float didntvote;
-
- if(autocvar_sv_eventlog)
- {
- result = strcat(":vote:finished:", mapvote_maps[mappos]);
- result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::");
- didntvote = mapvote_voters;
- for(i = 0; i < mapvote_count; ++i)
- if(mapvote_maps[i] != "")
- {
- didntvote -= mapvote_selections[i];
- if(i != mappos)
- {
- result = strcat(result, ":", mapvote_maps[i]);
- result = strcat(result, ":", ftos(mapvote_selections[i]));
- }
- }
- result = strcat(result, ":didn't vote:", ftos(didntvote));
-
- GameLogEcho(result);
- if(mapvote_maps_suggested[mappos])
- GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos]));
- }
-
- FOR_EACH_REALCLIENT(other)
- FixClientCvars(other);
-
- Map_Goto_SetStr(mapvote_maps[mappos]);
- Map_Goto(0);
- alreadychangedlevel = TRUE;
- return TRUE;
-}
-void MapVote_CheckRules_1()
-{
- float i;
-
- for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "")
- {
- //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
- mapvote_selections[i] = 0;
- }
-
- mapvote_voters = 0;
- FOR_EACH_REALCLIENT(other)
- {
- ++mapvote_voters;
- if(other.mapvote)
- {
- i = other.mapvote - 1;
- //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n");
- mapvote_selections[i] = mapvote_selections[i] + 1;
- }
- }
-}
-
-float MapVote_CheckRules_2()
-{
- float i;
- float firstPlace, secondPlace;
- float firstPlaceVotes, secondPlaceVotes;
- float mapvote_voters_real;
- string result;
-
- if(mapvote_count_real == 1)
- return MapVote_Finished(0);
-
- mapvote_voters_real = mapvote_voters;
- if(mapvote_abstain)
- mapvote_voters_real -= mapvote_selections[mapvote_count - 1];
-
- RandomSelection_Init();
- for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "")
- RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
- firstPlace = RandomSelection_chosen_float;
- firstPlaceVotes = RandomSelection_best_priority;
- //dprint("First place: ", ftos(firstPlace), "\n");
- //dprint("First place votes: ", ftos(firstPlaceVotes), "\n");
-
- RandomSelection_Init();
- for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "")
- if(i != firstPlace)
- RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
- secondPlace = RandomSelection_chosen_float;
- secondPlaceVotes = RandomSelection_best_priority;
- //dprint("Second place: ", ftos(secondPlace), "\n");
- //dprint("Second place votes: ", ftos(secondPlaceVotes), "\n");
-
- if(firstPlace == -1)
- error("No first place in map vote... WTF?");
-
- if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes)
- return MapVote_Finished(firstPlace);
-
- if(mapvote_keeptwotime)
- if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes)
- {
- float didntvote;
- MapVote_TouchMask();
- mapvote_message = "Now decide between the TOP TWO!";
- mapvote_keeptwotime = 0;
- result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]);
- result = strcat(result, ":", ftos(firstPlaceVotes));
- result = strcat(result, ":", mapvote_maps[secondPlace]);
- result = strcat(result, ":", ftos(secondPlaceVotes), "::");
- didntvote = mapvote_voters;
- for(i = 0; i < mapvote_count; ++i)
- if(mapvote_maps[i] != "")
- {
- didntvote -= mapvote_selections[i];
- if(i != firstPlace)
- if(i != secondPlace)
- {
- result = strcat(result, ":", mapvote_maps[i]);
- result = strcat(result, ":", ftos(mapvote_selections[i]));
- if(i < mapvote_count_real)
- {
- strunzone(mapvote_maps[i]);
- mapvote_maps[i] = "";
- strunzone(mapvote_maps_pakfile[i]);
- mapvote_maps_pakfile[i] = "";
- }
- }
- }
- result = strcat(result, ":didn't vote:", ftos(didntvote));
- if(autocvar_sv_eventlog)
- GameLogEcho(result);
- }
-
- return FALSE;
-}
-void MapVote_Tick()
-{
- float keeptwo;
- float totalvotes;
-
- keeptwo = mapvote_keeptwotime;
- MapVote_CheckRules_1(); // count
- if(MapVote_CheckRules_2()) // decide
- return;
-
- totalvotes = 0;
- FOR_EACH_REALCLIENT(other)
- {
- // hide scoreboard again
- if(other.health != 2342)
- {
- other.health = 2342;
- other.impulse = 0;
- if(IS_REAL_CLIENT(other))
- {
- msg_entity = other;
- WriteByte(MSG_ONE, SVC_FINALE);
- WriteString(MSG_ONE, "");
- }
- }
-
- // clear possibly invalid votes
- if(mapvote_maps[other.mapvote - 1] == "")
- other.mapvote = 0;
- // use impulses as new vote
- if(other.impulse >= 1 && other.impulse <= mapvote_count)
- if(mapvote_maps[other.impulse - 1] != "")
- {
- other.mapvote = other.impulse;
- MapVote_TouchVotes(other);
- }
- other.impulse = 0;
-
- if(other.mapvote)
- ++totalvotes;
- }
-
- MapVote_CheckRules_1(); // just count
-}
-void MapVote_Start()
-{
- if(mapvote_run)
- return;
-
- // wait for stats to be sent first
- if(!playerstats_waitforme)
- return;
-
- MapInfo_Enumerate();
- if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
- mapvote_run = TRUE;
-}
-void MapVote_Think()
-{
- if(!mapvote_run)
- return;
-
- if(alreadychangedlevel)
- return;
-
- if(time < mapvote_nextthink)
- return;
- //dprint("tick\n");
-
- mapvote_nextthink = time + 0.5;
-
- if(!mapvote_initialized)
- {
- if(autocvar_rescan_pending == 1)
- {
- cvar_set("rescan_pending", "2");
- localcmd("fs_rescan\nrescan_pending 3\n");
- return;
- }
- else if(autocvar_rescan_pending == 2)
- {
- return;
- }
- else if(autocvar_rescan_pending == 3)
- {
- // now build missing mapinfo files
- if(!MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
- return;
-
- // we're done, start the timer
- cvar_set("rescan_pending", "0");
- }
-
- mapvote_initialized = TRUE;
- if(DoNextMapOverride(0))
- return;
- if(!autocvar_g_maplist_votable || player_count <= 0)
- {
- GotoNextMap(0);
- return;
- }
- MapVote_Init();
- }
-
- MapVote_Tick();
-}
-
-string GotoMap(string m)
-{
- if(!MapInfo_CheckMap(m))
- return "The map you chose is not available on this server.";
cvar_set("nextmap", m);
cvar_set("timelimit", "-1");
if(mapvote_initialized || alreadychangedlevel)
--- /dev/null
+float GameTypeVote_AvailabilityStatus(string gtname)
+{
+ float type = MapInfo_Type_FromString(gtname);
+ if( type == 0 )
+ return GTV_FORBIDDEN;
+
+ if ( autocvar_nextmap != "" )
+ {
+ if ( !MapInfo_Get_ByName(autocvar_nextmap, FALSE, 0) )
+ return GTV_FORBIDDEN;
+ if (!(MapInfo_Map_supportedGametypes & type))
+ return GTV_FORBIDDEN;
+ }
+
+ return GTV_AVAILABLE;
+}
+
+float GameTypeVote_GetMask()
+{
+ float n, j, gametype_mask;
+ n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " ");
+ n = min(MAPVOTE_COUNT, n);
+ gametype_mask = 0;
+ for(j = 0; j < n; ++j)
+ gametype_mask |= MapInfo_Type_FromString(argv(j));
+ return gametype_mask;
+}
+
+string GameTypeVote_MapInfo_FixName(string m)
+{
+ if ( autocvar_sv_vote_gametype )
+ {
+ MapInfo_Enumerate();
+ MapInfo_FilterGametype(GameTypeVote_GetMask(), 0, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+ }
+ return MapInfo_FixName(m);
+}
+
+void MapVote_ClearAllVotes()
+{
+ FOR_EACH_CLIENT(other)
+ other.mapvote = 0;
+}
+
+void MapVote_UnzoneStrings()
+{
+ float j;
+ for(j = 0; j < mapvote_count; ++j)
+ {
+ if ( mapvote_maps[j] )
+ {
+ strunzone(mapvote_maps[j]);
+ mapvote_maps[j] = string_null;
+ }
+ if ( mapvote_maps_pakfile[j] )
+ {
+ strunzone(mapvote_maps_pakfile[j]);
+ mapvote_maps_pakfile[j] = string_null;
+ }
+ }
+}
+
+string MapVote_Suggest(string m)
+{
+ float i;
+ if(m == "")
+ return "That's not how to use this command.";
+ if(!autocvar_g_maplist_votable_suggestions)
+ return "Suggestions are not accepted on this server.";
+ if(mapvote_initialized)
+ if(!gametypevote)
+ return "Can't suggest - voting is already in progress!";
+ m = GameTypeVote_MapInfo_FixName(m);
+ if (!m)
+ return "The map you suggested is not available on this server.";
+ if(!autocvar_g_maplist_votable_suggestions_override_mostrecent)
+ if(Map_IsRecent(m))
+ return "This server does not allow for recent maps to be played again. Please be patient for some rounds.";
+
+ if (!autocvar_sv_vote_gametype)
+ if(!MapInfo_CheckMap(m))
+ return "The map you suggested does not support the current game mode.";
+ for(i = 0; i < mapvote_suggestion_ptr; ++i)
+ if(mapvote_suggestions[i] == m)
+ return "This map was already suggested.";
+ if(mapvote_suggestion_ptr >= MAPVOTE_COUNT)
+ {
+ i = floor(random() * mapvote_suggestion_ptr);
+ }
+ else
+ {
+ i = mapvote_suggestion_ptr;
+ mapvote_suggestion_ptr += 1;
+ }
+ if(mapvote_suggestions[i] != "")
+ strunzone(mapvote_suggestions[i]);
+ mapvote_suggestions[i] = strzone(m);
+ if(autocvar_sv_eventlog)
+ GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid)));
+ return strcat("Suggestion of ", m, " accepted.");
+}
+
+void MapVote_AddVotable(string nextMap, float isSuggestion)
+{
+ float j, i, o;
+ string pakfile, mapfile;
+
+ if(nextMap == "")
+ return;
+ for(j = 0; j < mapvote_count; ++j)
+ if(mapvote_maps[j] == nextMap)
+ return;
+ // suggestions might be no longer valid/allowed after gametype switch!
+ if(isSuggestion)
+ if(!MapInfo_CheckMap(nextMap))
+ return;
+ mapvote_maps[mapvote_count] = strzone(nextMap);
+ mapvote_maps_suggested[mapvote_count] = isSuggestion;
+
+ pakfile = string_null;
+ for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
+ {
+ mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]);
+ pakfile = whichpack(strcat(mapfile, ".tga"));
+ if(pakfile == "")
+ pakfile = whichpack(strcat(mapfile, ".jpg"));
+ if(pakfile == "")
+ pakfile = whichpack(strcat(mapfile, ".png"));
+ if(pakfile != "")
+ break;
+ }
+ if(i >= mapvote_screenshot_dirs_count)
+ i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server?
+ for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1)
+ pakfile = substring(pakfile, o, -1);
+
+ mapvote_maps_screenshot_dir[mapvote_count] = i;
+ mapvote_maps_pakfile[mapvote_count] = strzone(pakfile);
+ mapvote_maps_availability[mapvote_count] = GTV_AVAILABLE;
+
+ mapvote_count += 1;
+}
+
+void MapVote_Init()
+{
+ float i;
+ float nmax, smax;
+
+ MapVote_ClearAllVotes();
+ MapVote_UnzoneStrings();
+
+ mapvote_count = 0;
+ mapvote_detail = !autocvar_g_maplist_votable_nodetail;
+ mapvote_abstain = autocvar_g_maplist_votable_abstain;
+
+ if(mapvote_abstain)
+ nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable);
+ else
+ nmax = min(MAPVOTE_COUNT, autocvar_g_maplist_votable);
+ smax = min3(nmax, autocvar_g_maplist_votable_suggestions, mapvote_suggestion_ptr);
+
+ // we need this for AddVotable, as that cycles through the screenshot dirs
+ mapvote_screenshot_dirs_count = tokenize_console(autocvar_g_maplist_votable_screenshot_dir);
+ if(mapvote_screenshot_dirs_count == 0)
+ mapvote_screenshot_dirs_count = tokenize_console("maps levelshots");
+ mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT);
+ for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
+ mapvote_screenshot_dirs[i] = strzone(argv(i));
+
+ if(mapvote_suggestion_ptr)
+ for(i = 0; i < 100 && mapvote_count < smax; ++i)
+ MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE);
+
+ for(i = 0; i < 100 && mapvote_count < nmax; ++i)
+ MapVote_AddVotable(GetNextMap(), FALSE);
+
+ if(mapvote_count == 0)
+ {
+ bprint( "Maplist contains no single playable map! Resetting it to default map list.\n" );
+ cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_CurrentGametype(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
+ if(autocvar_g_maplist_shuffle)
+ ShuffleMaplist();
+ localcmd("\nmenu_cmd sync\n");
+ for(i = 0; i < 100 && mapvote_count < nmax; ++i)
+ MapVote_AddVotable(GetNextMap(), FALSE);
+ }
+
+ mapvote_count_real = mapvote_count;
+ if(mapvote_abstain)
+ MapVote_AddVotable("don't care", 0);
+
+ //dprint("mapvote count is ", ftos(mapvote_count), "\n");
+
+ mapvote_keeptwotime = time + autocvar_g_maplist_votable_keeptwotime;
+ mapvote_timeout = time + autocvar_g_maplist_votable_timeout;
+ if(mapvote_count_real < 3 || mapvote_keeptwotime <= time)
+ mapvote_keeptwotime = 0;
+ mapvote_message = "Choose a map and press its key!";
+
+ MapVote_Spawn();
+}
+
+void MapVote_SendPicture(float id)
+{
+ msg_entity = self;
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_PICTURE);
+ WriteByte(MSG_ONE, id);
+ WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
+}
+
+
+void MapVote_WriteMask()
+{
+ float i;
+ if ( mapvote_count < 24 )
+ {
+ float mask,power;
+ mask = 0;
+ for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
+ if(mapvote_maps_availability[i] == GTV_AVAILABLE )
+ mask |= power;
+
+ if(mapvote_count < 8)
+ WriteByte(MSG_ENTITY, mask);
+ else if (mapvote_count < 16)
+ WriteShort(MSG_ENTITY,mask);
+ else
+ WriteLong(MSG_ENTITY, mask);
+ }
+ else
+ {
+ for ( i = 0; i < mapvote_count; ++i )
+ WriteByte(MSG_ENTITY, mapvote_maps_availability[i]);
+ }
+}
+
+float MapVote_SendEntity(entity to, float sf)
+{
+ float i;
+
+ if(sf & 1)
+ sf &= ~2; // if we send 1, we don't need to also send 2
+
+ WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & 1)
+ {
+ // flag 1 == initialization
+ for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
+ WriteString(MSG_ENTITY, mapvote_screenshot_dirs[i]);
+ WriteString(MSG_ENTITY, "");
+ WriteByte(MSG_ENTITY, mapvote_count);
+ WriteByte(MSG_ENTITY, mapvote_abstain);
+ WriteByte(MSG_ENTITY, mapvote_detail);
+ WriteCoord(MSG_ENTITY, mapvote_timeout);
+
+ if ( gametypevote )
+ {
+ // gametype vote
+ WriteByte(MSG_ENTITY, 1);
+ WriteString(MSG_ENTITY, autocvar_nextmap);
+ }
+ else if ( autocvar_sv_vote_gametype )
+ {
+ // map vote but gametype has been chosen via voting screen
+ WriteByte(MSG_ENTITY, 2);
+ WriteString(MSG_ENTITY, MapInfo_Type_ToText(MapInfo_CurrentGametype()));
+ }
+ else
+ WriteByte(MSG_ENTITY, 0); // map vote
+
+ MapVote_WriteMask();
+
+ 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);
+ }
+ 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]);
+ }
+ }
+ }
+
+ if(sf & 2)
+ {
+ // flag 2 == update of mask
+ MapVote_WriteMask();
+ }
+
+ if(sf & 4)
+ {
+ if(mapvote_detail)
+ for(i = 0; i < mapvote_count; ++i)
+ if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ WriteByte(MSG_ENTITY, mapvote_selections[i]);
+
+ WriteByte(MSG_ENTITY, to.mapvote);
+ }
+
+ return TRUE;
+}
+
+void MapVote_Spawn()
+{
+ Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity);
+}
+
+void MapVote_TouchMask()
+{
+ mapvote_ent.SendFlags |= 2;
+}
+
+void MapVote_TouchVotes(entity voter)
+{
+ mapvote_ent.SendFlags |= 4;
+}
+
+float MapVote_Finished(float mappos)
+{
+ if(alreadychangedlevel)
+ return FALSE;
+
+ string result;
+ float i;
+ float didntvote;
+
+ if(autocvar_sv_eventlog)
+ {
+ result = strcat(":vote:finished:", mapvote_maps[mappos]);
+ result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::");
+ didntvote = mapvote_voters;
+ for(i = 0; i < mapvote_count; ++i)
+ if(mapvote_maps_availability[i] == GTV_AVAILABLE )
+ {
+ didntvote -= mapvote_selections[i];
+ if(i != mappos)
+ {
+ result = strcat(result, ":", mapvote_maps[i]);
+ result = strcat(result, ":", ftos(mapvote_selections[i]));
+ }
+ }
+ result = strcat(result, ":didn't vote:", ftos(didntvote));
+
+ GameLogEcho(result);
+ if(mapvote_maps_suggested[mappos])
+ GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos]));
+ }
+
+ FOR_EACH_REALCLIENT(other)
+ FixClientCvars(other);
+
+ if(gametypevote)
+ {
+ if ( GameTypeVote_Finished(mappos) )
+ {
+ gametypevote = FALSE;
+ if(autocvar_nextmap != "")
+ {
+ Map_Goto_SetStr(autocvar_nextmap);
+ Map_Goto(0);
+ alreadychangedlevel = TRUE;
+ return TRUE;
+ }
+ else
+ MapVote_Init();
+ }
+ return FALSE;
+ }
+
+ Map_Goto_SetStr(mapvote_maps[mappos]);
+ Map_Goto(0);
+ alreadychangedlevel = TRUE;
+
+ return TRUE;
+}
+
+void MapVote_CheckRules_1()
+{
+ float i;
+
+ for(i = 0; i < mapvote_count; ++i)
+ if( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ {
+ //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
+ mapvote_selections[i] = 0;
+ }
+
+ mapvote_voters = 0;
+ FOR_EACH_REALCLIENT(other)
+ {
+ ++mapvote_voters;
+ if(other.mapvote)
+ {
+ i = other.mapvote - 1;
+ //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n");
+ mapvote_selections[i] = mapvote_selections[i] + 1;
+ }
+ }
+}
+
+float MapVote_CheckRules_2()
+{
+ float i;
+ float firstPlace, secondPlace, currentPlace;
+ float firstPlaceVotes, secondPlaceVotes, currentVotes;
+ float mapvote_voters_real;
+ string result;
+
+ if(mapvote_count_real == 1)
+ return MapVote_Finished(0);
+
+ mapvote_voters_real = mapvote_voters;
+ if(mapvote_abstain)
+ mapvote_voters_real -= mapvote_selections[mapvote_count - 1];
+
+ RandomSelection_Init();
+ currentPlace = 0;
+ currentVotes = -1;
+ for(i = 0; i < mapvote_count_real; ++i)
+ if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ {
+ RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
+ if ( gametypevote && mapvote_maps[i] == MapInfo_Type_ToString(MapInfo_CurrentGametype()) )
+ {
+ currentVotes = mapvote_selections[i];
+ currentPlace = i;
+ }
+ }
+ firstPlaceVotes = RandomSelection_best_priority;
+ if ( autocvar_sv_vote_gametype_default_current && currentVotes == firstPlaceVotes )
+ firstPlace = currentPlace;
+ else
+ firstPlace = RandomSelection_chosen_float;
+
+ //dprint("First place: ", ftos(firstPlace), "\n");
+ //dprint("First place votes: ", ftos(firstPlaceVotes), "\n");
+
+ RandomSelection_Init();
+ for(i = 0; i < mapvote_count_real; ++i)
+ if(i != firstPlace)
+ if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
+ secondPlace = RandomSelection_chosen_float;
+ secondPlaceVotes = RandomSelection_best_priority;
+ //dprint("Second place: ", ftos(secondPlace), "\n");
+ //dprint("Second place votes: ", ftos(secondPlaceVotes), "\n");
+
+ if(firstPlace == -1)
+ error("No first place in map vote... WTF?");
+
+ if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes)
+ return MapVote_Finished(firstPlace);
+
+ if(mapvote_keeptwotime)
+ if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes)
+ {
+ float didntvote;
+ MapVote_TouchMask();
+ mapvote_message = "Now decide between the TOP TWO!";
+ mapvote_keeptwotime = 0;
+ result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]);
+ result = strcat(result, ":", ftos(firstPlaceVotes));
+ result = strcat(result, ":", mapvote_maps[secondPlace]);
+ result = strcat(result, ":", ftos(secondPlaceVotes), "::");
+ didntvote = mapvote_voters;
+ for(i = 0; i < mapvote_count; ++i)
+ {
+ didntvote -= mapvote_selections[i];
+ if(i != firstPlace)
+ if(i != secondPlace)
+ {
+ result = strcat(result, ":", mapvote_maps[i]);
+ result = strcat(result, ":", ftos(mapvote_selections[i]));
+ if(i < mapvote_count_real)
+ {
+ mapvote_maps_availability[i] = GTV_FORBIDDEN;
+ }
+ }
+ }
+ result = strcat(result, ":didn't vote:", ftos(didntvote));
+ if(autocvar_sv_eventlog)
+ GameLogEcho(result);
+ }
+
+ return FALSE;
+}
+
+void MapVote_Tick()
+{
+ float keeptwo;
+ float totalvotes;
+
+ keeptwo = mapvote_keeptwotime;
+ MapVote_CheckRules_1(); // count
+ if(MapVote_CheckRules_2()) // decide
+ return;
+
+ totalvotes = 0;
+ FOR_EACH_REALCLIENT(other)
+ {
+ // hide scoreboard again
+ if(other.health != 2342)
+ {
+ other.health = 2342;
+ other.impulse = 0;
+ if(IS_REAL_CLIENT(other))
+ {
+ msg_entity = other;
+ WriteByte(MSG_ONE, SVC_FINALE);
+ WriteString(MSG_ONE, "");
+ }
+ }
+
+ // clear possibly invalid votes
+ if ( mapvote_maps_availability[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 )
+ {
+ other.mapvote = other.impulse;
+ MapVote_TouchVotes(other);
+ }
+ other.impulse = 0;
+
+ if(other.mapvote)
+ ++totalvotes;
+ }
+
+ MapVote_CheckRules_1(); // just count
+}
+
+void MapVote_Start()
+{
+ if(mapvote_run)
+ return;
+
+ // wait for stats to be sent first
+ if(!playerstats_waitforme)
+ return;
+
+ MapInfo_Enumerate();
+ if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
+ mapvote_run = TRUE;
+}
+
+void MapVote_Think()
+{
+ if(!mapvote_run)
+ return;
+
+ if(alreadychangedlevel)
+ return;
+
+ if(time < mapvote_nextthink)
+ return;
+ //dprint("tick\n");
+
+ mapvote_nextthink = time + 0.5;
+
+ if(!mapvote_initialized)
+ {
+ if(autocvar_rescan_pending == 1)
+ {
+ cvar_set("rescan_pending", "2");
+ localcmd("fs_rescan\nrescan_pending 3\n");
+ return;
+ }
+ else if(autocvar_rescan_pending == 2)
+ {
+ return;
+ }
+ else if(autocvar_rescan_pending == 3)
+ {
+ // now build missing mapinfo files
+ if(!MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
+ return;
+
+ // we're done, start the timer
+ cvar_set("rescan_pending", "0");
+ }
+
+ mapvote_initialized = TRUE;
+ if(DoNextMapOverride(0))
+ return;
+ if(!autocvar_g_maplist_votable || player_count <= 0)
+ {
+ GotoNextMap(0);
+ return;
+ }
+
+ if(autocvar_sv_vote_gametype) { GameTypeVote_Start(); }
+ else if(autocvar_nextmap == "") { MapVote_Init(); }
+ }
+
+ MapVote_Tick();
+}
+
+float GameTypeVote_SetGametype(float type)
+{
+ if (MapInfo_CurrentGametype() == type)
+ return TRUE;
+
+ float tsave = MapInfo_CurrentGametype();
+
+ MapInfo_SwitchGameType(type);
+
+ MapInfo_Enumerate();
+ MapInfo_FilterGametype(type, MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+ if(MapInfo_count > 0)
+ {
+ // update lsmaps in case the gametype changed, this way people can easily list maps for it
+ if(lsmaps_reply != "") { strunzone(lsmaps_reply); }
+ lsmaps_reply = strzone(getlsmaps());
+ bprint("Game type successfully switched to ", MapInfo_Type_ToString(type), "\n");
+ }
+ else
+ {
+ bprint("Cannot use this game type: no map for it found\n");
+ MapInfo_SwitchGameType(tsave);
+ MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+ return FALSE;
+ }
+
+ //localcmd("gametype ", MapInfo_Type_ToString(type), "\n");
+
+ cvar_set("g_maplist", MapInfo_ListAllowedMaps(type, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()) );
+ if(autocvar_g_maplist_shuffle)
+ ShuffleMaplist();
+
+ return TRUE;
+}
+
+float gametypevote_finished;
+float GameTypeVote_Finished(float pos)
+{
+ if(!gametypevote || gametypevote_finished)
+ return FALSE;
+
+ if ( !GameTypeVote_SetGametype(MapInfo_Type_FromString(mapvote_maps[pos])) )
+ {
+ dprint("Selected gametype is not supported by any map");
+ }
+
+ localcmd("sv_vote_gametype_hook_all\n");
+ localcmd("sv_vote_gametype_hook_", mapvote_maps[pos], "\n");
+
+ gametypevote_finished = TRUE;
+
+ return TRUE;
+}
+
+float GameTypeVote_AddVotable(string nextMode)
+{
+ float j;
+ if ( nextMode == "" || MapInfo_Type_FromString(nextMode) == 0 )
+ return FALSE;
+ for(j = 0; j < mapvote_count; ++j)
+ if(mapvote_maps[j] == nextMode)
+ return FALSE;
+
+ mapvote_maps[mapvote_count] = strzone(nextMode);
+ mapvote_maps_suggested[mapvote_count] = FALSE;
+
+ mapvote_maps_screenshot_dir[mapvote_count] = 0;
+ mapvote_maps_pakfile[mapvote_count] = strzone("");
+ mapvote_maps_availability[mapvote_count] = GameTypeVote_AvailabilityStatus(nextMode);
+
+ mapvote_count += 1;
+
+ return TRUE;
+
+}
+
+float GameTypeVote_Start()
+{
+ float j;
+ MapVote_ClearAllVotes();
+ MapVote_UnzoneStrings();
+
+ mapvote_count = 0;
+ mapvote_timeout = time + autocvar_sv_vote_gametype_timeout;
+ mapvote_abstain = 0;
+ mapvote_detail = !autocvar_g_maplist_votable_nodetail;
+
+ float n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " ");
+ n = min(MAPVOTE_COUNT, n);
+
+ float really_available, which_available;
+ really_available = 0;
+ which_available = -1;
+ for(j = 0; j < n; ++j)
+ {
+ if ( GameTypeVote_AddVotable(argv(j)) )
+ if ( mapvote_maps_availability[j] == GTV_AVAILABLE )
+ {
+ really_available++;
+ which_available = j;
+ }
+ }
+
+ mapvote_count_real = mapvote_count;
+
+ gametypevote = 1;
+
+ if ( really_available == 0 )
+ {
+ if ( mapvote_count > 0 )
+ strunzone(mapvote_maps[0]);
+ mapvote_maps[0] = strzone(MapInfo_Type_ToString(MapInfo_CurrentGametype()));
+ //GameTypeVote_Finished(0);
+ MapVote_Finished(0);
+ return FALSE;
+ }
+ if ( really_available == 1 )
+ {
+ //GameTypeVote_Finished(which_available);
+ MapVote_Finished(which_available);
+ return FALSE;
+ }
+
+ mapvote_count_real = mapvote_count;
+
+ mapvote_keeptwotime = time + autocvar_sv_vote_gametype_keeptwotime;
+ if(mapvote_count_real < 3 || mapvote_keeptwotime <= time)
+ mapvote_keeptwotime = 0;
+
+ MapVote_Spawn();
+
+ return TRUE;
+}
--- /dev/null
+// definitions for functions used outside mapvoting.qc
+void MapVote_Start();
+void MapVote_Spawn();
+void MapVote_Think();
+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_initialized;
+float mapvote_keeptwotime;
+float mapvote_timeout;
+string mapvote_message;
+#define 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;
{
// forcibly turn off weaponarena
}
- else if (s == "all")
+ else if (s == "all" || s == "1")
{
g_weaponarena = 1;
g_weaponarena_list = "All Weapons";
float sv_taunt;
string GetGametype(); // g_world.qc
+void mutators_add(); // mutators.qc
void readlevelcvars(void)
{
// load mutators
- #define CHECK_MUTATOR_ADD(mut_cvar,mut_name,dependence) \
- { if(cvar(mut_cvar) && dependence) { MUTATOR_ADD(mut_name); } }
-
- CHECK_MUTATOR_ADD("g_dodging", mutator_dodging, 1);
- CHECK_MUTATOR_ADD("g_spawn_near_teammate", mutator_spawn_near_teammate, teamplay);
- CHECK_MUTATOR_ADD("g_physical_items", mutator_physical_items, 1);
- CHECK_MUTATOR_ADD("g_touchexplode", mutator_touchexplode, 1);
- CHECK_MUTATOR_ADD("g_minstagib", mutator_minstagib, 1);
- CHECK_MUTATOR_ADD("g_invincible_projectiles", mutator_invincibleprojectiles, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_new_toys", mutator_new_toys, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_nix", mutator_nix, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_rocket_flying", mutator_rocketflying, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_vampire", mutator_vampire, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_superspectate", mutator_superspec, 1);
- CHECK_MUTATOR_ADD("g_pinata", mutator_pinata, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_midair", mutator_midair, 1);
- CHECK_MUTATOR_ADD("g_bloodloss", mutator_bloodloss, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_random_gravity", mutator_random_gravity, 1);
- CHECK_MUTATOR_ADD("g_multijump", mutator_multijump, 1);
- CHECK_MUTATOR_ADD("g_melee_only", mutator_melee_only, !cvar("g_minstagib"));
- CHECK_MUTATOR_ADD("g_nades", mutator_nades, 1);
- CHECK_MUTATOR_ADD("g_sandbox", sandbox, 1);
- CHECK_MUTATOR_ADD("g_campcheck", mutator_campcheck, 1);
-
- #undef CHECK_MUTATOR_ADD
+ mutators_add();
if(cvar("sv_allow_fullbright"))
serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
sv_clones = cvar("sv_clones");
sv_foginterval = cvar("sv_foginterval");
g_cloaked = cvar("g_cloaked");
- if(g_cts)
- g_cloaked = 1; // always enable cloak in CTS
g_footsteps = cvar("g_footsteps");
g_grappling_hook = cvar("g_grappling_hook");
g_jetpack = cvar("g_jetpack");
return TRUE;
}
-#ifdef COMPAT_XON010_CHANNELS
-void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
-void sound(entity e, float chan, string samp, float vol, float atten)
-{
- if (!sound_allowed(MSG_BROADCAST, e))
- return;
- builtin_sound(e, chan, samp, vol, atten);
-}
-#else
#undef sound
void sound(entity e, float chan, string samp, float vol, float atten)
{
return;
sound7(e, chan, samp, vol, atten, 0, 0);
}
-#endif
void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
{
{
// gamemode related things
precache_model ("models/misc/chatbubble.spr");
+ precache_model("models/ice/ice.md3");
#ifdef TTURRETS_ENABLED
if (autocvar_g_turrets)
return s;
}
-float race_readTime(string map, float pos)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
-}
-
-string race_readUID(string map, float pos)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
-}
-
-float race_readPos(string map, float t) {
- float i;
- for (i = 1; i <= RANKINGS_CNT; ++i)
- if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
- return i;
-
- return 0; // pos is zero if unranked
-}
-
-void race_writeTime(string map, float t, string myuid)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- float newpos;
- newpos = race_readPos(map, t);
-
- float i, prevpos = 0;
- for(i = 1; i <= RANKINGS_CNT; ++i)
- {
- if(race_readUID(map, i) == myuid)
- prevpos = i;
- }
- if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
- for (i = prevpos; i > newpos; --i) {
- db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
- db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
- }
- } else { // player has no ranked record yet
- for (i = RANKINGS_CNT; i > newpos; --i) {
- db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
- db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
- }
- }
-
- // store new time itself
- db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
- db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
-}
-
-string race_readName(string map, float pos)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
-}
-
float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
{
float m, i;
return r; // callbacks return an error status, so 0 is default return value
}
-#define MAX_MUTATORS 8
+#define MAX_MUTATORS 15
string loaded_mutators[MAX_MUTATORS];
float Mutator_Add(mutatorfunc_t func, string name)
{
// called when a player presses the jump key
// INPUT, OUTPUT:
float player_multijump;
+ float player_jumpheight;
MUTATOR_HOOKABLE(GiveFragsForKill);
// called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill
MUTATOR_HOOKABLE(ForbidThrowCurrentWeapon);
// returns 1 if throwing the current weapon shall not be allowed
+MUTATOR_HOOKABLE(WeaponRateFactor);
+ // allows changing attack rate
+ // INPUT, OUTPUT:
+ float weapon_rate;
+
MUTATOR_HOOKABLE(SetStartItems);
// adjusts {warmup_}start_{items,weapons,ammo_{cells,rockets,nails,shells,fuel}}
MUTATOR_HOOKABLE(PlayerRegen);
// called every player think frame
// return 1 to disable regen
+ // INPUT, OUTPUT:
+ float regen_mod_max;
+ float regen_mod_regen;
+ float regen_mod_rot;
+ float regen_mod_limit;
MUTATOR_HOOKABLE(PlayerUseKey);
// called when the use key is pressed
#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == ca_teams)
float CA_CheckWinner()
{
+ entity e;
if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
{
Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
allowed_to_spawn = FALSE;
round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+ FOR_EACH_PLAYER(e)
+ nades_Clear(e);
return 1;
}
allowed_to_spawn = FALSE;
round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+
+ FOR_EACH_PLAYER(e)
+ nades_Clear(e);
+
return 1;
}
player.throw_prevtime = time;
player.throw_count = 0;
+ nades_GiveBonus(player, autocvar_g_nades_bonus_score_high );
+
// messages and sounds
Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((enemy_flag.team) ? APP_TEAM_ENT_4(enemy_flag, CENTER_CTF_CAPTURE_) : CENTER_CTF_CAPTURE_NEUTRAL));
ctf_CaptureRecord(enemy_flag, player);
{
PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_return); // reward for return
PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns
+
+ nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium);
}
TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
// scoring
PlayerScore_Add(player, SP_CTF_PICKUPS, 1);
+ nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor);
switch(pickuptype)
{
case PICKUP_BASE:
FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
// special touch behaviors
- if(toucher.vehicle_flags & VHF_ISVEHICLE)
+ if(toucher.frozen) { return; }
+ else if(toucher.vehicle_flags & VHF_ISVEHICLE)
{
if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
toucher = toucher.owner; // the player is actually the vehicle owner, not other
--- /dev/null
+// legacy bot roles
+.float race_checkpoint;
+void havocbot_role_cts()
+{
+ if(self.deadflag != DEAD_NO)
+ return;
+
+ entity e;
+ if (self.bot_strategytime < time)
+ {
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_start();
+
+ for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
+ {
+ if(e.cnt == self.race_checkpoint)
+ {
+ navigation_routerating(e, 1000000, 5000);
+ }
+ else if(self.race_checkpoint == -1)
+ {
+ navigation_routerating(e, 1000000, 5000);
+ }
+ }
+
+ navigation_goalrating_end();
+ }
+}
+
+void cts_ScoreRules()
+{
+ ScoreRules_basics(0, 0, 0, FALSE);
+ if(g_race_qualifying)
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ else
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ ScoreRules_basics_end();
+}
+
+void cts_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
+{
+ if(autocvar_sv_eventlog)
+ GameLogEcho(strcat(":cts:", mode, ":", ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerPhysics)
+{
+ // force kbd movement for fairness
+ float wishspeed;
+ vector wishvel;
+
+ // if record times matter
+ // ensure nothing EVIL is being done (i.e. div0_evade)
+ // this hinders joystick users though
+ // but it still gives SOME analog control
+ wishvel_x = fabs(self.movement_x);
+ wishvel_y = fabs(self.movement_y);
+ if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y)
+ {
+ wishvel_z = 0;
+ wishspeed = vlen(wishvel);
+ if(wishvel_x >= 2 * wishvel_y)
+ {
+ // pure X motion
+ if(self.movement_x > 0)
+ self.movement_x = wishspeed;
+ else
+ self.movement_x = -wishspeed;
+ self.movement_y = 0;
+ }
+ else if(wishvel_y >= 2 * wishvel_x)
+ {
+ // pure Y motion
+ self.movement_x = 0;
+ if(self.movement_y > 0)
+ self.movement_y = wishspeed;
+ else
+ self.movement_y = -wishspeed;
+ }
+ else
+ {
+ // diagonal
+ if(self.movement_x > 0)
+ self.movement_x = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_x = -M_SQRT1_2 * wishspeed;
+ if(self.movement_y > 0)
+ self.movement_y = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_y = -M_SQRT1_2 * wishspeed;
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ResetMap)
+{
+ float s;
+
+ Score_NicePrint(world);
+
+ race_ClearRecords();
+ PlayerScore_Sort(race_place, 0, 1, 0);
+
+ entity e;
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.race_place)
+ {
+ s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+ if(!s)
+ e.race_place = 0;
+ }
+ cts_EventLog(ftos(e.race_place), e);
+ }
+
+ if(g_race_qualifying == 2)
+ {
+ g_race_qualifying = 0;
+ independent_players = 0;
+ cvar_set("fraglimit", ftos(race_fraglimit));
+ cvar_set("leadlimit", ftos(race_leadlimit));
+ cvar_set("timelimit", ftos(race_timelimit));
+ cts_ScoreRules();
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerPreThink)
+{
+ if(IS_SPEC(self) || IS_OBSERVER(self))
+ if(g_race_qualifying)
+ if(msg_entity.enemy.race_laptime)
+ race_SendNextCheckpoint(msg_entity.enemy, 1);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ClientConnect)
+{
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ if(IS_REAL_CLIENT(self))
+ {
+ string rr = CTS_RECORD;
+
+ msg_entity = self;
+ race_send_recordtime(MSG_ONE);
+ race_send_speedaward(MSG_ONE);
+
+ speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+ speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+ race_send_speedaward_alltimebest(MSG_ONE);
+
+ float i;
+ for (i = 1; i <= RANKINGS_CNT; ++i)
+ {
+ race_SendRankings(i, 0, 0, MSG_ONE);
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_MakePlayerObserver)
+{
+ if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerSpawn)
+{
+ if(spawn_spot.target == "")
+ // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+ race_PreparePlayer();
+
+ // if we need to respawn, do it right
+ self.race_respawn_checkpoint = self.race_checkpoint;
+ self.race_respawn_spotref = spawn_spot;
+
+ self.race_place = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PutClientInServer)
+{
+ if(IS_PLAYER(self))
+ if(!gameover)
+ {
+ if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
+ race_PreparePlayer();
+ else // respawn
+ race_RetractPlayer();
+
+ race_AbandonRaceCheck(self);
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerDies)
+{
+ self.respawn_flags |= RESPAWN_FORCE;
+ race_AbandonRaceCheck(self);
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_BotRoles)
+{
+ self.havocbot_role = havocbot_role_cts;
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerPostThink)
+{
+ if(self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
+ {
+ if (!self.stored_netname)
+ self.stored_netname = strzone(uid2name(self.crypto_idfp));
+ if(self.stored_netname != self.netname)
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
+ strunzone(self.stored_netname);
+ self.stored_netname = strzone(self.netname);
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ForbidThrowing)
+{
+ // no weapon dropping in CTS
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_FilterItem)
+{
+ if(self.classname == "droppedweapon")
+ return TRUE;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerDamage)
+{
+ if(frag_target == frag_attacker || frag_deathtype == DEATH_FALL)
+ if(!autocvar_g_cts_selfdamage)
+ frag_damage = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ForbidClearPlayerScore)
+{
+ return TRUE; // in CTS, you don't lose score by observing
+}
+
+MUTATOR_HOOKFUNCTION(cts_SetMods)
+{
+ g_cloaked = 1; // always enable cloak in CTS
+
+ return FALSE;
+}
+
+void cts_Initialize()
+{
+ cts_ScoreRules();
+}
+
+MUTATOR_DEFINITION(gamemode_cts)
+{
+ MUTATOR_HOOK(PlayerPhysics, cts_PlayerPhysics, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_global, cts_ResetMap, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, cts_PlayerPreThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, cts_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, cts_MakePlayerObserver, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, cts_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PutClientInServer, cts_PutClientInServer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, cts_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(HavocBot_ChooseRole, cts_BotRoles, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetPressedKeys, cts_PlayerPostThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, cts_ForbidThrowing, CBC_ORDER_ANY);
+ MUTATOR_HOOK(FilterItem, cts_FilterItem, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDamage_Calculate, cts_PlayerDamage, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, cts_ForbidClearPlayerScore, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SetModname, cts_SetMods, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ cts_Initialize();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back cts_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+float g_race_qualifying;
+
+// scores
+#define ST_CTS_LAPS 1
+#define SP_CTS_LAPS 4
+#define SP_CTS_TIME 5
+#define SP_CTS_FASTEST 6
e.dom_total_pps = total_pps;
e.dom_pps_red = pps_red;
e.dom_pps_blue = pps_blue;
- if(c3 >= 0)
+ if(domination_teams >= 3)
e.dom_pps_yellow = pps_yellow;
- if(c4 >= 0)
+ if(domination_teams >= 4)
e.dom_pps_pink = pps_pink;
}
else
wait_time = self.wait;
- bprint("^3", head.netname, "^3", self.message);
- if (points != 1)
- bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
+ if(domination_roundbased)
+ bprint(sprintf("^3%s^3%s\n", head.netname, self.message));
else
- bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_DOMINATION_CAPTURE_TIME, head.netname, self.message, points, wait_time);
if(self.enemy.playerid == self.enemy_playerid)
PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
break;
case NUM_TEAM_4:
pps_pink += points/wait_time;
+ break;
}
total_pps += points/wait_time;
}
// give credit to the team
// NOTE: this defaults to 0
+ if (!domination_roundbased)
if (self.goalentity.netname != "")
{
if(autocvar_g_domination_point_amt)
if (other.health < 1)
return;
+ if(round_handler_IsActive() && !round_handler_IsRoundStarted())
+ return;
+
if(time < self.captime + 0.3)
return;
WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
}
+float total_controlpoints, redowned, blueowned, yellowowned, pinkowned;
+void Domination_count_controlpoints()
+{
+ entity e;
+ total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
+ for(e = world; (e = find(e, classname, "dom_controlpoint")) != world; )
+ {
+ ++total_controlpoints;
+ redowned += (e.goalentity.team == NUM_TEAM_1);
+ blueowned += (e.goalentity.team == NUM_TEAM_2);
+ yellowowned += (e.goalentity.team == NUM_TEAM_3);
+ pinkowned += (e.goalentity.team == NUM_TEAM_4);
+ }
+}
+
+float Domination_GetWinnerTeam()
+{
+ float winner_team = 0;
+ if(redowned == total_controlpoints)
+ winner_team = NUM_TEAM_1;
+ if(blueowned == total_controlpoints)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_2;
+ }
+ if(yellowowned == total_controlpoints)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_3;
+ }
+ if(pinkowned == total_controlpoints)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no control points left?
+}
+
+#define DOM_OWNED_CONTROLPOINTS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
+#define DOM_OWNED_CONTROLPOINTS_OK() (DOM_OWNED_CONTROLPOINTS() < total_controlpoints)
+float Domination_CheckWinner()
+{
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
+ round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+ return 1;
+ }
+
+ Domination_count_controlpoints();
+
+ float winner_team = Domination_GetWinnerTeam();
+
+ if(winner_team == -1)
+ return 0;
+
+ if(winner_team > 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
+ TeamScore_AddToTeam(winner_team, ST_DOM_CAPS, +1);
+ }
+ else if(winner_team == -1)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
+ }
+
+ round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+
+ return 1;
+}
+
+float Domination_CheckPlayers()
+{
+ return 1;
+}
+
+void Domination_RoundStart()
+{
+ entity e;
+ FOR_EACH_PLAYER(e)
+ e.player_blocked = 0;
+}
+
//go to best items, or control points you don't own
void havocbot_role_dom()
{
}
}
+MUTATOR_HOOKFUNCTION(dom_GetTeamCount)
+{
+ ret_float = domination_teams;
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(dom_ResetMap)
+{
+ total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+ FOR_EACH_PLAYER(self)
+ {
+ PutClientInServer();
+ self.player_blocked = 1;
+ if(IS_REAL_CLIENT(self))
+ set_dom_state(self);
+ }
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(dom_PlayerSpawn)
+{
+ if(domination_roundbased)
+ if(!round_handler_IsRoundStarted())
+ self.player_blocked = 1;
+ else
+ self.player_blocked = 0;
+ return FALSE;
+}
+
MUTATOR_HOOKFUNCTION(dom_ClientConnect)
{
set_dom_state(self);
}
// scoreboard setup
-void ScoreRules_dom()
+void ScoreRules_dom(float teams)
{
- float sp_domticks, sp_score;
- sp_score = sp_domticks = 0;
- if(autocvar_g_domination_disable_frags)
- sp_domticks = SFL_SORT_PRIO_PRIMARY;
+ if(domination_roundbased)
+ {
+ ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, TRUE);
+ ScoreInfo_SetLabel_TeamScore (ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES, "takes", 0);
+ ScoreRules_basics_end();
+ }
else
- sp_score = SFL_SORT_PRIO_PRIMARY;
- CheckAllowedTeams(world);
- ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), sp_score, sp_score, TRUE);
- ScoreInfo_SetLabel_TeamScore (ST_DOM_TICKS, "ticks", sp_domticks);
- ScoreInfo_SetLabel_PlayerScore(SP_DOM_TICKS, "ticks", sp_domticks);
- ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES, "takes", 0);
- ScoreRules_basics_end();
+ {
+ float sp_domticks, sp_score;
+ sp_score = sp_domticks = 0;
+ if(autocvar_g_domination_disable_frags)
+ sp_domticks = SFL_SORT_PRIO_PRIMARY;
+ else
+ sp_score = SFL_SORT_PRIO_PRIMARY;
+ ScoreRules_basics(teams, sp_score, sp_score, TRUE);
+ ScoreInfo_SetLabel_TeamScore (ST_DOM_TICKS, "ticks", sp_domticks);
+ ScoreInfo_SetLabel_PlayerScore(SP_DOM_TICKS, "ticks", sp_domticks);
+ ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES, "takes", 0);
+ ScoreRules_basics_end();
+ }
}
// code from here on is just to support maps that don't have control point and team entities
}
// spawn some default teams if the map is not set up for domination
-void dom_spawnteams()
+void dom_spawnteams(float teams)
{
- float numteams = ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override);
-
dom_spawnteam("Red", NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
dom_spawnteam("Blue", NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
- if(numteams > 2)
+ if(teams >= 3)
dom_spawnteam("Yellow", NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
- if(numteams > 3)
+ if(teams >= 4)
dom_spawnteam("Pink", NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
}
if(find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
{
print("No ""dom_team"" entities found on this map, creating them anyway.\n");
- dom_spawnteams();
+ domination_teams = bound(2, ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override), 4);
+ dom_spawnteams(domination_teams);
}
+
+ CheckAllowedTeams(world);
+ domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
+
+ addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
+ addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
+ addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
+ if(domination_teams >= 3) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
+ if(domination_teams >= 4) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
+
+ domination_roundbased = autocvar_g_domination_roundbased;
+
+ ScoreRules_dom(domination_teams);
- ScoreRules_dom();
+ if(domination_roundbased)
+ {
+ round_handler_Spawn(Domination_CheckPlayers, Domination_CheckWinner, Domination_RoundStart);
+ round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+ }
}
void dom_Initialize()
precache_model("models/domination/dom_unclaimed.md3");
precache_sound("domination/claim.wav");
- addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
- addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
- addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
- if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
- if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
-
InitializeEntity(world, dom_DelayedInit, INITPRIO_GAMETYPE);
}
MUTATOR_DEFINITION(gamemode_domination)
{
+ MUTATOR_HOOK(GetTeamCount, dom_GetTeamCount, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_players, dom_ResetMap, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, dom_PlayerSpawn, CBC_ORDER_ANY);
MUTATOR_HOOK(ClientConnect, dom_ClientConnect, CBC_ORDER_ANY);
MUTATOR_HOOK(HavocBot_ChooseRole, dom_BotRoles, CBC_ORDER_ANY);
#define ST_DOM_TICKS 1
#define SP_DOM_TICKS 4
#define SP_DOM_TAKES 5
+#define ST_DOM_CAPS 1
+#define SP_DOM_CAPS 4
// pps: points per second
.float dom_total_pps;
// capture declarations
.float enemy_playerid;
.entity sprite;
-.float captime;
\ No newline at end of file
+.float captime;
+
+// misc globals
+float domination_roundbased;
+float domination_teams;
.float freezetag_frozen_time;
.float freezetag_frozen_timeout;
.float freezetag_revive_progress;
-.entity freezetag_ice;
#define ICE_MAX_ALPHA 1
#define ICE_MIN_ALPHA 0.1
float freezetag_teams;
{
entity e;
total_players = redalive = bluealive = yellowalive = pinkalive = 0;
- FOR_EACH_PLAYER(e) {
- if(e.team == NUM_TEAM_1 && e.health >= 1)
- {
- ++total_players;
- if (!e.freezetag_frozen) ++redalive;
- }
- else if(e.team == NUM_TEAM_2 && e.health >= 1)
- {
- ++total_players;
- if (!e.freezetag_frozen) ++bluealive;
- }
- else if(e.team == NUM_TEAM_3 && e.health >= 1)
- {
- ++total_players;
- if (!e.freezetag_frozen) ++yellowalive;
- }
- else if(e.team == NUM_TEAM_4 && e.health >= 1)
+ FOR_EACH_PLAYER(e)
+ {
+ switch(e.team)
{
- ++total_players;
- if (!e.freezetag_frozen) ++pinkalive;
+ case NUM_TEAM_1: ++total_players; if(e.health >= 1 && e.frozen != 1) ++redalive; break;
+ case NUM_TEAM_2: ++total_players; if(e.health >= 1 && e.frozen != 1) ++bluealive; break;
+ case NUM_TEAM_3: ++total_players; if(e.health >= 1 && e.frozen != 1) ++yellowalive; break;
+ case NUM_TEAM_4: ++total_players; if(e.health >= 1 && e.frozen != 1) ++pinkalive; break;
}
}
- FOR_EACH_REALCLIENT(e) {
+ FOR_EACH_REALCLIENT(e)
+ {
e.redalive_stat = redalive;
e.bluealive_stat = bluealive;
e.yellowalive_stat = yellowalive;
FOR_EACH_PLAYER(e)
{
e.freezetag_frozen_timeout = 0;
- e.freezetag_revive_progress = 0;
+ nades_Clear(e);
}
round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
return 1;
FOR_EACH_PLAYER(e)
{
e.freezetag_frozen_timeout = 0;
- e.freezetag_revive_progress = 0;
+ nades_Clear(e);
}
round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
return 1;
}
-// this is needed to allow the player to turn his view around (fixangle can't
-// be used to freeze his view, as that also changes the angles), while not
-// turning that ice object with the player
-void freezetag_Ice_Think()
-{
- setorigin(self, self.owner.origin - '0 0 16');
- self.nextthink = time;
-}
-
void freezetag_Add_Score(entity attacker)
{
if(attacker == self)
void freezetag_Freeze(entity attacker)
{
- if(self.freezetag_frozen)
+ if(self.frozen)
return;
- self.freezetag_frozen = 1;
- self.freezetag_frozen_time = time;
- self.freezetag_revive_progress = 0;
- self.health = 1;
+
if(autocvar_g_freezetag_frozen_maxtime > 0)
self.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
- freezetag_count_alive_players();
+ Freeze(self, 0, 1, TRUE);
- entity ice;
- ice = spawn();
- ice.owner = self;
- ice.classname = "freezetag_ice";
- ice.think = freezetag_Ice_Think;
- ice.nextthink = time;
- ice.frame = floor(random() * 21); // ice model has 20 different looking frames
- ice.alpha = ICE_MAX_ALPHA;
- ice.colormod = Team_ColorRGB(self.team);
- ice.glowmod = ice.colormod;
- setmodel(ice, "models/ice/ice.md3");
-
- self.freezetag_ice = ice;
-
- RemoveGrapplingHook(self);
-
- // add waypoint
- WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
+ freezetag_count_alive_players();
freezetag_Add_Score(attacker);
}
void freezetag_Unfreeze(entity attacker)
{
- self.freezetag_frozen = 0;
self.freezetag_frozen_time = 0;
self.freezetag_frozen_timeout = 0;
- self.freezetag_revive_progress = 0;
- remove(self.freezetag_ice);
- self.freezetag_ice = world;
-
- if(self.waypointsprite_attached)
- WaypointSprite_Kill(self.waypointsprite_attached);
+ Unfreeze(self);
}
{
if ((head != self) && (head.team == self.team))
{
- if (head.freezetag_frozen)
+ if (head.frozen == 1)
{
distance = vlen(head.origin - org);
if (distance > sradius)
unfrozen = 0;
FOR_EACH_PLAYER(head)
{
- if ((head.team == self.team) && (!head.freezetag_frozen))
+ if ((head.team == self.team) && (head.frozen != 1))
unfrozen++;
}
// If only one left on team or if role has timed out then start trying to free players.
- if (((unfrozen == 0) && (!self.freezetag_frozen)) || (time > self.havocbot_role_timeout))
+ if (((unfrozen == 0) && (!self.frozen)) || (time > self.havocbot_role_timeout))
{
dprint("changing role to freeing\n");
self.havocbot_role = havocbot_role_ft_freeing;
if(round_handler_IsActive())
if(round_handler_CountdownRunning())
{
- if(self.freezetag_frozen)
+ if(self.frozen)
freezetag_Unfreeze(world);
freezetag_count_alive_players();
return 1; // let the player die so that he can respawn whenever he wants
|| frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
{
// let the player die, he will be automatically frozen when he respawns
- if(!self.freezetag_frozen)
+ if(self.frozen != 1)
{
freezetag_Add_Score(frag_attacker);
freezetag_count_alive_players();
}
else
freezetag_Unfreeze(world); // remove ice
+ self.health = 0; // Unfreeze resets health
self.freezetag_frozen_timeout = -2; // freeze on respawn
return 1;
}
- if(self.freezetag_frozen)
+ if(self.frozen)
return 1;
freezetag_Freeze(frag_attacker);
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
}
- frag_target.health = 1; // "respawn" the player :P
-
return 1;
}
FOR_EACH_PLAYER(self)
{
self.killcount = 0;
- if (self.freezetag_frozen)
- freezetag_Unfreeze(world);
self.freezetag_frozen_timeout = -1;
PutClientInServer();
self.freezetag_frozen_timeout = 0;
if(gameover)
return 1;
- if(self.freezetag_frozen)
+ if(self.frozen == 1)
{
// keep health = 1
self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
entity o;
o = world;
- if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout)
- self.freezetag_ice.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time);
+ //if(self.frozen)
+ //if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout)
+ //self.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time);
if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
n = -1;
{
vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
n = 0;
- FOR_EACH_PLAYER(other) if(self != other)
+ FOR_EACH_PLAYER(other)
+ if(self != other)
+ if(other.frozen == 0)
+ if(other.deadflag == DEAD_NO)
+ if(SAME_TEAM(other, self))
+ if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
{
- if(other.freezetag_frozen == 0)
- {
- if(other.team == self.team)
- {
- if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
- {
- if(!o)
- o = other;
- if(self.freezetag_frozen)
- other.reviving = TRUE;
- ++n;
- }
- }
- }
+ if(!o)
+ o = other;
+ if(self.frozen == 1)
+ other.reviving = TRUE;
+ ++n;
}
}
- if(n && self.freezetag_frozen) // OK, there is at least one teammate reviving us
+ if(n && self.frozen == 1) // OK, there is at least one teammate reviving us
{
- self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
- if(warmup_stage)
- self.health = max(1, self.freezetag_revive_progress * warmup_start_health);
- else
- self.health = max(1, self.freezetag_revive_progress * start_health);
+ self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+ self.health = max(1, self.revive_progress * ((warmup_stage) ? warmup_start_health : start_health));
- if(self.freezetag_revive_progress >= 1)
+ if(self.revive_progress >= 1)
{
freezetag_Unfreeze(self);
freezetag_count_alive_players();
{
PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
PlayerScore_Add(other, SP_SCORE, +1);
+
+ nades_GiveBonus(other,autocvar_g_nades_bonus_score_low);
}
}
{
if(other.reviving)
{
- other.freezetag_revive_progress = self.freezetag_revive_progress;
+ other.revive_progress = self.revive_progress;
other.reviving = FALSE;
}
}
}
- else if(!n && self.freezetag_frozen) // only if no teammate is nearby will we reset
- {
- self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
- if(warmup_stage)
- self.health = max(1, self.freezetag_revive_progress * warmup_start_health);
- else
- self.health = max(1, self.freezetag_revive_progress * start_health);
- }
- else if(!n)
+ else if(!n && self.frozen == 1) // only if no teammate is nearby will we reset
{
- self.freezetag_revive_progress = 0; // thawing nobody
+ self.revive_progress = bound(0, self.revive_progress - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
+ self.health = max(1, self.revive_progress * ((warmup_stage) ? warmup_start_health : start_health));
}
-
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(freezetag_PlayerPhysics)
-{
- if(self.freezetag_frozen)
+ else if(!n && !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;
+ self.revive_progress = 0; // thawing nobody
}
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
-{
- if(frag_target.freezetag_frozen && frag_deathtype != DEATH_HURTTRIGGER)
- {
- if(autocvar_g_freezetag_revive_falldamage > 0)
- if(frag_deathtype == DEATH_FALL)
- if(frag_damage >= autocvar_g_freezetag_revive_falldamage)
- {
- freezetag_Unfreeze(frag_target);
- frag_target.health = autocvar_g_freezetag_revive_falldamage_health;
- pointparticles(particleeffectnum("iceorglass"), frag_target.origin, '0 0 0', 3);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, frag_target.netname);
- Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_FALL);
- }
- frag_damage = 0;
- frag_force = frag_force * autocvar_g_freezetag_frozen_force;
- }
return 1;
}
-MUTATOR_HOOKFUNCTION(freezetag_PlayerJump)
-{
- if(self.freezetag_frozen)
- return TRUE; // no jumping in freezetag when frozen
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon)
-{
- if (self.freezetag_frozen)
- return 1;
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(freezetag_ItemTouch)
-{
- if (other.freezetag_frozen)
- return MUT_ITEMTOUCH_RETURN;
- return MUT_ITEMTOUCH_CONTINUE;
-}
-
MUTATOR_HOOKFUNCTION(freezetag_BotRoles)
{
if (!self.deadflag)
return TRUE;
}
-MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy)
-{
- self.freezetag_frozen = other.freezetag_frozen;
- self.freezetag_revive_progress = other.freezetag_revive_progress;
- return 0;
-}
-
MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount)
{
ret_float = freezetag_teams;
return 0;
}
-MUTATOR_HOOKFUNCTION(freezetag_VehicleTouch)
-{
- if(other.freezetag_frozen)
- return TRUE;
-
- return FALSE;
-}
-
void freezetag_Initialize()
{
- precache_model("models/ice/ice.md3");
-
freezetag_teams = autocvar_g_freezetag_teams_override;
if(freezetag_teams < 2)
freezetag_teams = autocvar_g_freezetag_teams;
addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
-
- addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
- addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
}
MUTATOR_DEFINITION(gamemode_freezetag)
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(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
- MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerJump, freezetag_PlayerJump, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
- MUTATOR_HOOK(ItemTouch, freezetag_ItemTouch, CBC_ORDER_ANY);
MUTATOR_HOOK(HavocBot_ChooseRole, freezetag_BotRoles, CBC_ORDER_ANY);
- MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY);
MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE);
- MUTATOR_HOOK(VehicleTouch, freezetag_VehicleTouch, CBC_ORDER_ANY);
MUTATOR_ONADD
{
return;
}
if(other.deadflag != DEAD_NO) { return; }
+ if(other.frozen) { return; }
if (!IS_PLAYER(other))
{ // The ball just touched an object, most likely the world
pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1);
f = DistributeEvenly_Get(1);
kh_Scores_Event(key.owner, key, "capture", f, 0);
PlayerTeamScore_Add(key.owner, SP_KH_CAPS, ST_KH_CAPS, 1);
+ nades_GiveBonus(key.owner, autocvar_g_nades_bonus_score_high);
}
first = TRUE;
football_touch();
return;
}
- if(!self.cnt && IS_PLAYER(other) && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
+ if(!self.cnt && IS_PLAYER(other) && !other.frozen && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
{
if(other.health <= 0)
return;
--- /dev/null
+// legacy bot roles
+.float race_checkpoint;
+void havocbot_role_race()
+{
+ if(self.deadflag != DEAD_NO)
+ return;
+
+ entity e;
+ if (self.bot_strategytime < time)
+ {
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_start();
+
+ for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
+ {
+ if(e.cnt == self.race_checkpoint)
+ {
+ navigation_routerating(e, 1000000, 5000);
+ }
+ else if(self.race_checkpoint == -1)
+ {
+ navigation_routerating(e, 1000000, 5000);
+ }
+ }
+
+ navigation_goalrating_end();
+ }
+}
+
+void race_ScoreRules()
+{
+ ScoreRules_basics(race_teams, 0, 0, FALSE);
+ if(race_teams)
+ {
+ ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ else if(g_race_qualifying)
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ else
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ ScoreRules_basics_end();
+}
+
+void race_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
+{
+ if(autocvar_sv_eventlog)
+ GameLogEcho(strcat(":race:", mode, ":", ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerPhysics)
+{
+ // force kbd movement for fairness
+ float wishspeed;
+ vector wishvel;
+
+ // if record times matter
+ // ensure nothing EVIL is being done (i.e. div0_evade)
+ // this hinders joystick users though
+ // but it still gives SOME analog control
+ wishvel_x = fabs(self.movement_x);
+ wishvel_y = fabs(self.movement_y);
+ if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y)
+ {
+ wishvel_z = 0;
+ wishspeed = vlen(wishvel);
+ if(wishvel_x >= 2 * wishvel_y)
+ {
+ // pure X motion
+ if(self.movement_x > 0)
+ self.movement_x = wishspeed;
+ else
+ self.movement_x = -wishspeed;
+ self.movement_y = 0;
+ }
+ else if(wishvel_y >= 2 * wishvel_x)
+ {
+ // pure Y motion
+ self.movement_x = 0;
+ if(self.movement_y > 0)
+ self.movement_y = wishspeed;
+ else
+ self.movement_y = -wishspeed;
+ }
+ else
+ {
+ // diagonal
+ if(self.movement_x > 0)
+ self.movement_x = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_x = -M_SQRT1_2 * wishspeed;
+ if(self.movement_y > 0)
+ self.movement_y = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_y = -M_SQRT1_2 * wishspeed;
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_ResetMap)
+{
+ float s;
+
+ Score_NicePrint(world);
+
+ race_ClearRecords();
+ PlayerScore_Sort(race_place, 0, 1, 0);
+
+ entity e;
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.race_place)
+ {
+ s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+ if(!s)
+ e.race_place = 0;
+ }
+ race_EventLog(ftos(e.race_place), e);
+ }
+
+ if(g_race_qualifying == 2)
+ {
+ g_race_qualifying = 0;
+ independent_players = 0;
+ cvar_set("fraglimit", ftos(race_fraglimit));
+ cvar_set("leadlimit", ftos(race_leadlimit));
+ cvar_set("timelimit", ftos(race_timelimit));
+ race_ScoreRules();
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerPreThink)
+{
+ if(IS_SPEC(self) || IS_OBSERVER(self))
+ if(g_race_qualifying)
+ if(msg_entity.enemy.race_laptime)
+ race_SendNextCheckpoint(msg_entity.enemy, 1);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_ClientConnect)
+{
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ string rr = RACE_RECORD;
+
+ if(IS_REAL_CLIENT(self))
+ {
+ msg_entity = self;
+ race_send_recordtime(MSG_ONE);
+ race_send_speedaward(MSG_ONE);
+
+ speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+ speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+ race_send_speedaward_alltimebest(MSG_ONE);
+
+ float i;
+ for (i = 1; i <= RANKINGS_CNT; ++i)
+ {
+ race_SendRankings(i, 0, 0, MSG_ONE);
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_MakePlayerObserver)
+{
+ if(g_race_qualifying)
+ if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerSpawn)
+{
+ if(spawn_spot.target == "")
+ // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+ race_PreparePlayer();
+
+ // if we need to respawn, do it right
+ self.race_respawn_checkpoint = self.race_checkpoint;
+ self.race_respawn_spotref = spawn_spot;
+
+ self.race_place = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PutClientInServer)
+{
+ if(IS_PLAYER(self))
+ if(!gameover)
+ {
+ if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
+ race_PreparePlayer();
+ else // respawn
+ race_RetractPlayer();
+
+ race_AbandonRaceCheck(self);
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerDies)
+{
+ self.respawn_flags |= RESPAWN_FORCE;
+ race_AbandonRaceCheck(self);
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_BotRoles)
+{
+ self.havocbot_role = havocbot_role_race;
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerPostThink)
+{
+ if(self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
+ {
+ if (!self.stored_netname)
+ self.stored_netname = strzone(uid2name(self.crypto_idfp));
+ if(self.stored_netname != self.netname)
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
+ strunzone(self.stored_netname);
+ self.stored_netname = strzone(self.netname);
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_ForbidClearPlayerScore)
+{
+ if(g_race_qualifying)
+ return TRUE; // in qualifying, you don't lose score by observing
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_GetTeamCount)
+{
+ ret_float = race_teams;
+ return FALSE;
+}
+
+void race_Initialize()
+{
+ race_ScoreRules();
+ if(g_race_qualifying == 2)
+ warmup_stage = 0;
+}
+
+MUTATOR_DEFINITION(gamemode_race)
+{
+ MUTATOR_HOOK(PlayerPhysics, race_PlayerPhysics, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_global, race_ResetMap, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, race_PlayerPreThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, race_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, race_MakePlayerObserver, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, race_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PutClientInServer, race_PutClientInServer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, race_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(HavocBot_ChooseRole, race_BotRoles, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetPressedKeys, race_PlayerPostThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, race_ForbidClearPlayerScore, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetTeamCount, race_GetTeamCount, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ race_Initialize();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back race_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+float g_race_qualifying;
+float race_teams;
+
+// scores
+#define ST_RACE_LAPS 1
+#define SP_RACE_LAPS 4
+#define SP_RACE_TIME 5
+#define SP_RACE_FASTEST 6
--- /dev/null
+/*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.
+Keys:
+"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
+"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
+void spawnfunc_tdm_team()
+{
+ if(!g_tdm) { remove(self); return; }
+
+ self.classname = "tdm_team";
+ self.team = self.cnt + 1;
+}
+
+// code from here on is just to support maps that don't have team entities
+void tdm_SpawnTeam (string teamname, float teamcolor)
+{
+ entity oldself;
+ oldself = self;
+ self = spawn();
+ self.classname = "tdm_team";
+ self.netname = teamname;
+ self.cnt = teamcolor;
+
+ spawnfunc_tdm_team();
+
+ self = oldself;
+}
+
+void tdm_DelayedInit()
+{
+ // if no teams are found, spawn defaults
+ if(find(world, classname, "tdm_team") == world)
+ {
+ print("No ""tdm_team"" entities found on this map, creating them anyway.\n");
+
+ float numteams = min(4, autocvar_g_tdm_teams_override);
+
+ if(numteams < 2) { numteams = autocvar_g_tdm_teams; }
+ numteams = bound(2, numteams, 4);
+
+ float i;
+ for(i = 1; i <= numteams; ++i)
+ tdm_SpawnTeam(Team_ColorName(Team_NumberToTeam(i)), Team_NumberToTeam(i) - 1);
+ }
+}
+
+MUTATOR_HOOKFUNCTION(tdm_GetTeamCount)
+{
+ ret_string = "tdm_team";
+ return TRUE;
+}
+
+MUTATOR_DEFINITION(gamemode_tdm)
+{
+ MUTATOR_HOOK(GetTeamCount, tdm_GetTeamCount, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ InitializeEntity(world, tdm_DelayedInit, INITPRIO_GAMETYPE);
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back tdm_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+float buffs_BuffModel_Customize()
+{
+ entity player, myowner;
+ float same_team;
+
+ player = WaypointSprite_getviewentity(other);
+ myowner = self.owner;
+ same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
+
+ if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
+ return FALSE;
+
+ if(player == myowner || (IS_SPEC(other) && other.enemy == myowner))
+ {
+ // somewhat hide the model, but keep the glow
+ self.effects = 0;
+ self.alpha = -1;
+ }
+ else
+ {
+ self.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
+ self.alpha = 1;
+ }
+ return TRUE;
+}
+
+// buff item
+float buff_Waypoint_visible_for_player(entity plr)
+{
+ if(!self.owner.buff_active && !self.owner.buff_activetime)
+ return FALSE;
+
+ if(plr.buffs)
+ {
+ if(plr.cvar_cl_buffs_autoreplace)
+ {
+ if(plr.buffs == self.owner.buffs)
+ return FALSE;
+ }
+ else
+ return FALSE;
+ }
+
+ return WaypointSprite_visible_for_player(plr);
+}
+
+void buff_Waypoint_Spawn(entity e)
+{
+ WaypointSprite_Spawn(Buff_Sprite(e.buffs), 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs_z, world, e.team, e, buff_waypoint, TRUE, RADARICON_POWERUP, e.glowmod);
+ WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_POWERUP, e.glowmod);
+ e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
+}
+
+void buff_SetCooldown(float cd)
+{
+ cd = max(0, cd);
+
+ if(!self.buff_waypoint)
+ buff_Waypoint_Spawn(self);
+
+ WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + cd);
+ self.buff_activetime = cd;
+ self.buff_active = !cd;
+}
+
+void buff_Respawn(entity ent)
+{
+ if(gameover) { return; }
+
+ vector oldbufforigin = ent.origin;
+
+ if(!MoveToRandomMapLocation(ent, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
+ {
+ entity spot = SelectSpawnPoint(TRUE);
+ setorigin(ent, ((spot.origin + '0 0 200') + (randomvec() * 300)));
+ ent.angles = spot.angles;
+ }
+
+ tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent);
+
+ setorigin(ent, trace_endpos); // attempt to unstick
+
+ ent.movetype = MOVETYPE_TOSS;
+
+ makevectors(ent.angles);
+ ent.velocity = '0 0 200';
+ ent.angles = '0 0 0';
+ if(autocvar_g_buffs_random_lifetime > 0)
+ ent.lifetime = time + autocvar_g_buffs_random_lifetime;
+
+ pointparticles(particleeffectnum("electro_combo"), oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1);
+ pointparticles(particleeffectnum("electro_combo"), CENTER_OR_VIEWOFS(ent), '0 0 0', 1);
+
+ WaypointSprite_Ping(ent.buff_waypoint);
+
+ sound(ent, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+}
+
+void buff_Touch()
+{
+ if(gameover) { return; }
+
+ if(ITEM_TOUCH_NEEDKILL())
+ {
+ buff_Respawn(self);
+ return;
+ }
+
+ if((self.team && DIFF_TEAM(other, self))
+ || (other.frozen)
+ || (other.vehicle)
+ || (!IS_PLAYER(other))
+ || (!self.buff_active)
+ )
+ {
+ // can't touch this
+ return;
+ }
+
+ if(other.buffs)
+ {
+ if(other.cvar_cl_buffs_autoreplace && other.buffs != self.buffs)
+ {
+ //Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_DROP, other.buffs);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ITEM_BUFF_LOST, other.netname, other.buffs);
+
+ other.buffs = 0;
+ //sound(other, CH_TRIGGER, "relics/relic_effect.wav", VOL_BASE, ATTN_NORM);
+ }
+ else { return; } // do nothing
+ }
+
+ self.owner = other;
+ self.buff_active = FALSE;
+ self.lifetime = 0;
+
+ Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, self.buffs);
+ Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, self.buffs);
+
+ pointparticles(particleeffectnum("item_pickup"), CENTER_OR_VIEWOFS(self), '0 0 0', 1);
+ sound(other, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTN_NORM);
+ other.buffs |= (self.buffs);
+}
+
+float buff_Available(float buffid)
+{
+ if(buffid == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
+ return FALSE;
+
+ if(buffid == BUFF_VAMPIRE && cvar("g_vampire"))
+ return FALSE;
+
+ if(!cvar(strcat("g_buffs_", Buff_Name(buffid))))
+ return FALSE;
+
+ return TRUE;
+}
+
+void buff_NewType(entity ent, float cb)
+{
+ entity e;
+ RandomSelection_Init();
+ for(e = Buff_Type_first; e; e = e.enemy)
+ if(buff_Available(e.items))
+ {
+ RandomSelection_Add(world, e.items, string_null, 1, 1 / e.count); // if it's already been chosen, give it a lower priority
+ e.count += 1;
+ }
+ ent.buffs = RandomSelection_chosen_float;
+}
+
+void buff_Think()
+{
+ if(self.buffs != self.oldbuffs)
+ {
+ self.color = Buff_Color(self.buffs);
+ self.glowmod = ((self.team) ? Team_ColorRGB(self.team) + '0.1 0.1 0.1' : self.color);
+ self.skin = Buff_Skin(self.buffs);
+
+ setmodel(self, "models/relics/relic.md3");
+
+ if(self.buff_waypoint)
+ {
+ //WaypointSprite_Disown(self.buff_waypoint, 1);
+ WaypointSprite_Kill(self.buff_waypoint);
+ buff_Waypoint_Spawn(self);
+ if(self.buff_activetime)
+ WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + self.buff_activetime - frametime);
+ }
+
+ self.oldbuffs = self.buffs;
+ }
+
+ if(!gameover)
+ if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+ if(!self.buff_activetime_updated)
+ {
+ buff_SetCooldown(self.buff_activetime);
+ self.buff_activetime_updated = TRUE;
+ }
+
+ if(!self.buff_active && !self.buff_activetime)
+ if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs))
+ {
+ buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime);
+ self.owner = world;
+ if(autocvar_g_buffs_randomize)
+ buff_NewType(self, self.buffs);
+
+ if(autocvar_g_buffs_random_location || (self.spawnflags & 1))
+ buff_Respawn(self);
+ }
+
+ if(self.buff_activetime)
+ if(!gameover)
+ if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+ {
+ self.buff_activetime = max(0, self.buff_activetime - frametime);
+
+ if(!self.buff_activetime)
+ {
+ self.buff_active = TRUE;
+ sound(self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTN_NORM);
+ pointparticles(particleeffectnum("item_respawn"), CENTER_OR_VIEWOFS(self), '0 0 0', 1);
+ }
+ }
+
+ if(!self.buff_active)
+ {
+ self.alpha = 0.3;
+ self.effects &= ~(EF_FULLBRIGHT);
+ self.pflags = 0;
+ }
+ else
+ {
+ self.alpha = 1;
+ self.effects |= EF_FULLBRIGHT;
+ self.light_lev = 220 + 36 * sin(time);
+ self.pflags = PFLAGS_FULLDYNAMIC;
+
+ if(self.team && !self.buff_waypoint)
+ buff_Waypoint_Spawn(self);
+
+ if(self.lifetime)
+ if(time >= self.lifetime)
+ buff_Respawn(self);
+ }
+
+ self.nextthink = time;
+ //self.angles_y = time * 110.1;
+}
+
+void buff_Waypoint_Reset()
+{
+ WaypointSprite_Kill(self.buff_waypoint);
+
+ if(self.buff_activetime) { buff_Waypoint_Spawn(self); }
+}
+
+void buff_Reset()
+{
+ if(autocvar_g_buffs_randomize)
+ buff_NewType(self, self.buffs);
+ self.owner = world;
+ buff_SetCooldown(autocvar_g_buffs_cooldown_activate);
+ buff_Waypoint_Reset();
+ self.buff_activetime_updated = FALSE;
+
+ if(autocvar_g_buffs_random_location || (self.spawnflags & 1))
+ buff_Respawn(self);
+}
+
+void buff_Init(entity ent)
+{
+ if(!cvar("g_buffs")) { remove(self); return; }
+
+ if(!teamplay && self.team) { self.team = 0; }
+
+ entity oldself = self;
+ self = ent;
+ if(!self.buffs || buff_Available(self.buffs))
+ buff_NewType(self, 0);
+
+ self.classname = "item_buff";
+ self.solid = SOLID_TRIGGER;
+ self.flags = FL_ITEM;
+ self.think = buff_Think;
+ self.touch = buff_Touch;
+ self.reset = buff_Reset;
+ self.nextthink = time + 0.1;
+ self.gravity = 1;
+ self.movetype = MOVETYPE_TOSS;
+ self.scale = 1;
+ self.skin = Buff_Skin(self.buffs);
+ self.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+ //self.gravity = 100;
+ self.color = Buff_Color(self.buffs);
+ self.glowmod = ((self.team) ? Team_ColorRGB(self.team) + '0.1 0.1 0.1' : self.color);
+ buff_SetCooldown(autocvar_g_buffs_cooldown_activate + game_starttime);
+ self.buff_active = !self.buff_activetime;
+ self.pflags = PFLAGS_FULLDYNAMIC;
+
+ if(self.noalign)
+ self.movetype = MOVETYPE_NONE; // reset by random location
+
+ setmodel(self, "models/relics/relic.md3");
+ setsize(self, BUFF_MIN, BUFF_MAX);
+
+ if(cvar("g_buffs_random_location") || (self.spawnflags & 1))
+ buff_Respawn(self);
+
+ self = oldself;
+}
+
+void buff_Init_Compat(entity ent, float replacement)
+{
+ if(ent.spawnflags & 2)
+ ent.team = NUM_TEAM_1;
+ else if(ent.spawnflags & 4)
+ ent.team = NUM_TEAM_2;
+
+ ent.buffs = replacement;
+
+ buff_Init(ent);
+}
+
+void buff_SpawnReplacement(entity ent, entity old)
+{
+ setorigin(ent, old.origin);
+ ent.angles = old.angles;
+ ent.noalign = old.noalign;
+
+ buff_Init(ent);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_SplitHealthArmor)
+{
+ if(frag_deathtype == DEATH_BUFF_VENGEANCE) { return FALSE; } // oh no you don't
+
+ if(frag_target.buffs & BUFF_RESISTANCE)
+ {
+ vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
+ damage_take = v_x;
+ damage_save = v_y;
+ }
+
+ return FALSE;
+}
+
+void buff_Vengeance_DelayedDamage()
+{
+ if(self.enemy)
+ Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF_VENGEANCE, self.enemy.origin, '0 0 0');
+
+ remove(self);
+ return;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_Calculate)
+{
+ if(frag_deathtype == DEATH_BUFF_VENGEANCE) { return FALSE; } // oh no you don't
+
+ if(frag_target.buffs & BUFF_SPEED)
+ if(frag_target != frag_attacker)
+ frag_damage *= autocvar_g_buffs_speed_damage_take;
+
+ if(frag_target.buffs & BUFF_MEDIC)
+ if((frag_target.health - frag_damage) <= 0)
+ if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+ if(frag_attacker)
+ if(random() <= autocvar_g_buffs_medic_survive_chance)
+ if(frag_target.health - autocvar_g_buffs_medic_survive_health > 0) // not if the final result would be less than 0, medic must get health
+ frag_damage = frag_target.health - autocvar_g_buffs_medic_survive_health;
+
+ if(frag_target.buffs & BUFF_VENGEANCE)
+ if(frag_attacker)
+ if(frag_attacker != frag_target)
+ if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+ {
+ entity dmgent = spawn();
+
+ dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
+ dmgent.enemy = frag_attacker;
+ dmgent.owner = frag_target;
+ dmgent.think = buff_Vengeance_DelayedDamage;
+ dmgent.nextthink = time + 0.1;
+ }
+
+ if(frag_target.buffs & BUFF_BASH)
+ if(frag_attacker != frag_target)
+ if(vlen(frag_force))
+ frag_force = '0 0 0';
+
+ if(frag_attacker.buffs & BUFF_BASH)
+ if(vlen(frag_force))
+ if(frag_attacker == frag_target)
+ frag_force *= autocvar_g_buffs_bash_force_self;
+ else
+ frag_force *= autocvar_g_buffs_bash_force;
+
+ if(frag_attacker.buffs & BUFF_DISABILITY)
+ if(frag_target != frag_attacker)
+ frag_target.buff_disability_time = time + autocvar_g_buffs_disability_time;
+
+ if(frag_attacker.buffs & BUFF_MEDIC)
+ if(SAME_TEAM(frag_attacker, frag_target))
+ if(frag_attacker != frag_target)
+ {
+ frag_target.health = min(g_pickup_healthmega_max, frag_target.health + frag_damage);
+ frag_damage = 0;
+ }
+
+ // this... is ridiculous (TODO: fix!)
+ if(frag_attacker.buffs & BUFF_VAMPIRE)
+ if(!frag_target.vehicle)
+ if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+ if(frag_target.deadflag == DEAD_NO)
+ if(IS_PLAYER(frag_target) || (frag_target.flags & FL_MONSTER))
+ if(frag_attacker != frag_target)
+ if(!frag_target.frozen)
+ if(frag_target.takedamage)
+ if(DIFF_TEAM(frag_attacker, frag_target))
+ frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerSpawn)
+{
+ self.buffs = 0;
+ // reset timers here to prevent them continuing after re-spawn
+ self.buff_disability_time = 0;
+ self.buff_disability_effect_time = 0;
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerPhysics)
+{
+ if(self.buffs & BUFF_SPEED)
+ {
+ self.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
+ self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
+ }
+
+ if(time < self.buff_disability_time)
+ {
+ self.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
+ self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerJump)
+{
+ if(self.buffs & BUFF_JUMP)
+ player_jumpheight = autocvar_g_buffs_jump_height;
+ self.stat_jumpheight = player_jumpheight;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_MonsterMove)
+{
+ if(time < self.buff_disability_time)
+ {
+ monster_speed_walk *= autocvar_g_buffs_disability_speed;
+ monster_speed_run *= autocvar_g_buffs_disability_speed;
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerDies)
+{
+ if(self.buffs)
+ {
+ Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, self.buffs);
+ self.buffs = 0;
+
+ if(self.buff_model)
+ {
+ remove(self.buff_model);
+ self.buff_model = world;
+ }
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerUseKey)
+{
+ if(MUTATOR_RETURNVALUE || gameover) { return FALSE; }
+ if(self.buffs)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, self.buffs);
+ Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, self.buffs);
+
+ self.buffs = 0;
+ sound(self, CH_TRIGGER, "relics/relic_effect.wav", VOL_BASE, ATTN_NORM);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_RemovePlayer)
+{
+ if(self.buff_model)
+ {
+ remove(self.buff_model);
+ self.buff_model = world;
+ }
+
+ // also reset timers here to prevent them continuing after spectating
+ self.buff_disability_time = 0;
+ self.buff_disability_effect_time = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_CustomizeWaypoint)
+{
+ entity e = WaypointSprite_getviewentity(other);
+
+ // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+ // but only apply this to real players, not to spectators
+ if((self.owner.flags & FL_CLIENT) && (self.owner.buffs & BUFF_INVISIBLE) && (e == other))
+ if(DIFF_TEAM(self.owner, e))
+ return TRUE;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_OnEntityPreSpawn)
+{
+ if(autocvar_g_buffs_replace_powerups)
+ switch(self.classname)
+ {
+ case "item_strength":
+ case "item_invincible":
+ {
+ entity e = spawn();
+ buff_SpawnReplacement(e, self);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_WeaponRate)
+{
+ if(self.buffs & BUFF_SPEED)
+ weapon_rate *= autocvar_g_buffs_speed_rate;
+
+ if(time < self.buff_disability_time)
+ weapon_rate *= autocvar_g_buffs_disability_rate;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerThink)
+{
+ if(gameover || self.deadflag != DEAD_NO) { return FALSE; }
+
+ if(time < self.buff_disability_time)
+ if(time >= self.buff_disability_effect_time)
+ {
+ pointparticles(particleeffectnum("smoking"), self.origin + ((self.mins + self.maxs) * 0.5), '0 0 0', 1);
+ self.buff_disability_effect_time = time + 0.5;
+ }
+
+ if(self.frozen)
+ {
+ if(self.buffs)
+ {
+ Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, self.buffs);
+ self.buffs = 0;
+ }
+ }
+
+ if((self.buffs & BUFF_INVISIBLE) && (self.oldbuffs & BUFF_INVISIBLE))
+ if(self.alpha != autocvar_g_buffs_invisible_alpha)
+ self.alpha = autocvar_g_buffs_invisible_alpha;
+
+ if(self.buffs != self.oldbuffs)
+ {
+ if(self.oldbuffs & BUFF_AMMO)
+ {
+ if(self.buff_ammo_prev_infitems)
+ self.items |= IT_UNLIMITED_WEAPON_AMMO;
+ else
+ self.items &= ~IT_UNLIMITED_WEAPON_AMMO;
+ }
+ else if(self.buffs & BUFF_AMMO)
+ {
+ self.buff_ammo_prev_infitems = (self.items & IT_UNLIMITED_WEAPON_AMMO);
+ self.items |= IT_UNLIMITED_WEAPON_AMMO;
+ if(!self.ammo_shells) { self.ammo_shells = 20; }
+ if(!self.ammo_cells) { self.ammo_cells = 20; }
+ if(!self.ammo_rockets) { self.ammo_rockets = 20; }
+ if(!self.ammo_nails) { self.ammo_nails = 20; }
+ if(!self.ammo_fuel) { self.ammo_fuel = 20; }
+ }
+
+ if(self.oldbuffs & BUFF_INVISIBLE)
+ {
+ if(time < self.strength_finished && g_minstagib)
+ self.alpha = autocvar_g_minstagib_invis_alpha;
+ else
+ self.alpha = self.buff_invisible_prev_alpha;
+ }
+ else if(self.buffs & BUFF_INVISIBLE)
+ {
+ if(time < self.strength_finished && g_minstagib)
+ self.buff_invisible_prev_alpha = default_player_alpha;
+ else
+ self.buff_invisible_prev_alpha = self.alpha;
+ self.alpha = autocvar_g_buffs_invisible_alpha;
+ }
+
+ if(self.oldbuffs & BUFF_FLIGHT)
+ self.gravity = self.buff_flight_prev_gravity;
+ else if(self.buffs & BUFF_FLIGHT)
+ {
+ self.buff_flight_prev_gravity = self.gravity;
+ self.gravity = autocvar_g_buffs_flight_gravity;
+ }
+
+ self.oldbuffs = self.buffs;
+ if(self.buffs)
+ {
+ if(!self.buff_model)
+ {
+ self.buff_model = spawn();
+ setmodel(self.buff_model, "models/relics/relic.md3");
+ setsize(self.buff_model, '0 0 -40', '0 0 40');
+ setattachment(self.buff_model, self, "");
+ setorigin(self.buff_model, '0 0 1' * (self.buff_model.maxs_z * 1));
+ self.buff_model.owner = self;
+ self.buff_model.scale = 0.7;
+ self.buff_model.pflags = PFLAGS_FULLDYNAMIC;
+ self.buff_model.light_lev = 200;
+ self.buff_model.customizeentityforclient = buffs_BuffModel_Customize;
+ }
+ self.buff_model.color = Buff_Color(self.buffs);
+ self.buff_model.glowmod = ((self.buff_model.team) ? Team_ColorRGB(self.buff_model.team) + '0.1 0.1 0.1' : self.buff_model.color);
+ self.buff_model.skin = Buff_Skin(self.buffs);
+
+ self.effects |= EF_NOSHADOW;
+ }
+ else
+ {
+ remove(self.buff_model);
+ self.buff_model = world;
+
+ self.effects &= ~(EF_NOSHADOW);
+ }
+ }
+
+ if(self.buff_model)
+ {
+ self.buff_model.effects = self.effects;
+ self.buff_model.effects |= EF_LOWPRECISION;
+ self.buff_model.effects = self.buff_model.effects & EFMASK_CHEAP; // eat performance
+
+ self.buff_model.alpha = self.alpha;
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_SpectateCopy)
+{
+ self.buffs = other.buffs;
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_VehicleEnter)
+{
+ vh_vehicle.buffs = vh_player.buffs;
+ vh_player.buffs = 0;
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_VehicleExit)
+{
+ vh_player.buffs = vh_vehicle.buffs;
+ vh_vehicle.buffs = 0;
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_PlayerRegen)
+{
+ if(self.buffs & BUFF_MEDIC)
+ {
+ regen_mod_rot = autocvar_g_buffs_medic_rot;
+ regen_mod_limit = regen_mod_max = autocvar_g_buffs_medic_max;
+ regen_mod_regen = autocvar_g_buffs_medic_regen;
+ }
+
+ if(self.buffs & BUFF_SPEED)
+ regen_mod_regen = autocvar_g_buffs_speed_regen;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace");
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":Buffs");
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(buffs_BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", Buffs");
+ return FALSE;
+}
+
+void buffs_DelayedInit()
+{
+ if(autocvar_g_buffs_spawn_count > 0)
+ if(find(world, classname, "item_buff") == world)
+ {
+ float i;
+ for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
+ {
+ entity e = spawn();
+ e.spawnflags |= 1; // always randomize
+ e.velocity = randomvec() * 250; // this gets reset anyway if random location works
+ buff_Init(e);
+ }
+ }
+}
+
+void buffs_Initialize()
+{
+ precache_model("models/relics/relic.md3");
+ precache_sound("misc/strength_respawn.wav");
+ precache_sound("misc/shield_respawn.wav");
+ precache_sound("relics/relic_effect.wav");
+ precache_sound("weapons/rocket_impact.wav");
+ precache_sound("keepaway/respawn.wav");
+
+ addstat(STAT_BUFFS, AS_INT, buffs);
+ addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_jumpheight);
+
+ InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
+}
+
+MUTATOR_DEFINITION(mutator_buffs)
+{
+ MUTATOR_HOOK(PlayerDamage_SplitHealthArmor, buffs_PlayerDamage_SplitHealthArmor, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDamage_Calculate, buffs_PlayerDamage_Calculate, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, buffs_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPhysics, buffs_PlayerPhysics, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerJump, buffs_PlayerJump, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MonsterMove, buffs_MonsterMove, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SpectateCopy, buffs_SpectateCopy, CBC_ORDER_ANY);
+ MUTATOR_HOOK(VehicleEnter, buffs_VehicleEnter, CBC_ORDER_ANY);
+ MUTATOR_HOOK(VehicleExit, buffs_VehicleExit, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerRegen, buffs_PlayerRegen, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, buffs_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerUseKey, buffs_PlayerUseKey, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, buffs_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientDisconnect, buffs_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(OnEntityPreSpawn, buffs_OnEntityPreSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(CustomizeWaypoint, buffs_CustomizeWaypoint, CBC_ORDER_ANY);
+ MUTATOR_HOOK(WeaponRateFactor, buffs_WeaponRate, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, buffs_PlayerThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetCvars, buffs_GetCvars, CBC_ORDER_ANY);
+ MUTATOR_HOOK(BuildMutatorsString, buffs_BuildMutatorsString, CBC_ORDER_ANY);
+ MUTATOR_HOOK(BuildMutatorsPrettyString, buffs_BuildMutatorsPrettyString, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ buffs_Initialize();
+ }
+
+ return FALSE;
+}
--- /dev/null
+// buff specific variables \\
+//
+// ammo
+.float buff_ammo_prev_infitems;
+// invisible
+.float buff_invisible_prev_alpha;
+// flight
+.float buff_flight_prev_gravity;
+// jump
+.float stat_jumpheight;
+const float STAT_MOVEVARS_JUMPVELOCITY = 250; // engine hack
+// disability
+.float buff_disability_time;
+.float buff_disability_effect_time;
+
+// buff definitions
+.float buff_active;
+.float buff_activetime;
+.float buff_activetime_updated;
+.entity buff_waypoint;
+.float oldbuffs; // for updating effects
+.entity buff_model; // controls effects (TODO: make csqc)
+
+#define BUFF_MIN ('-16 -16 -20')
+#define BUFF_MAX ('16 16 20')
+
+// client side options
+.float cvar_cl_buffs_autoreplace;
{
if(IS_PLAYER(self))
if(self.deadflag == DEAD_NO)
+ if(!self.frozen)
if(autocvar_g_campcheck_interval)
{
vector dist;
float clean_up_and_do_nothing;
float horiz_speed = autocvar_sv_dodging_horiz_speed;
- if(self.freezetag_frozen)
+ if(self.frozen)
horiz_speed = autocvar_sv_dodging_horiz_speed_frozen;
if (self.deadflag != DEAD_NO)
tap_direction_x = 0;
tap_direction_y = 0;
- float frozen_dodging;
- frozen_dodging = (self.freezetag_frozen && autocvar_sv_dodging_frozen);
+ 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)
if (self.movement_x > 0) {
// is this a state change?
- if (!(self.pressedkeys & KEY_FORWARD) || frozen_dodging) {
+ 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;
if (self.movement_x < 0) {
// is this a state change?
- if (!(self.pressedkeys & KEY_BACKWARD) || frozen_dodging) {
+ 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;
if (self.movement_y > 0) {
// is this a state change?
- if (!(self.pressedkeys & KEY_RIGHT) || frozen_dodging) {
+ 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;
if (self.movement_y < 0) {
// is this a state change?
- if (!(self.pressedkeys & KEY_LEFT) || frozen_dodging) {
+ 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;
MUTATOR_HOOKFUNCTION(minstagib_ForbidThrowing)
{
// weapon dropping on death handled by FilterItem
- nades_CheckThrow();
return TRUE;
}
+.entity nade_spawnloc;
+
void nade_timer_think()
{
self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
self.nextthink = time;
if(!self.owner || wasfreed(self.owner))
remove(self);
-
}
void nade_burn_spawn(entity _nade)
{
- float p;
-
- switch(_nade.realowner.team)
- {
- case NUM_TEAM_1: p = PROJECTILE_NADE_RED_BURN; break;
- case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE_BURN; break;
- case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW_BURN; break;
- case NUM_TEAM_4: p = PROJECTILE_NADE_PINK_BURN; break;
- default: p = PROJECTILE_NADE_BURN; break;
- }
-
- CSQCProjectile(_nade, TRUE, p, TRUE);
+ CSQCProjectile(_nade, TRUE, Nade_ProjectileFromID(_nade.nade_type, TRUE), TRUE);
}
void nade_spawn(entity _nade)
{
- float p;
entity timer = spawn();
setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3");
setattachment(timer, _nade, "");
timer.owner = _nade;
timer.skin = 10;
- switch(_nade.realowner.team)
+ _nade.effects |= EF_LOWPRECISION;
+
+ CSQCProjectile(_nade, TRUE, Nade_ProjectileFromID(_nade.nade_type, FALSE), TRUE);
+}
+
+void napalm_damage(float dist, float damage, float edgedamage, float burntime)
+{
+ entity e;
+ float d;
+ vector p;
+
+ if ( damage < 0 )
+ return;
+
+ RandomSelection_Init();
+ for(e = WarpZone_FindRadius(self.origin, dist, TRUE); e; e = e.chain)
+ if(e.takedamage == DAMAGE_AIM)
+ if(self.realowner != e || autocvar_g_nades_napalm_selfdamage)
+ if(!IS_PLAYER(e) || !self.realowner || DIFF_TEAM(e, self))
+ if(!e.frozen)
+ {
+ p = e.origin;
+ p_x += e.mins_x + random() * (e.maxs_x - e.mins_x);
+ p_y += e.mins_y + random() * (e.maxs_y - e.mins_y);
+ p_z += e.mins_z + random() * (e.maxs_z - e.mins_z);
+ d = vlen(WarpZone_UnTransformOrigin(e, self.origin) - p);
+ if(d < dist)
+ {
+ e.fireball_impactvec = p;
+ RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e));
+ }
+ }
+ if(RandomSelection_chosen_ent)
{
- case NUM_TEAM_1: p = PROJECTILE_NADE_RED; break;
- case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE; break;
- case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW; break;
- case NUM_TEAM_4: p = PROJECTILE_NADE_PINK; break;
- default: p = PROJECTILE_NADE; break;
+ d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, self.origin) - RandomSelection_chosen_ent.fireball_impactvec);
+ d = damage + (edgedamage - damage) * (d / dist);
+ Fire_AddDamage(RandomSelection_chosen_ent, self.realowner, d * burntime, burntime, self.projectiledeathtype | HITTYPE_BOUNCE);
+ //trailparticles(self, particleeffectnum("fireball_laser"), self.origin, RandomSelection_chosen_ent.fireball_impactvec);
+ pointparticles(particleeffectnum("fireball_laser"), self.origin, RandomSelection_chosen_ent.fireball_impactvec - self.origin, 1);
}
+}
- CSQCProjectile(_nade, TRUE, p, TRUE);
+void napalm_ball_think()
+{
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ {
+ remove(self);
+ return;
+ }
+
+ if(time > self.pushltime)
+ {
+ remove(self);
+ return;
+ }
+
+ 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; }
+ }
+
+ self.angles = vectoangles(self.velocity);
+
+ napalm_damage(autocvar_g_nades_napalm_ball_radius,autocvar_g_nades_napalm_ball_damage,
+ autocvar_g_nades_napalm_ball_damage,autocvar_g_nades_napalm_burntime);
+
+ self.nextthink = time + 0.1;
+}
+
+
+void nade_napalm_ball()
+{
+ entity proj;
+ vector kick;
+
+ spamsound(self, CH_SHOTS, "weapons/fireball_fire.wav", VOL_BASE, ATTEN_NORM);
+
+ proj = spawn ();
+ proj.owner = self.owner;
+ proj.realowner = self.realowner;
+ proj.team = self.owner.team;
+ proj.classname = "grenade";
+ proj.bot_dodge = TRUE;
+ proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage;
+ proj.movetype = MOVETYPE_BOUNCE;
+ proj.projectiledeathtype = DEATH_NADE_NAPALM;
+ PROJECTILE_MAKETRIGGER(proj);
+ setmodel(proj, "null");
+ proj.scale = 1;//0.5;
+ setsize(proj, '-4 -4 -4', '4 4 4');
+ setorigin(proj, self.origin);
+ proj.think = napalm_ball_think;
+ proj.nextthink = time;
+ proj.damageforcescale = autocvar_g_nades_napalm_ball_damageforcescale;
+ proj.effects = EF_LOWPRECISION | EF_FLAME;
+
+ kick_x =(random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
+ kick_y = (random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
+ kick_z = (random()/2+0.5) * autocvar_g_nades_napalm_ball_spread;
+ proj.velocity = kick;
+
+ proj.pushltime = time + autocvar_g_nades_napalm_ball_lifetime;
+
+ proj.angles = vectoangles(proj.velocity);
+ proj.flags = FL_PROJECTILE;
+ proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
+
+ //CSQCProjectile(proj, TRUE, PROJECTILE_NAPALM_FIRE, TRUE);
+}
+
+
+void napalm_fountain_think()
+{
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ {
+ remove(self);
+ return;
+ }
+
+ if(time >= self.ltime)
+ {
+ remove(self);
+ return;
+ }
+
+ 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; }
+
+ UpdateCSQCProjectile(self);
+ }
+
+ napalm_damage(autocvar_g_nades_napalm_fountain_radius, autocvar_g_nades_napalm_fountain_damage,
+ autocvar_g_nades_napalm_fountain_edgedamage, autocvar_g_nades_napalm_burntime);
+
+ self.nextthink = time + 0.1;
+ if(time >= self.nade_special_time)
+ {
+ self.nade_special_time = time + autocvar_g_nades_napalm_fountain_delay;
+ nade_napalm_ball();
+ }
+}
+
+void nade_napalm_boom()
+{
+ entity fountain;
+ local float c;
+ for (c = 0; c < autocvar_g_nades_napalm_ball_count; c ++)
+ nade_napalm_ball();
+
+
+ fountain = spawn();
+ fountain.owner = self.owner;
+ fountain.realowner = self.realowner;
+ fountain.origin = self.origin;
+ setorigin(fountain, fountain.origin);
+ fountain.think = napalm_fountain_think;
+ fountain.nextthink = time;
+ fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime;
+ fountain.pushltime = fountain.ltime;
+ fountain.team = self.team;
+ fountain.movetype = MOVETYPE_TOSS;
+ fountain.projectiledeathtype = DEATH_NADE_NAPALM;
+ fountain.bot_dodge = TRUE;
+ fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage;
+ fountain.nade_special_time = time;
+ setsize(fountain, '-16 -16 -16', '16 16 16');
+ CSQCProjectile(fountain, TRUE, PROJECTILE_NAPALM_FOUNTAIN, TRUE);
+}
+
+void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time)
+{
+ frost_target.frozen_by = freezefield.realowner;
+ pointparticles(particleeffectnum("electro_impact"), frost_target.origin, '0 0 0', 1);
+ Freeze(frost_target, 1/freeze_time, 3, FALSE);
+ if(frost_target.ballcarried)
+ if(g_keepaway) { ka_DropEvent(frost_target); }
+ else { DropBall(frost_target.ballcarried, frost_target.origin, frost_target.velocity);}
+ if(frost_target.flagcarried) { ctf_Handle_Throw(frost_target, world, DROP_THROW); }
+ if(frost_target.nade) { toss_nade(frost_target, '0 0 0', time + 0.05); }
+
+ kh_Key_DropAll(frost_target, FALSE);
+}
+
+void nade_ice_think()
+{
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ {
+ remove(self);
+ return;
+ }
+
+ if(time >= self.ltime)
+ {
+ if ( autocvar_g_nades_ice_explode )
+ {
+ string expef;
+ switch(self.realowner.team)
+ {
+ case NUM_TEAM_1: expef = "nade_red_explode"; break;
+ case NUM_TEAM_2: expef = "nade_blue_explode"; break;
+ case NUM_TEAM_3: expef = "nade_yellow_explode"; break;
+ case NUM_TEAM_4: expef = "nade_pink_explode"; break;
+ default: expef = "nade_neutral_explode"; break;
+ }
+ pointparticles(particleeffectnum(expef), self.origin + '0 0 1', '0 0 0', 1);
+ sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
+
+ RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+ autocvar_g_nades_nade_radius, self, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
+ Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+ autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+ }
+ remove(self);
+ return;
+ }
+
+
+ self.nextthink = time+0.1;
+
+ // gaussian
+ float randomr;
+ randomr = random();
+ randomr = exp(-5*randomr*randomr)*autocvar_g_nades_nade_radius;
+ float randomw;
+ randomw = random()*M_PI*2;
+ vector randomp;
+ randomp_x = randomr*cos(randomw);
+ randomp_y = randomr*sin(randomw);
+ randomp_z = 1;
+ pointparticles(particleeffectnum("electro_muzzleflash"), self.origin + randomp, '0 0 0', 1);
+
+ if(time >= self.nade_special_time)
+ {
+ self.nade_special_time = time+0.7;
+
+
+ pointparticles(particleeffectnum("electro_impact"), self.origin, '0 0 0', 1);
+ pointparticles(particleeffectnum("icefield"), self.origin, '0 0 0', 1);
+ }
+
+
+ float current_freeze_time = self.ltime - time - 0.1;
+
+ entity e;
+ for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
+ if(e != self)
+ if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner))
+ if(e.takedamage && e.deadflag == DEAD_NO)
+ if(e.health > 0)
+ if(!e.revival_time || ((time - e.revival_time) >= 1.5))
+ if(!e.frozen)
+ if(current_freeze_time > 0)
+ nade_ice_freeze(self, e, current_freeze_time);
+}
+
+void nade_ice_boom()
+{
+ entity fountain;
+ fountain = spawn();
+ fountain.owner = self.owner;
+ fountain.realowner = self.realowner;
+ fountain.origin = self.origin;
+ setorigin(fountain, fountain.origin);
+ fountain.think = nade_ice_think;
+ fountain.nextthink = time;
+ fountain.ltime = time + autocvar_g_nades_ice_freeze_time;
+ fountain.pushltime = fountain.wait = fountain.ltime;
+ fountain.team = self.team;
+ fountain.movetype = MOVETYPE_TOSS;
+ fountain.projectiledeathtype = DEATH_NADE_ICE;
+ fountain.bot_dodge = FALSE;
+ setsize(fountain, '-16 -16 -16', '16 16 16');
+ fountain.nade_special_time = time+0.3;
+ fountain.angles = self.angles;
+
+ if ( autocvar_g_nades_ice_explode )
+ {
+ setmodel(fountain, "models/grenademodel.md3");
+ entity timer = spawn();
+ setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3");
+ setattachment(timer, fountain, "");
+ timer.classname = "nade_timer";
+ timer.colormap = self.colormap;
+ timer.glowmod = self.glowmod;
+ timer.think = nade_timer_think;
+ timer.nextthink = time;
+ timer.wait = fountain.ltime;
+ timer.owner = fountain;
+ timer.skin = 10;
+ }
+ else
+ setmodel(fountain, "null");
+}
+
+void nade_translocate_boom()
+{
+ if(self.realowner.vehicle)
+ return;
+
+ vector locout = self.origin + '0 0 1' * (1 - self.realowner.mins_z - 24);
+ tracebox(locout, self.realowner.mins, self.realowner.maxs, locout, MOVE_NOMONSTERS, self.realowner);
+ locout = trace_endpos;
+
+ makevectors(self.realowner.angles);
+
+ entity oldself = self;
+ self = self.realowner;
+ MUTATOR_CALLHOOK(PortalTeleport);
+ self.realowner = self;
+ self = oldself;
+
+ TeleportPlayer(self, self.realowner, locout, self.realowner.mangle, v_forward * vlen(self.realowner.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+}
+
+void nade_spawn_boom()
+{
+ entity spawnloc = spawn();
+ setorigin(spawnloc, self.origin);
+ setsize(spawnloc, self.realowner.mins, self.realowner.maxs);
+ spawnloc.movetype = MOVETYPE_NONE;
+ spawnloc.solid = SOLID_NOT;
+ spawnloc.drawonlytoclient = self.realowner;
+ spawnloc.effects = EF_STARDUST;
+ spawnloc.cnt = autocvar_g_nades_spawn_count;
+
+ if(self.realowner.nade_spawnloc)
+ {
+ remove(self.realowner.nade_spawnloc);
+ self.realowner.nade_spawnloc = world;
+ }
+
+ self.realowner.nade_spawnloc = spawnloc;
+}
+
+void nade_heal_think()
+{
+ if(time >= self.ltime)
+ {
+ remove(self);
+ return;
+ }
+
+ self.nextthink = time;
+
+ if(time >= self.nade_special_time)
+ {
+ self.nade_special_time = time+0.25;
+ self.nade_show_particles = 1;
+ }
+ else
+ self.nade_show_particles = 0;
+}
+
+void nade_heal_touch()
+{
+ float maxhealth;
+ float health_factor;
+ if(IS_PLAYER(other) || (other.flags & FL_MONSTER))
+ if(other.deadflag == DEAD_NO)
+ if(!other.frozen)
+ {
+ health_factor = autocvar_g_nades_heal_rate*frametime/2;
+ if ( other != self.realowner )
+ {
+ if ( SAME_TEAM(other,self) )
+ health_factor *= autocvar_g_nades_heal_friend;
+ else
+ health_factor *= autocvar_g_nades_heal_foe;
+ }
+ if ( health_factor > 0 )
+ {
+ maxhealth = (other.flags & FL_MONSTER) ? other.max_health : g_pickup_healthmega_max;
+ if ( other.health < maxhealth )
+ {
+ if ( self.nade_show_particles )
+ pointparticles(particleeffectnum("healing_fx"), other.origin, '0 0 0', 1);
+ other.health = min(other.health+health_factor, maxhealth);
+ }
+ other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+ }
+ else if ( health_factor < 0 )
+ {
+ Damage(other,self,self.realowner,-health_factor,DEATH_NADE_HEAL,other.origin,'0 0 0');
+ }
+
+ }
+
+ if ( IS_REAL_CLIENT(other) || (other.vehicle_flags & VHF_ISVEHICLE) )
+ {
+ entity show_red = (other.vehicle_flags & VHF_ISVEHICLE) ? other.owner : other;
+ show_red.stat_healing_orb = time+0.1;
+ show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.healer_lifetime;
+ }
+}
+
+void nade_heal_boom()
+{
+ entity healer;
+ healer = spawn();
+ healer.owner = self.owner;
+ healer.realowner = self.realowner;
+ setorigin(healer, self.origin);
+ healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
+ healer.ltime = time + healer.healer_lifetime;
+ healer.team = self.realowner.team;
+ healer.bot_dodge = FALSE;
+ healer.solid = SOLID_TRIGGER;
+ healer.touch = nade_heal_touch;
+
+ setmodel(healer, "models/ctf/shield.md3");
+ healer.healer_radius = autocvar_g_nades_nade_radius;
+ vector size = '1 1 1' * healer.healer_radius / 2;
+ setsize(healer,-size,size);
+
+ Net_LinkEntity(healer, TRUE, 0, healer_send);
+
+ healer.think = nade_heal_think;
+ healer.nextthink = time;
+ healer.SendFlags |= 1;
+}
+
+void nade_monster_boom()
+{
+ entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, FALSE, FALSE, 1);
+
+ if(autocvar_g_nades_pokenade_monster_lifetime > 0)
+ e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
+ e.monster_skill = MONSTER_SKILL_INSANE;
}
void nade_boom()
{
string expef;
+ float nade_blast = 1;
- switch(self.realowner.team)
+ switch ( self.nade_type )
{
- case NUM_TEAM_1: expef = "nade_red_explode"; break;
- case NUM_TEAM_2: expef = "nade_blue_explode"; break;
- case NUM_TEAM_3: expef = "nade_yellow_explode"; break;
- case NUM_TEAM_4: expef = "nade_pink_explode"; break;
- default: expef = "nade_explode"; break;
+ case NADE_TYPE_NAPALM:
+ nade_blast = autocvar_g_nades_napalm_blast;
+ expef = "explosion_medium";
+ break;
+ case NADE_TYPE_ICE:
+ nade_blast = 0;
+ expef = "electro_combo"; // hookbomb_explode electro_combo bigplasma_impact
+ break;
+ case NADE_TYPE_TRANSLOCATE:
+ nade_blast = 0;
+ expef = "";
+ break;
+ case NADE_TYPE_MONSTER:
+ case NADE_TYPE_SPAWN:
+ nade_blast = 0;
+ switch(self.realowner.team)
+ {
+ case NUM_TEAM_1: expef = "spawn_event_red"; break;
+ case NUM_TEAM_2: expef = "spawn_event_blue"; break;
+ case NUM_TEAM_3: expef = "spawn_event_yellow"; break;
+ case NUM_TEAM_4: expef = "spawn_event_pink"; break;
+ default: expef = "spawn_event_neutral"; break;
+ }
+ break;
+ case NADE_TYPE_HEAL:
+ nade_blast = 0;
+ expef = "spawn_event_red";
+ break;
+
+ default:
+ case NADE_TYPE_NORMAL:
+ switch(self.realowner.team)
+ {
+ case NUM_TEAM_1: expef = "nade_red_explode"; break;
+ case NUM_TEAM_2: expef = "nade_blue_explode"; break;
+ case NUM_TEAM_3: expef = "nade_yellow_explode"; break;
+ case NUM_TEAM_4: expef = "nade_pink_explode"; break;
+ default: expef = "nade_neutral_explode"; break;
+ }
}
- sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM);
- sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
pointparticles(particleeffectnum(expef), self.origin + '0 0 1', '0 0 0', 1);
- Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+ sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM);
+ sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
self.takedamage = DAMAGE_NO;
- RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+
+ if(nade_blast)
+ {
+ RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
autocvar_g_nades_nade_radius, self, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
+ Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+ }
+
+ switch ( self.nade_type )
+ {
+ case NADE_TYPE_NAPALM: nade_napalm_boom(); break;
+ case NADE_TYPE_ICE: nade_ice_boom(); break;
+ case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break;
+ case NADE_TYPE_SPAWN: nade_spawn_boom(); break;
+ case NADE_TYPE_HEAL: nade_heal_boom(); break;
+ case NADE_TYPE_MONSTER: nade_monster_boom(); break;
+ }
remove(self);
}
void nade_touch()
{
+ if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
PROJECTILE_TOUCH;
//setsize(self, '-2 -2 -2', '2 2 2');
//UpdateCSQCProjectile(self);
void nade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
+ if(self.nade_type == NADE_TYPE_TRANSLOCATE || self.nade_type == NADE_TYPE_SPAWN)
+ return;
+
if(DEATH_ISWEAPON(deathtype, WEP_LASER))
return;
if(DEATH_ISWEAPON(deathtype, WEP_UZI))
damage = self.max_health * 0.1;
- if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && !(deathtype & HITTYPE_SECONDARY))
- damage = self.max_health * 1.1;
-
- if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && (deathtype & HITTYPE_SECONDARY))
+ if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN))
+ if(deathtype & HITTYPE_SECONDARY)
{
damage = self.max_health * 0.1;
- force *= 15;
+ force *= 10;
}
+ else
+ damage = self.max_health * 1.1;
self.velocity += force;
self.think = nade_beep;
}
- self.health -= damage;
- self.realowner = attacker;
+ self.health -= damage;
+
+ if ( self.nade_type != NADE_TYPE_HEAL || IS_PLAYER(attacker) )
+ self.realowner = attacker;
if(self.health <= 0)
W_PrepareExplosionByDamage(attacker, nade_boom);
void toss_nade(entity e, vector _velocity, float _time)
{
+ if(e.nade == world)
+ return;
+
entity _nade = e.nade;
e.nade = world;
Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
- //setorigin(_nade, CENTER_OR_VIEWOFS(e) + (v_right * 10) * -1);
setorigin(_nade, w_shotorg + (v_right * 25) * -1);
- setmodel(_nade, "models/weapons/v_ok_grenade.md3");
- setattachment(_nade, world, "");
+ //setmodel(_nade, "models/weapons/v_ok_grenade.md3");
+ //setattachment(_nade, world, "");
PROJECTILE_MAKETRIGGER(_nade);
setsize(_nade, '-16 -16 -16', '16 16 16');
_nade.movetype = MOVETYPE_BOUNCE;
_nade.velocity = _velocity;
else
_nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, TRUE);
-
+
_nade.touch = nade_touch;
_nade.health = autocvar_g_nades_nade_health;
_nade.max_health = _nade.health;
_nade.takedamage = DAMAGE_AIM;
_nade.event_damage = nade_damage;
+ _nade.customizeentityforclient = func_null;
+ _nade.exteriormodeltoclient = world;
+ _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ _nade.traileffectnum = 0;
_nade.teleportable = TRUE;
_nade.pushable = TRUE;
_nade.gravity = 1;
_nade.damagedbycontents = TRUE;
_nade.angles = vectoangles(_nade.velocity);
_nade.flags = FL_PROJECTILE;
+ _nade.projectiledeathtype = DEATH_NADE;
+ _nade.toss_time = time;
+ _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
nade_spawn(_nade);
}
e.nade_refire = time + autocvar_g_nades_nade_refire;
+ e.nade_timer = 0;
+}
+
+void nades_GiveBonus(entity player, float score)
+{
+ if (autocvar_g_nades)
+ if (autocvar_g_nades_bonus)
+ if (IS_REAL_CLIENT(player))
+ if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
+ if (player.frozen == 0)
+ if (player.deadflag == DEAD_NO)
+ {
+ if ( player.bonus_nade_score < 1 )
+ player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
+
+ if ( player.bonus_nade_score >= 1 )
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
+ play2(player,"kh/alarm.wav");
+ player.bonus_nades++;
+ player.bonus_nade_score -= 1;
+ }
+ }
+}
+
+void nades_RemoveBonus(entity player)
+{
+ player.bonus_nades = player.bonus_nade_score = 0;
+}
+
+float nade_customize()
+{
+ //if(IS_SPEC(other)) { return FALSE; }
+ if(other == self.realowner || (IS_SPEC(other) && other.enemy == self.realowner))
+ {
+ // somewhat hide the model, but keep the glow
+ //self.effects = 0;
+ if(self.traileffectnum)
+ self.traileffectnum = 0;
+ self.alpha = -1;
+ }
+ else
+ {
+ //self.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+ if(!self.traileffectnum)
+ self.traileffectnum = particleeffectnum(Nade_TrailEffect(Nade_ProjectileFromID(self.nade_type, FALSE), self.team));
+ self.alpha = 1;
+ }
+
+ return TRUE;
}
void nade_prime()
if(self.fake_nade)
remove(self.fake_nade);
- self.nade = spawn();
- setmodel(self.nade, "null");
- setattachment(self.nade, self, "bip01 l hand");
- self.nade.classname = "nade";
- self.nade.realowner = self;
- self.nade.colormap = self.colormap;
- self.nade.glowmod = self.glowmod;
- self.nade.wait = time + autocvar_g_nades_nade_lifetime;
- self.nade.lifetime = time;
- self.nade.think = nade_beep;
- self.nade.nextthink = max(self.nade.wait - 3, time);
- self.nade.projectiledeathtype = DEATH_NADE;
-
- self.fake_nade = spawn();
- setmodel(self.fake_nade, "models/weapons/h_ok_grenade.iqm");
- setattachment(self.fake_nade, self.weaponentity, "");
- self.fake_nade.classname = "fake_nade";
- //self.fake_nade.viewmodelforclient = self;
- self.fake_nade.realowner = self.fake_nade.owner = self;
- self.fake_nade.colormap = self.colormap;
- self.fake_nade.glowmod = self.glowmod;
- self.fake_nade.think = SUB_Remove;
- self.fake_nade.nextthink = self.nade.wait;
+ entity n = spawn(), fn = spawn();
+
+ n.classname = "nade";
+ fn.classname = "fake_nade";
+
+ if(self.items & IT_STRENGTH && autocvar_g_nades_bonus_onstrength)
+ n.nade_type = self.nade_type;
+ else if (self.bonus_nades >= 1)
+ {
+ n.nade_type = self.nade_type;
+ n.pokenade_type = self.pokenade_type;
+ self.bonus_nades -= 1;
+ }
+ else
+ {
+ n.nade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_nade_type : autocvar_g_nades_nade_type);
+ n.pokenade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type);
+ }
+
+ n.nade_type = bound(1, n.nade_type, NADE_TYPE_LAST);
+
+ setmodel(n, "models/weapons/v_ok_grenade.md3");
+ //setattachment(n, self, "bip01 l hand");
+ n.exteriormodeltoclient = self;
+ n.customizeentityforclient = nade_customize;
+ n.traileffectnum = particleeffectnum(Nade_TrailEffect(Nade_ProjectileFromID(n.nade_type, FALSE), self.team));
+ n.colormod = Nade_Color(n.nade_type);
+ n.realowner = self;
+ n.colormap = self.colormap;
+ n.glowmod = self.glowmod;
+ n.wait = time + autocvar_g_nades_nade_lifetime;
+ n.lifetime = time;
+ n.think = nade_beep;
+ n.nextthink = max(n.wait - 3, time);
+ n.projectiledeathtype = DEATH_NADE;
+
+ setmodel(fn, "models/weapons/h_ok_grenade.iqm");
+ setattachment(fn, self.weaponentity, "");
+ fn.realowner = fn.owner = self;
+ fn.colormod = Nade_Color(n.nade_type);
+ fn.colormap = self.colormap;
+ fn.glowmod = self.glowmod;
+ fn.think = SUB_Remove;
+ fn.nextthink = n.wait;
+
+ self.nade = n;
+ self.fake_nade = fn;
}
float CanThrowNade()
}
}
+void nades_Clear(entity player)
+{
+ if(player.nade)
+ remove(player.nade);
+ if(player.fake_nade)
+ remove(player.fake_nade);
+
+ player.nade = player.fake_nade = world;
+ player.nade_timer = 0;
+}
+
+MUTATOR_HOOKFUNCTION(nades_CheckThrow)
+{
+ if(MUTATOR_RETURNVALUE) { nades_CheckThrow(); }
+ return FALSE;
+}
+
MUTATOR_HOOKFUNCTION(nades_VehicleEnter)
{
- if(other.nade)
- toss_nade(other, '0 0 100', max(other.nade.wait, time + 0.05));
+ if(vh_player.nade)
+ toss_nade(vh_player, '0 0 100', max(vh_player.nade.wait, time + 0.05));
return FALSE;
}
MUTATOR_HOOKFUNCTION(nades_PlayerPreThink)
{
- float key_pressed = ((g_grappling_hook || client_hasweapon(self, WEP_HOOK, FALSE, FALSE) || (weaponsInMap & WEPSET_HOOK)) ? self.button16 : self.BUTTON_HOOK);
+ if(!IS_PLAYER(self)) { return FALSE; }
+
+ float key_pressed = self.BUTTON_HOOK;
+ float time_score;
+ if(g_grappling_hook || client_hasweapon(self, WEP_HOOK, FALSE, FALSE) || (weaponsInMap & WEPSET_HOOK) || g_jetpack || self.items & IT_JETPACK)
+ key_pressed = self.button16; // if hook/jetpack is enabled, use an alternate key
+
if(self.nade)
- if(self.nade.wait - 0.1 <= time)
- toss_nade(self, '0 0 0', time + 0.05);
+ {
+ self.nade_timer = bound(0, (time - self.nade.lifetime) / autocvar_g_nades_nade_lifetime, 1);
+ //print(sprintf("%d %d\n", self.nade_timer, time - self.nade.lifetime));
+ makevectors(self.angles);
+ self.nade.velocity = self.velocity;
+
+ setorigin(self.nade, self.origin + self.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
+ self.nade.angles_y = self.angles_y;
+ }
+
+ if(self.nade)
+ if(self.nade.wait - 0.1 <= time)
+ toss_nade(self, '0 0 0', time + 0.05);
if(CanThrowNade())
if(self.nade_refire < time)
}
}
+ if(IS_PLAYER(self))
+ {
+ if ( autocvar_g_nades_bonus && autocvar_g_nades )
+ {
+ entity key;
+ float key_count = 0;
+ FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; }
+
+ if(self.flagcarried || self.ballcarried) // this player is important
+ time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
+ else
+ time_score = autocvar_g_nades_bonus_score_time;
+
+ if(key_count)
+ time_score = autocvar_g_nades_bonus_score_time_flagcarrier * key_count; // multiply by the number of keys the player is holding
+
+ if(autocvar_g_nades_bonus_client_select)
+ {
+ self.nade_type = self.cvar_cl_nade_type;
+ self.pokenade_type = self.cvar_cl_pokenade_type;
+ }
+ else
+ {
+ self.nade_type = autocvar_g_nades_bonus_type;
+ self.pokenade_type = autocvar_g_nades_pokenade_monster_type;
+ }
+
+ self.nade_type = bound(1, self.nade_type, NADE_TYPE_LAST);
+
+ if(self.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max)
+ nades_GiveBonus(self, time_score / autocvar_g_nades_bonus_score_max);
+ }
+ else
+ {
+ self.bonus_nades = self.bonus_nade_score = 0;
+ }
+ }
+
+ float n = 0;
+ entity o = world;
+ if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+ n = -1;
+ else
+ {
+ vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+ n = 0;
+ FOR_EACH_PLAYER(other) if(self != other)
+ {
+ if(other.deadflag == DEAD_NO)
+ if(other.frozen == 0)
+ if(SAME_TEAM(other, self))
+ if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+ {
+ if(!o)
+ o = other;
+ if(self.frozen == 1)
+ other.reviving = TRUE;
+ ++n;
+ }
+ }
+ }
+
+ if(n && self.frozen == 3) // OK, there is at least one teammate reviving us
+ {
+ self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+ self.health = max(1, self.revive_progress * start_health);
+
+ if(self.revive_progress >= 1)
+ {
+ Unfreeze(self);
+
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+ Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
+ }
+
+ FOR_EACH_PLAYER(other) if(other.reviving)
+ {
+ other.revive_progress = self.revive_progress;
+ other.reviving = FALSE;
+ }
+ }
+
return FALSE;
}
else
self.nade_refire = time + autocvar_g_nades_nade_refire;
+ if(autocvar_g_nades_bonus_client_select)
+ self.nade_type = self.cvar_cl_nade_type;
+
+ self.nade_timer = 0;
+
+ if(self.nade_spawnloc)
+ {
+ setorigin(self, self.nade_spawnloc.origin);
+ self.nade_spawnloc.cnt -= 1;
+
+ if(self.nade_spawnloc.cnt <= 0)
+ {
+ remove(self.nade_spawnloc);
+ self.nade_spawnloc = world;
+ }
+ }
+
return FALSE;
}
MUTATOR_HOOKFUNCTION(nades_PlayerDies)
{
- if(self.nade)
- toss_nade(self, '0 0 100', max(self.nade.wait, time + 0.05));
+ if(frag_target.nade)
+ if(!frag_target.frozen || !autocvar_g_freezetag_revive_nade)
+ toss_nade(frag_target, '0 0 100', max(frag_target.nade.wait, time + 0.05));
+
+ float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
+
+ if(IS_PLAYER(frag_attacker))
+ {
+ if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
+ nades_RemoveBonus(frag_attacker);
+ else if(frag_target.flagcarried)
+ nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium);
+ else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1)
+ {
+ #define SPREE_ITEM(counta,countb,center,normal,gentle) \
+ case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; }
+ switch(frag_attacker.killcount)
+ {
+ KILL_SPREE_LIST
+ default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break;
+ }
+ #undef SPREE_ITEM
+ }
+ else
+ nades_GiveBonus(frag_attacker, killcount_bonus);
+ }
+
+ nades_RemoveBonus(frag_target);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(nades_PlayerDamage)
+{
+ if(frag_target.frozen)
+ if(autocvar_g_freezetag_revive_nade)
+ if(frag_attacker == frag_target)
+ if(frag_deathtype == DEATH_NADE)
+ if(time - frag_inflictor.toss_time <= 0.1)
+ {
+ Unfreeze(frag_target);
+ frag_target.health = autocvar_g_freezetag_revive_nade_health;
+ pointparticles(particleeffectnum("iceorglass"), frag_target.origin, '0 0 0', 3);
+ frag_damage = 0;
+ frag_force = '0 0 0';
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_NADE, frag_target.netname);
+ Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(nades_MonsterDies)
+{
+ if(IS_PLAYER(frag_attacker))
+ if(DIFF_TEAM(frag_attacker, self))
+ if(!(self.spawnflags & MONSTERFLAG_SPAWNED))
+ nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor);
return FALSE;
}
MUTATOR_HOOKFUNCTION(nades_RemovePlayer)
{
- if(self.nade)
- remove(self.nade);
+ nades_Clear(self);
+ nades_RemoveBonus(self);
+ return FALSE;
+}
- if(self.fake_nade)
- remove(self.fake_nade);
+MUTATOR_HOOKFUNCTION(nades_SpectateCopy)
+{
+ self.nade_timer = other.nade_timer;
+ self.nade_type = other.nade_type;
+ self.pokenade_type = other.pokenade_type;
+ self.bonus_nades = other.bonus_nades;
+ self.bonus_nade_score = other.bonus_nade_score;
+ self.stat_healing_orb = other.stat_healing_orb;
+ self.stat_healing_orb_alpha = other.stat_healing_orb_alpha;
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(nades_GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_nade_type, "cl_nade_type");
+ GetCvars_handleString(get_cvars_s, get_cvars_f, cvar_cl_pokenade_type, "cl_pokenade_type");
return FALSE;
}
return FALSE;
}
+void nades_Initialize()
+{
+ addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
+ addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
+ addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
+ addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
+ addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
+ addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
+
+ precache_model("models/ok_nade_counter/ok_nade_counter.md3");
+ precache_model("models/weapons/h_ok_grenade.iqm");
+ precache_model("models/weapons/v_ok_grenade.md3");
+ precache_model("models/ctf/shield.md3");
+
+ precache_sound("weapons/rocket_impact.wav");
+ precache_sound("weapons/grenade_bounce1.wav");
+ precache_sound("weapons/grenade_bounce2.wav");
+ precache_sound("weapons/grenade_bounce3.wav");
+ precache_sound("weapons/grenade_bounce4.wav");
+ precache_sound("weapons/grenade_bounce5.wav");
+ precache_sound("weapons/grenade_bounce6.wav");
+ precache_sound("overkill/grenadebip.ogg");
+}
+
MUTATOR_DEFINITION(mutator_nades)
{
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, nades_CheckThrow, CBC_ORDER_LAST);
MUTATOR_HOOK(VehicleEnter, nades_VehicleEnter, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerPreThink, nades_PlayerPreThink, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerSpawn, nades_PlayerSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDies, nades_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, nades_PlayerDies, CBC_ORDER_LAST);
+ MUTATOR_HOOK(PlayerDamage_Calculate, nades_PlayerDamage, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MonsterDies, nades_MonsterDies, CBC_ORDER_ANY);
MUTATOR_HOOK(MakePlayerObserver, nades_RemovePlayer, CBC_ORDER_ANY);
MUTATOR_HOOK(ClientDisconnect, nades_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SpectateCopy, nades_SpectateCopy, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetCvars, nades_GetCvars, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_global, nades_RemovePlayer, CBC_ORDER_ANY);
MUTATOR_HOOK(BuildMutatorsString, nades_BuildMutatorsString, CBC_ORDER_ANY);
MUTATOR_HOOK(BuildMutatorsPrettyString, nades_BuildMutatorsPrettyString, CBC_ORDER_ANY);
MUTATOR_ONADD
{
- precache_model("models/ok_nade_counter/ok_nade_counter.md3");
-
- precache_model("models/weapons/h_ok_grenade.iqm");
- precache_model("models/weapons/v_ok_grenade.md3");
- precache_sound("weapons/rocket_impact.wav");
- precache_sound("weapons/grenade_bounce1.wav");
- precache_sound("weapons/grenade_bounce2.wav");
- precache_sound("weapons/grenade_bounce3.wav");
- precache_sound("weapons/grenade_bounce4.wav");
- precache_sound("weapons/grenade_bounce5.wav");
- precache_sound("weapons/grenade_bounce6.wav");
- precache_sound("overkill/grenadebip.ogg");
+ nades_Initialize();
}
return FALSE;
.entity nade;
.entity fake_nade;
+.float nade_timer;
.float nade_refire;
+.float bonus_nades;
+.float nade_special_time;
+.float bonus_nade_score;
+.float nade_type;
+.string pokenade_type;
+.entity nade_damage_target;
+.float cvar_cl_nade_type;
+.string cvar_cl_pokenade_type;
+.float toss_time;
+.float stat_healing_orb;
+.float stat_healing_orb_alpha;
+.float nade_show_particles;
-void() nades_CheckThrow;
+void toss_nade(entity e, vector _velocity, float _time);
+
+// Remove nades that are being thrown
+void(entity player) nades_Clear;
+
+// Give a bonus grenade to a player
+void(entity player, float score) nades_GiveBonus;
+// Remove all bonus nades from a player
+void(entity player) nades_RemoveBonus;
if(team_mate.msnt_timer < time)
if(SAME_TEAM(self, team_mate))
if(time > team_mate.spawnshieldtime) // spawn shielding
- if(team_mate.freezetag_frozen == 0)
+ if(team_mate.frozen == 0)
if(team_mate != self)
{
tracebox(team_mate.origin, PL_MIN, PL_MAX, team_mate.origin - '0 0 100', MOVE_WORLDONLY, team_mate);
MUTATOR_HOOKFUNCTION(touchexplode_PlayerThink)
{
if(time > self.touchexplode_time)
- if (!gameover)
+ if(!gameover)
+ if(!self.frozen)
if(IS_PLAYER(self))
if(self.deadflag == DEAD_NO)
if (!IS_INDEPENDENT_PLAYER(self))
FOR_EACH_PLAYER(other) if(self != other)
{
if(time > other.touchexplode_time)
+ if(!other.frozen)
if(other.deadflag == DEAD_NO)
if (!IS_INDEPENDENT_PLAYER(other))
if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
--- /dev/null
+void mutators_add()
+{
+ #define CHECK_MUTATOR_ADD(mut_cvar,mut_name,dependence) \
+ { if(cvar(mut_cvar) && dependence) { MUTATOR_ADD(mut_name); } }
+
+ CHECK_MUTATOR_ADD("g_dodging", mutator_dodging, 1);
+ CHECK_MUTATOR_ADD("g_spawn_near_teammate", mutator_spawn_near_teammate, teamplay);
+ CHECK_MUTATOR_ADD("g_physical_items", mutator_physical_items, 1);
+ CHECK_MUTATOR_ADD("g_touchexplode", mutator_touchexplode, 1);
+ CHECK_MUTATOR_ADD("g_minstagib", mutator_minstagib, !g_nexball);
+ CHECK_MUTATOR_ADD("g_invincible_projectiles", mutator_invincibleprojectiles, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_new_toys", mutator_new_toys, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_nix", mutator_nix, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_rocket_flying", mutator_rocketflying, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_vampire", mutator_vampire, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_superspectate", mutator_superspec, 1);
+ CHECK_MUTATOR_ADD("g_pinata", mutator_pinata, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_midair", mutator_midair, 1);
+ CHECK_MUTATOR_ADD("g_bloodloss", mutator_bloodloss, !cvar("g_minstagib"));
+ CHECK_MUTATOR_ADD("g_random_gravity", mutator_random_gravity, 1);
+ CHECK_MUTATOR_ADD("g_multijump", mutator_multijump, 1);
+ CHECK_MUTATOR_ADD("g_melee_only", mutator_melee_only, !cvar("g_minstagib") && !g_nexball);
+ CHECK_MUTATOR_ADD("g_nades", mutator_nades, 1);
+ CHECK_MUTATOR_ADD("g_sandbox", sandbox, 1);
+ CHECK_MUTATOR_ADD("g_campcheck", mutator_campcheck, 1);
+ CHECK_MUTATOR_ADD("g_buffs", mutator_buffs, 1);
+
+ #undef CHECK_MUTATOR_ADD
+}
MUTATOR_DECLARATION(gamemode_domination);
MUTATOR_DECLARATION(gamemode_lms);
MUTATOR_DECLARATION(gamemode_invasion);
+MUTATOR_DECLARATION(gamemode_cts);
+MUTATOR_DECLARATION(gamemode_race);
+MUTATOR_DECLARATION(gamemode_tdm);
MUTATOR_DECLARATION(mutator_dodging);
MUTATOR_DECLARATION(mutator_invincibleprojectiles);
MUTATOR_DECLARATION(mutator_melee_only);
MUTATOR_DECLARATION(mutator_nades);
MUTATOR_DECLARATION(mutator_campcheck);
+MUTATOR_DECLARATION(mutator_buffs);
MUTATOR_DECLARATION(sandbox);
--- /dev/null
+#include "base.qc"
+#include "gamemode_assault.qc"
+#include "gamemode_ca.qc"
+#include "gamemode_ctf.qc"
+#include "gamemode_domination.qc"
+#include "gamemode_freezetag.qc"
+#include "gamemode_keyhunt.qc"
+#include "gamemode_keepaway.qc"
+#include "gamemode_nexball.qc"
+#include "gamemode_onslaught.qc"
+#include "gamemode_lms.qc"
+#include "gamemode_invasion.qc"
+#include "gamemode_race.qc"
+#include "gamemode_cts.qc"
+#include "gamemode_tdm.qc"
+
+#include "mutator_invincibleproj.qc"
+#include "mutator_new_toys.qc"
+#include "mutator_nix.qc"
+#include "mutator_dodging.qc"
+#include "mutator_rocketflying.qc"
+#include "mutator_vampire.qc"
+#include "mutator_spawn_near_teammate.qc"
+#include "mutator_physical_items.qc"
+#include "sandbox.qc"
+#include "mutator_superspec.qc"
+#include "mutator_minstagib.qc"
+#include "mutator_touchexplode.qc"
+#include "mutator_pinata.qc"
+#include "mutator_midair.qc"
+#include "mutator_bloodloss.qc"
+#include "mutator_random_gravity.qc"
+#include "mutator_multijump.qc"
+#include "mutator_melee_only.qc"
+#include "mutator_nades.qc"
+#include "mutator_campcheck.qc"
+#include "mutator_buffs.qc"
--- /dev/null
+#include "base.qh"
+#include "mutators.qh"
+#include "gamemode_assault.qh"
+#include "gamemode_ca.qh"
+#include "gamemode_ctf.qh"
+#include "gamemode_domination.qh"
+#include "gamemode_keyhunt.qh"
+#include "gamemode_keepaway.qh"
+#include "gamemode_nexball.qh"
+#include "gamemode_lms.qh"
+#include "gamemode_invasion.qh"
+#include "gamemode_race.qh"
+#include "gamemode_cts.qh"
+
+#include "mutator_dodging.qh"
+#include "mutator_nades.qh"
+#include "mutator_buffs.qh"
.float playerstats_addedglobalinfo;
.string playerstats_id;
+// Note that _time isn't mentioned here. That one is special.
#define ALL_ANTICHEATS \
- ANTICHEAT("_time"); \
ANTICHEAT("speedhack"); \
ANTICHEAT("speedhack_m1"); \
ANTICHEAT("speedhack_m2"); \
PlayerStats_AddEvent(strcat("acc-", w.netname, "-frags"));
}
+ PlayerStats_AddEvent("anticheat-_time");
#define ANTICHEAT(name) \
PlayerStats_AddEvent("anticheat-" name)
ALL_ANTICHEATS
entity oldself = self;
self = p;
-#define ANTICHEAT(name) \
- PlayerStats_Event(p, "anticheat-" name, anticheat_getvalue(name))
+ float t0 = PlayerStats_Event(p, "anticheat-_time", 0);
+ float dt = anticheat_getvalue("_time");
+ PlayerStats_Event(p, "anticheat-_time", dt);
+ float f = dt / (t0 + dt);
+#define ANTICHEAT(name) do { \
+ float prev = PlayerStats_Event(p, "anticheat-" name, 0); \
+ float change = (anticheat_getvalue(name) - prev) * f; \
+ PlayerStats_Event(p, "anticheat-" name, change); \
+ } while(0)
ALL_ANTICHEATS
#undef ANTICHEAT
self = oldself;
../warpzonelib/server.qh
../common/constants.qh
+../common/stats.qh
../common/teams.qh
../common/util.qh
+../common/nades.qh
+../common/buffs.qh
../common/test.qh
../common/counting.qh
../common/items.qh
../common/notifications.qh // must be after autocvars
../common/deathtypes.qh // must be after notifications
-mutators/base.qh
-mutators/mutators.qh
-mutators/gamemode_assault.qh
-mutators/gamemode_ca.qh
-mutators/gamemode_ctf.qh
-mutators/gamemode_domination.qh
-mutators/gamemode_keyhunt.qh // TODO fix this
-mutators/gamemode_keepaway.qh
-mutators/gamemode_nexball.qh
-mutators/gamemode_lms.qh
-mutators/gamemode_invasion.qh
-mutators/mutator_dodging.qh
-mutators/mutator_nades.qh
+mutators/mutators_include.qh
//// tZork Turrets ////
tturrets/include/turrets_early.qh
spawnpoints.qh
+mapvoting.qh
+
ipban.qh
race.qh
miscfunctions.qc
+mutators/mutators.qc
+
waypointsprites.qc
bot/bot.qc
g_world.qc
g_casings.qc
+mapvoting.qc
+
t_jumppads.qc
t_teleporters.qc
../common/items.qc
+../common/nades.qc
+../common/buffs.qc
+
accuracy.qc
../csqcmodellib/sv_model.qc
../common/monsters/spawn.qc
-mutators/base.qc
-mutators/gamemode_assault.qc
-mutators/gamemode_ca.qc
-mutators/gamemode_ctf.qc
-mutators/gamemode_domination.qc
-mutators/gamemode_freezetag.qc
-mutators/gamemode_keyhunt.qc
-mutators/gamemode_keepaway.qc
-mutators/gamemode_nexball.qc
-mutators/gamemode_onslaught.qc
-mutators/gamemode_lms.qc
-mutators/gamemode_invasion.qc
-mutators/mutator_invincibleproj.qc
-mutators/mutator_new_toys.qc
-mutators/mutator_nix.qc
-mutators/mutator_dodging.qc
-mutators/mutator_rocketflying.qc
-mutators/mutator_vampire.qc
-mutators/mutator_spawn_near_teammate.qc
-mutators/mutator_physical_items.qc
-mutators/sandbox.qc
-mutators/mutator_superspec.qc
-mutators/mutator_minstagib.qc
-mutators/mutator_touchexplode.qc
-mutators/mutator_pinata.qc
-mutators/mutator_midair.qc
-mutators/mutator_bloodloss.qc
-mutators/mutator_random_gravity.qc
-mutators/mutator_multijump.qc
-mutators/mutator_melee_only.qc
-mutators/mutator_nades.qc
-mutators/mutator_campcheck.qc
+mutators/mutators_include.qc
../warpzonelib/anglestransform.qc
../warpzonelib/mathlib.qc
+float race_readTime(string map, float pos)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
+}
+
+string race_readUID(string map, float pos)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
+}
+
+float race_readPos(string map, float t)
+{
+ float i;
+ for (i = 1; i <= RANKINGS_CNT; ++i)
+ if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
+ return i;
+
+ return 0; // pos is zero if unranked
+}
+
+void race_writeTime(string map, float t, string myuid)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ float newpos;
+ newpos = race_readPos(map, t);
+
+ float i, prevpos = 0;
+ for(i = 1; i <= RANKINGS_CNT; ++i)
+ {
+ if(race_readUID(map, i) == myuid)
+ prevpos = i;
+ }
+ if (prevpos)
+ {
+ // player improved his existing record, only have to iterate on ranks between new and old recs
+ for (i = prevpos; i > newpos; --i)
+ {
+ db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
+ db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
+ }
+ }
+ else
+ {
+ // player has no ranked record yet
+ for (i = RANKINGS_CNT; i > newpos; --i)
+ {
+ db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
+ db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
+ }
+ }
+
+ // store new time itself
+ db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
+ db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
+}
+
+string race_readName(string map, float pos)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
+}
+
+
#define MAX_CHECKPOINTS 255
void spawnfunc_target_checkpoint();
if(recordholder == e.netname)
recordholder = "";
+ if(!IS_REAL_CLIENT(e))
+ return;
+
if(!spec)
msg_entity = e;
WRITESPECTATABLE_MSG_ONE({
});
}
-void race_InitSpectator()
-{
- if(g_race_qualifying)
- if(msg_entity.enemy.race_laptime)
- race_SendNextCheckpoint(msg_entity.enemy, 1);
-}
-
void race_send_recordtime(float msg)
{
// send the server best time
void race_SendStatus(float id, entity e)
{
+ if(!IS_REAL_CLIENT(e))
+ return;
+
float msg;
if (id == 0)
msg = MSG_ONE;
});
}
-void race_setTime(string map, float t, string myuid, string mynetname, entity e) { // netname only used TEMPORARILY for printing
+void race_setTime(string map, float t, string myuid, string mynetname, entity e)
+{
+ // netname only used TEMPORARILY for printing
float newpos, player_prevpos;
newpos = race_readPos(map, t);
race_SendStatus(0, e); // "fail"
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_RANKED, mynetname, player_prevpos, t, oldrec);
return;
- } else if (!newpos) { // no ranking, time worse than the worst ranked
+ }
+ else if (!newpos)
+ {
+ // no ranking, time worse than the worst ranked
oldrec = race_readTime(GetMapname(), RANKINGS_CNT);
race_SendStatus(0, e); // "fail"
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_UNRANKED, mynetname, RANKINGS_CNT, t, oldrec);
// store new ranking
race_writeTime(GetMapname(), t, myuid);
- if (newpos == 1) {
+ if (newpos == 1)
+ {
write_recordmarker(e, time - TIME_DECODE(t), TIME_DECODE(t));
race_send_recordtime(MSG_ALL);
}
}
}
-void race_deleteTime(string map, float pos) {
+void race_deleteTime(string map, float pos)
+{
string rr;
if(g_cts)
rr = CTS_RECORD;
rr = RACE_RECORD;
float i;
- for (i = pos; i <= RANKINGS_CNT; ++i) {
- if (i == RANKINGS_CNT) {
+ for (i = pos; i <= RANKINGS_CNT; ++i)
+ {
+ if (i == RANKINGS_CNT)
+ {
db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), string_null);
db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), string_null);
}
- else {
+ else
+ {
db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(GetMapname(), i+1)));
db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(GetMapname(), i+1));
}
if(recordholder == e.netname)
recordholder = "";
- if(t != 0) {
+ if(t != 0)
+ {
if(cp == race_timed_checkpoint)
{
race_setTime(GetMapname(), t, e.crypto_idfp, e.netname, e);
recordholder = "";
}
- msg_entity = e;
- if(g_race_qualifying)
+ if(IS_REAL_CLIENT(e))
{
- WRITESPECTATABLE_MSG_ONE_VARNAME(dummy1, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
- WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_QUALIFYING);
- WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
- WriteInt24_t(MSG_ONE, t); // time to that intermediate
- WriteInt24_t(MSG_ONE, recordtime); // previously best time
- WriteString(MSG_ONE, recordholder); // record holder
- });
+ msg_entity = e;
+ if(g_race_qualifying)
+ {
+ WRITESPECTATABLE_MSG_ONE_VARNAME(dummy1, {
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_QUALIFYING);
+ WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
+ WriteInt24_t(MSG_ONE, t); // time to that intermediate
+ WriteInt24_t(MSG_ONE, recordtime); // previously best time
+ WriteString(MSG_ONE, recordholder); // record holder
+ });
+ }
}
}
else // RACE! Not Qualifying
else
lself = lother = othtime = 0;
- msg_entity = e;
- WRITESPECTATABLE_MSG_ONE_VARNAME(dummy2, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
- WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE);
- WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
- if(e == oth)
- {
- WriteInt24_t(MSG_ONE, 0);
- WriteByte(MSG_ONE, 0);
- WriteString(MSG_ONE, "");
- }
- else
- {
- WriteInt24_t(MSG_ONE, TIME_ENCODE(time - race_checkpoint_lasttimes[cp]));
- WriteByte(MSG_ONE, lself - lother);
- WriteString(MSG_ONE, oth.netname); // record holder
- }
- });
+ if(IS_REAL_CLIENT(e))
+ {
+ msg_entity = e;
+ WRITESPECTATABLE_MSG_ONE_VARNAME(dummy2, {
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE);
+ WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
+ if(e == oth)
+ {
+ WriteInt24_t(MSG_ONE, 0);
+ WriteByte(MSG_ONE, 0);
+ WriteString(MSG_ONE, "");
+ }
+ else
+ {
+ WriteInt24_t(MSG_ONE, TIME_ENCODE(time - race_checkpoint_lasttimes[cp]));
+ WriteByte(MSG_ONE, lself - lother);
+ WriteString(MSG_ONE, oth.netname); // record holder
+ }
+ });
+ }
race_checkpoint_lastplayers[cp] = e;
race_checkpoint_lasttimes[cp] = time;
race_checkpoint_lastlaps[cp] = lself;
- msg_entity = oth;
- WRITESPECTATABLE_MSG_ONE_VARNAME(dummy3, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
- WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT);
- WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
- if(e == oth)
- {
- WriteInt24_t(MSG_ONE, 0);
- WriteByte(MSG_ONE, 0);
- WriteString(MSG_ONE, "");
- }
- else
- {
- WriteInt24_t(MSG_ONE, TIME_ENCODE(time - othtime));
- WriteByte(MSG_ONE, lother - lself);
- WriteString(MSG_ONE, e.netname); // record holder
- }
- });
+ if(IS_REAL_CLIENT(oth))
+ {
+ msg_entity = oth;
+ WRITESPECTATABLE_MSG_ONE_VARNAME(dummy3, {
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT);
+ WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
+ if(e == oth)
+ {
+ WriteInt24_t(MSG_ONE, 0);
+ WriteByte(MSG_ONE, 0);
+ WriteString(MSG_ONE, "");
+ }
+ else
+ {
+ WriteInt24_t(MSG_ONE, TIME_ENCODE(time - othtime));
+ WriteByte(MSG_ONE, lother - lself);
+ WriteString(MSG_ONE, e.netname); // record holder
+ }
+ });
+ }
}
}
e.race_penalty_accumulator = 0;
e.race_lastpenalty = world;
+ if(!IS_REAL_CLIENT(e))
+ return;
+
msg_entity = e;
WRITESPECTATABLE_MSG_ONE({
WriteByte(MSG_ONE, SVC_TEMPENTITY);
other.porto_forbidden = 2; // decreased by 1 each StartFrame
- if(defrag_ents) {
+ if(defrag_ents)
+ {
if(self.race_checkpoint == -2)
{
self.race_checkpoint = other.race_checkpoint;
float largest_cp_id = 0;
float cp_amount = 0;
- for(cp = world; (cp = find(cp, classname, "target_checkpoint"));) {
+ for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
+ {
cp_amount += 1;
if(cp.race_checkpoint > largest_cp_id) // update the finish id if someone hit a new checkpoint
{
race_highest_checkpoint = largest_cp_id + 1;
race_timed_checkpoint = largest_cp_id + 1;
- for(cp = world; (cp = find(cp, classname, "target_checkpoint"));) {
+ for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
+ {
if(cp.race_checkpoint == -2) // set defragcpexists to -1 so that the cp id file will be rewritten when someone finishes
defragcpexists = -1;
}
}
}
- if(cp_amount == 0) {
+ if(cp_amount == 0)
+ {
for(cp = world; (cp = find(cp, classname, "target_stopTimer"));)
cp.race_checkpoint = 1;
race_highest_checkpoint = 1;
while((l = fgets(fh)))
{
len = tokenize_console(l);
- if(len != 2) {
+ if(len != 2)
+ {
defragcpexists = -1; // something's wrong in the defrag cp file, set defragcpexists to -1 so that it will be rewritten when someone finishes
continue;
}
g_race_qualifying = qual;
- if(race_timed_checkpoint) {
- if(defrag_ents) {
+ if(race_timed_checkpoint)
+ {
+ if(defrag_ents)
+ {
for(cp = world; (cp = find(cp, classname, "target_startTimer"));)
WaypointSprite_UpdateSprites(cp.sprite, "race-start", "", "");
for(cp = world; (cp = find(cp, classname, "target_stopTimer"));)
WaypointSprite_UpdateSprites(cp.sprite, "race-finish", "", "");
- for(cp = world; (cp = find(cp, classname, "target_checkpoint"));) {
+ for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
+ {
if(cp.race_checkpoint == -2) // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes
defragcpexists = -1;
}
- if(defragcpexists != -1){
+ if(defragcpexists != -1)
+ {
float largest_cp_id = 0;
for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
if(cp.race_checkpoint > largest_cp_id)
cp.race_checkpoint = largest_cp_id + 1; // finish line
race_highest_checkpoint = largest_cp_id + 1;
race_timed_checkpoint = largest_cp_id + 1;
- } else {
+ }
+ else
+ {
for(cp = world; (cp = find(cp, classname, "target_stopTimer"));)
cp.race_checkpoint = 255; // finish line
race_highest_checkpoint = 255;
race_timed_checkpoint = 255;
}
}
- else {
+ else
+ {
for(cp = world; (cp = find(cp, classname, "trigger_race_checkpoint")); )
if(cp.sprite)
{
}
}
- if(defrag_ents) {
+ if(defrag_ents)
+ {
entity trigger, targ;
for(trigger = world; (trigger = find(trigger, classname, "trigger_multiple")); )
for(targ = world; (targ = find(targ, targetname, trigger.target)); )
- if (targ.classname == "target_checkpoint" || targ.classname == "target_startTimer" || targ.classname == "target_stopTimer") {
+ if (targ.classname == "target_checkpoint" || targ.classname == "target_startTimer" || targ.classname == "target_stopTimer")
+ {
trigger.wait = 0;
trigger.delay = 0;
targ.wait = 0;
void spawnfunc_trigger_race_checkpoint()
{
vector o;
- if(!g_race && !g_cts)
- {
- remove(self);
- return;
- }
+ if(!g_race && !g_cts) { remove(self); return; }
EXACTTRIGGER_INIT;
void spawnfunc_target_checkpoint() // defrag entity
{
vector o;
- if(!g_race && !g_cts)
- {
- remove(self);
- return;
- }
+ if(!g_race && !g_cts) { remove(self); return; }
defrag_ents = 1;
EXACTTRIGGER_INIT;
self.race_checkpoint = self.race_respawn_checkpoint;
}
-void race_PreDie()
-{
- if(!g_race && !g_cts)
- return;
-
- race_AbandonRaceCheck(self);
-}
-
-void race_PreSpawn()
-{
- if(!g_race && !g_cts)
- return;
- if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
- race_PreparePlayer();
- else // respawn
- race_RetractPlayer();
-
- race_AbandonRaceCheck(self);
-}
-
-void race_PostSpawn(entity spot)
-{
- if(!g_race && !g_cts)
- return;
-
- if(spot.target == "")
- // Emergency: this wasn't a real spawnpoint. Can this ever happen?
- race_PreparePlayer();
-
- // if we need to respawn, do it right
- self.race_respawn_checkpoint = self.race_checkpoint;
- self.race_respawn_spotref = spot;
-
- self.race_place = 0;
-}
-
-void race_PreSpawnObserver()
-{
- if(!g_race && !g_cts)
- return;
- race_PreparePlayer();
- self.race_checkpoint = -1;
-}
-
void spawnfunc_info_player_race (void)
{
- if(!g_race && !g_cts)
- {
- remove(self);
- return;
- }
+ if(!g_race && !g_cts) { remove(self); return; }
++race_spawns;
spawnfunc_info_player_deathmatch();
self = e;
}
-void race_ReadyRestart()
-{
- float s;
-
- Score_NicePrint(world);
-
- race_ClearRecords();
- PlayerScore_Sort(race_place, 0, 1, 0);
-
- entity e;
- FOR_EACH_CLIENT(e)
- {
- if(e.race_place)
- {
- s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
- if(!s)
- e.race_place = 0;
- }
- print(e.netname, " = ", ftos(e.race_place), "\n");
- }
-
- if(g_race_qualifying == 2)
- {
- g_race_qualifying = 0;
- independent_players = 0;
- cvar_set("fraglimit", ftos(race_fraglimit));
- cvar_set("leadlimit", ftos(race_leadlimit));
- cvar_set("timelimit", ftos(race_timelimit));
- ScoreRules_race();
- }
-}
-
void race_ImposePenaltyTime(entity pl, float penalty, string reason)
{
if(g_race_qualifying)
{
pl.race_penalty_accumulator += penalty;
- msg_entity = pl;
- WRITESPECTATABLE_MSG_ONE({
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
- WriteByte(MSG_ONE, RACE_NET_PENALTY_QUALIFYING);
- WriteShort(MSG_ONE, TIME_ENCODE(penalty));
- WriteString(MSG_ONE, reason);
- });
+ if(IS_REAL_CLIENT(pl))
+ {
+ msg_entity = pl;
+ WRITESPECTATABLE_MSG_ONE({
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteByte(MSG_ONE, RACE_NET_PENALTY_QUALIFYING);
+ WriteShort(MSG_ONE, TIME_ENCODE(penalty));
+ WriteString(MSG_ONE, reason);
+ });
+ }
}
else
{
pl.race_penalty = time + penalty;
- msg_entity = pl;
- WRITESPECTATABLE_MSG_ONE_VARNAME(dummy, {
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_RACE);
- WriteByte(MSG_ONE, RACE_NET_PENALTY_RACE);
- WriteShort(MSG_ONE, TIME_ENCODE(penalty));
- WriteString(MSG_ONE, reason);
- });
+ if(IS_REAL_CLIENT(pl))
+ {
+ msg_entity = pl;
+ WRITESPECTATABLE_MSG_ONE_VARNAME(dummy, {
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_RACE);
+ WriteByte(MSG_ONE, RACE_NET_PENALTY_RACE);
+ WriteShort(MSG_ONE, TIME_ENCODE(penalty));
+ WriteString(MSG_ONE, reason);
+ });
+ }
}
}
-void race_InitSpectator();
-void race_PreSpawnObserver();
-void race_PreSpawn();
-void race_PostSpawn(entity spot);
-void race_PreDie();
-void race_ReadyRestart();
-float race_teams;
float race_spawns;
-float race_PreviousCheckpoint(float f);
-float race_NextCheckpoint(float f);
-void race_AbandonRaceCheck(entity p);
float race_highest_place_spawn; // number of places; a place higher gets spawned at 0
float race_lowest_place_spawn; // where to spawn in qualifying
float race_fraglimit;
.float race_started;
.float race_completed;
float race_completing;
-void race_ImposePenaltyTime(entity pl, float penalty, string reason);
-void race_StartCompleting();
.float race_movetime; // for reading
.float race_movetime_frac; // fractional accumulator for higher accuracy (helper for writing)
.float race_respawn_checkpoint;
.entity race_respawn_spotref; // try THIS spawn in case you respawn
+// definitions for functions used outside race.qc
+float race_PreviousCheckpoint(float f);
+float race_NextCheckpoint(float f);
+void race_AbandonRaceCheck(entity p);
+void race_ImposePenaltyTime(entity pl, float penalty, string reason);
+void race_StartCompleting();
float race_GetFractionalLapCount(entity e);
+float race_readTime(string map, float pos);
+string race_readUID(string map, float pos);
+string race_readName(string map, float pos);
if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
- if(g_cts) return 0; // in CTS, you don't lose score by observing
- if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
-
sk = player.scorekeeper;
for(i = 0; i < MAX_SCORE; ++i)
{
ScoreRules_basics_end();
}
-// Race stuff
-#define ST_RACE_LAPS 1
-#define SP_RACE_LAPS 4
-#define SP_RACE_TIME 5
-#define SP_RACE_FASTEST 6
-void ScoreRules_race()
-{
- ScoreRules_basics(race_teams, 0, 0, FALSE);
- if(race_teams)
- {
- ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
- }
- else if(g_race_qualifying)
- {
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- }
- else
- {
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
- }
- ScoreRules_basics_end();
-}
-
// Nexball stuff
#define ST_NEXBALL_GOALS 1
#define SP_NEXBALL_GOALS 4
float spawnpoint_nag;
float SpawnEvent_Send(entity to, float sf);
entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck);
-
+entity SelectSpawnPoint (float anypoint);
if (self.watersound_finished < time)
{
self.watersound_finished = time + 0.5;
- sound (self, CH_PLAYER, "player/lava.wav", VOL_BASE, ATTEN_NORM);
+ sound (self, CH_PLAYER_SINGLE, "player/lava.wav", VOL_BASE, ATTEN_NORM);
}
Damage (self, world, world, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * self.waterlevel, DEATH_LAVA, self.origin, '0 0 0');
}
if (self.watersound_finished < time)
{
self.watersound_finished = time + 0.5;
- sound (self, CH_PLAYER, "player/slime.wav", VOL_BASE, ATTEN_NORM);
+ sound (self, CH_PLAYER_SINGLE, "player/slime.wav", VOL_BASE, ATTEN_NORM);
}
Damage (self, world, world, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * self.waterlevel, DEATH_SLIME, self.origin, '0 0 0');
}
{
// check for falling damage
float velocity_len = vlen(self.velocity);
- if(!self.hook.state && !(g_cts && !autocvar_g_cts_selfdamage))
+ if(!self.hook.state)
{
dm = vlen(self.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.
if (self.deadflag)
float game_delay_last;
float RedirectionThink();
-entity SelectSpawnPoint (float anypoint);
void StartFrame (void)
{
execute_next_frame();
var vector autocvar_cl_weapon_stay_color = '2 0.5 0.5';
var float autocvar_cl_weapon_stay_alpha = 0.75;
var float autocvar_cl_simple_items = 0;
-var string autocvr_cl_simpleitems_postfix = "_simple";
+var string autocvar_cl_simpleitems_postfix = "_simple";
.float spawntime;
.float gravity;
.vector colormod;
- if(fexists(sprintf("%s%s.md3", _fn2, autocvr_cl_simpleitems_postfix)))
- self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvr_cl_simpleitems_postfix));
- else if(fexists(sprintf("%s%s.dpm", _fn2, autocvr_cl_simpleitems_postfix)))
- self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvr_cl_simpleitems_postfix));
- else if(fexists(sprintf("%s%s.iqm", _fn2, autocvr_cl_simpleitems_postfix)))
- self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvr_cl_simpleitems_postfix));
- else if(fexists(sprintf("%s%s.obj", _fn2, autocvr_cl_simpleitems_postfix)))
- self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvr_cl_simpleitems_postfix));
+ if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
+ self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
+ else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
+ self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
+ else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
+ self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
+ else if(fexists(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix)))
+ self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix));
else
{
self.draw = ItemDraw;
vector v;
self.nextthink = time + 0.1;
- if (!(self.owner.active == ACTIVE_ACTIVE))
+ if(self.owner.active != ACTIVE_ACTIVE)
{
self.owner.velocity = '0 0 0';
return;
void button_use()
{
- if (!(self.active == ACTIVE_ACTIVE))
+ if(self.active != ACTIVE_ACTIVE)
return;
self.enemy = activator;
// some keys were used
if (other.key_door_messagetime <= time) {
play2(other, "misc/talk.wav");
- centerprint(other, strcat("You also need ", item_keys_keylist(door.itemkeys), "!"));
+ 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");
- centerprint(other, strcat("You need ", item_keys_keylist(door.itemkeys), "!"));
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
other.key_door_messagetime = time + 2;
}
}
if (door.itemkeys) {
// door is now unlocked
play2(other, "misc/talk.wav");
- centerprint(other, "Door unlocked!");
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_UNLOCKED);
return TRUE;
} else
return FALSE;
float n, i, t;
self.nextthink = time + 0.1;
- if (!(self.owner.active == ACTIVE_ACTIVE))
+ if(self.owner.active != ACTIVE_ACTIVE)
{
self.owner.velocity = '0 0 0';
return;
{
self.nextthink = time + 0.1;
- if (!(self.owner.active == ACTIVE_ACTIVE))
+ if(self.owner.active != ACTIVE_ACTIVE)
{
self.owner.velocity = '0 0 0';
return;
InitializeEntity(self, target_give_init, INITPRIO_FINDTARGET);
}
-//void spawnfunc_item_flight() /* not supported */
-//void spawnfunc_item_haste() /* not supported */
+//void spawnfunc_item_flight() /* handled by buffs mutator or jetpack */
+//void spawnfunc_item_haste() /* handled by buffs mutator */
//void spawnfunc_item_health() /* handled in t_quake.qc */
//void spawnfunc_item_health_large() /* handled in t_items.qc */
//void spawnfunc_item_health_small() /* handled in t_items.qc */
//void spawnfunc_item_health_mega() /* handled in t_items.qc */
-//void spawnfunc_item_invis() /* not supported */
-//void spawnfunc_item_regen() /* not supported */
+//void spawnfunc_item_invis() /* handled by buffs mutator */
+//void spawnfunc_item_regen() /* handled by buffs mutator */
// CTF spawnfuncs handled in mutators/gamemode_ctf.qc now
-void spawnfunc_item_flight() { spawnfunc_item_jetpack(); }
+void spawnfunc_item_flight()
+{
+ if(!cvar("g_buffs") || !cvar("g_buffs_flight"))
+ spawnfunc_item_jetpack();
+ else
+ buff_Init_Compat(self, BUFF_FLIGHT);
+}
.float notteam;
.float notsingle;
{
if(!activator)
return;
- if(!IS_REAL_CLIENT(activator))
- return;
- msg_entity = activator;
- target_music_sendto(MSG_ONE, 1);
+ 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); }
}
PlayerScore_Clear(e);
}
-void tdm_init();
void entcs_init();
void LogTeamchange(float player_id, float team_number, float type)
if(g_tdm)
{
ActivateTeamplay();
- tdm_init();
+ fraglimit_override = autocvar_g_tdm_point_limit;
+ leadlimit_override = autocvar_g_tdm_point_leadlimit;
+ MUTATOR_ADD(gamemode_tdm);
+
if(autocvar_g_tdm_team_spawns)
have_team_spawns = -1; // request team spawns
}
fraglimit_override = autocvar_g_domination_point_limit;
leadlimit_override = autocvar_g_domination_point_leadlimit;
MUTATOR_ADD(gamemode_domination);
+
+ if(autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
+ fraglimit_override = autocvar_g_domination_roundbased_point_limit;
+
have_team_spawns = -1; // request team spawns
}
if(g_race)
{
-
if(autocvar_g_race_teams)
{
ActivateTeamplay();
qualifying_override = autocvar_g_race_qualifying_timelimit_override;
fraglimit_override = autocvar_g_race_laps_limit;
leadlimit_override = 0; // currently not supported by race
+
+ MUTATOR_ADD(gamemode_race);
}
if(g_cts)
g_race_qualifying = 1;
fraglimit_override = 0;
leadlimit_override = 0;
+ MUTATOR_ADD(gamemode_cts);
}
if(g_nexball)
}
if(g_race || g_cts)
- {
- if(g_race_qualifying)
- independent_players = 1;
-
- ScoreRules_race();
- }
+ if(g_race_qualifying)
+ independent_players = 1;
InitializeEntity(world, default_delayedinit, INITPRIO_GAMETYPE_FALLBACK);
}
if (g_grappling_hook)
s = strcat(s, "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
+ if (cvar("g_nades"))
+ s = strcat(s, "\n\n^3nades^8 are enabled, press 'g' to use them\n");
+
if(cache_lastmutatormsg != autocvar_g_mutatormsg)
{
if(cache_lastmutatormsg)
else
{
// cover anything else by treating it like tdm with no teams spawned
- if(g_race)
- dm = race_teams;
- else
- dm = 2;
+ dm = 2;
ret_float = dm;
MUTATOR_CALLHOOK(GetTeamCount);
{
if(autocvar_g_campaign && pl && IS_REAL_CLIENT(pl))
return 1; // special case for campaign and player joining
- else if(g_domination)
- error("Too few teams available for domination\n");
- else if(g_ctf)
- error("Too few teams available for ctf\n");
- else if(g_keyhunt)
- error("Too few teams available for key hunt\n");
- else if(g_freezetag)
- error("Too few teams available for freeze tag\n");
else
- error("Too few teams available for team deathmatch\n");
+ error(sprintf("Too few teams available for %s\n", MapInfo_Type_ToString(MapInfo_CurrentGametype())));
}
// count how many players are in each team
}
if((autocvar_g_campaign) || (autocvar_g_changeteam_banned && self.wasplayer)) {
- sprint(self, "Team changes not allowed\n");
+ Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TEAMCHANGE_NOTALLOWED);
return; // changing teams is not allowed
}
GetTeamCounts(self);
if(!TeamSmallerEqThanTeam(dteam, steam, self))
{
- sprint(self, "Cannot change to a larger/better/shinier team\n");
+ Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
return;
}
}
if(selected.deadflag == DEAD_NO)
Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE, selected.origin, '0 0 0');
- centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", Team_ColoredFullName(selected.team)));
-}
-
-// code from here on is just to support maps that don't have team entities
-void tdm_spawnteam (string teamname, float teamcolor)
-{
- entity e;
- e = spawn();
- e.classname = "tdm_team";
- e.netname = teamname;
- e.cnt = teamcolor;
- e.team = e.cnt + 1;
-}
-
-// spawn some default teams if the map is not set up for tdm
-void tdm_spawnteams()
-{
- float numteams;
-
- numteams = autocvar_g_tdm_teams_override;
- if(numteams < 2)
- numteams = autocvar_g_tdm_teams;
- numteams = bound(2, numteams, 4);
-
- tdm_spawnteam("Red", NUM_TEAM_1-1);
- tdm_spawnteam("Blue", NUM_TEAM_2-1);
- if(numteams >= 3)
- tdm_spawnteam("Yellow", NUM_TEAM_3-1);
- if(numteams >= 4)
- tdm_spawnteam("Pink", NUM_TEAM_4-1);
-}
-
-void tdm_delayedinit()
-{
- // if no teams are found, spawn defaults
- if (find(world, classname, "tdm_team") == world)
- tdm_spawnteams();
-}
-
-void tdm_init()
-{
- InitializeEntity(world, tdm_delayedinit, INITPRIO_GAMETYPE);
+ Send_Notification(NOTIF_ONE, selected, MSG_CENTER, CENTER_DEATH_SELF_AUTOTEAMCHANGE, selected.team);
}
return;
}
- if (owner_player.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || owner_player.deadflag != DEAD_NO || !owner_player.BUTTON_ATCK || owner_player.freezetag_frozen)
+ if (owner_player.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || owner_player.deadflag != DEAD_NO || !owner_player.BUTTON_ATCK || owner_player.frozen)
{
if(self == owner_player.lgbeam)
owner_player.lgbeam = world;
// a player's mines shall explode if he disconnects or dies
// TODO: Do this on team change too -- Samual: But isn't a player killed when they switch teams?
- if(!IS_PLAYER(self.realowner) || self.realowner.deadflag != DEAD_NO || self.realowner.freezetag_frozen)
+ if(!IS_PLAYER(self.realowner) || self.realowner.deadflag != DEAD_NO || self.realowner.frozen)
{
other = world;
self.projectiledeathtype |= HITTYPE_BOUNCE;
head = findradius(self.origin, autocvar_g_balance_minelayer_proximityradius);
while(head)
{
- if(IS_PLAYER(head) && head.deadflag == DEAD_NO && !head.freezetag_frozen)
+ if(IS_PLAYER(head) && head.deadflag == DEAD_NO && !head.frozen)
if(head != self.realowner && DIFF_TEAM(head, self.realowner)) // don't trigger for team mates
if(!self.mine_time)
{
Przemysław "atheros" Grzywacz
Robert "ai" Kuroto
The player with the unnecessarily long name
+Mattia "Melanosuchus" Basaglia
**Translators