]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'TimePath/experiments/csqc_prediction' into Mario/qc_physics
authorMario <zacjardine@y7mail.com>
Tue, 17 Feb 2015 19:52:51 +0000 (06:52 +1100)
committerMario <zacjardine@y7mail.com>
Tue, 17 Feb 2015 19:52:51 +0000 (06:52 +1100)
Conflicts:
qcsrc/server/miscfunctions.qc
qcsrc/server/t_plats.qc

104 files changed:
bal-wep-xonotic.cfg
bal-wep-xpm.cfg
balance-xonotic.cfg
balance-xpm.cfg
crosshairs.cfg
defaultXonotic.cfg
gfx/crosshair29.tga [deleted file]
gfx/crosshair30.tga [deleted file]
gfx/crosshair31.tga
gfx/crosshair32.tga
gfx/crosshair33.tga
gfx/crosshair34.tga
gfx/crosshair35.tga
gfx/crosshair36.tga
gfx/crosshair37.tga
gfx/crosshair38.tga
gfx/crosshair39.tga
gfx/crosshair40.tga
gfx/crosshair41.tga
gfx/crosshair42.tga
gfx/crosshair43.tga [new file with mode: 0644]
gfx/crosshair44.tga [new file with mode: 0644]
gfx/crosshair45.tga [new file with mode: 0644]
gfx/crosshair46.tga [new file with mode: 0644]
gfx/crosshair47.tga [new file with mode: 0644]
gfx/crosshair48.tga [new file with mode: 0644]
gfx/crosshair49.tga [new file with mode: 0644]
gfx/crosshair50.tga [new file with mode: 0644]
gfx/crosshair51.tga [new file with mode: 0644]
gfx/crosshair52.tga [new file with mode: 0644]
gfx/crosshair53.tga [new file with mode: 0644]
gfx/crosshair54.tga [new file with mode: 0644]
gfx/crosshair55.tga [new file with mode: 0644]
gfx/crosshair56.tga [new file with mode: 0644]
gfx/crosshair57.tga [new file with mode: 0644]
gfx/crosshair58.tga [new file with mode: 0644]
gfx/crosshair59.tga [new file with mode: 0644]
gfx/crosshair60.tga [new file with mode: 0644]
gfx/crosshair61.tga [new file with mode: 0644]
gfx/crosshair62.tga [new file with mode: 0644]
gfx/crosshair63.tga [new file with mode: 0644]
gfx/crosshair64.tga [new file with mode: 0644]
gfx/crosshair65.tga [new file with mode: 0644]
gfx/crosshair66.tga [new file with mode: 0644]
gfx/crosshaircalibrate.tga [new file with mode: 0644]
gfx/crosshairdot.tga
gfx/crosshairmoustache.tga [new file with mode: 0644]
gfx/crosshairtuba.tga
mutators.cfg
qcsrc/client/casings.qc
qcsrc/client/hud.qc
qcsrc/client/laser.qc
qcsrc/client/progs.src
qcsrc/client/sys-post.qh [deleted file]
qcsrc/client/sys-pre.qh [deleted file]
qcsrc/client/tuba.qc
qcsrc/client/tuba.qh
qcsrc/common/csqcmodel_settings.qh
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/util-pre.qh
qcsrc/common/util.qc
qcsrc/common/weapons/w_blaster.qc
qcsrc/common/weapons/w_crylink.qc
qcsrc/common/weapons/w_devastator.qc
qcsrc/common/weapons/w_electro.qc
qcsrc/common/weapons/w_rifle.qc
qcsrc/common/weapons/w_rpc.qc
qcsrc/common/weapons/w_vaporizer.qc
qcsrc/common/weapons/weapons.qc
qcsrc/csqcmodellib/settings.qh
qcsrc/dpdefs/csprogsdefs.qh
qcsrc/dpdefs/dpextensions.qh
qcsrc/dpdefs/keycodes.qh
qcsrc/dpdefs/menudefs.qh
qcsrc/menu/item/modalcontroller.qc
qcsrc/menu/progs.src
qcsrc/menu/xonotic/dialog_firstrun.qc
qcsrc/menu/xonotic/dialog_multiplayer_create.qc
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc
qcsrc/menu/xonotic/dialog_multiplayer_profile.qc
qcsrc/menu/xonotic/dialog_settings_effects.qc
qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc
qcsrc/menu/xonotic/dialog_settings_game_hud.qc
qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc
qcsrc/menu/xonotic/dialog_settings_game_messages.qc
qcsrc/menu/xonotic/dialog_settings_input.qc
qcsrc/menu/xonotic/gametypelist.qc
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/util.qh
qcsrc/server/cl_client.qc
qcsrc/server/command/common.qc
qcsrc/server/command/common.qh
qcsrc/server/command/radarmap.qc
qcsrc/server/ipban.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/sys-post.qh
qcsrc/server/sys-pre.qh
qcsrc/server/t_plats.qc [new file with mode: 0644]
qcsrc/warpzonelib/mathlib.qc
qcsrc/warpzonelib/mathlib.qh
xonotic-credits.txt

index 2e6d10e7b1d62b34202c7388d5c74979f0b051ad..1fa36d0c4985fbbb016e532453947a2a692e752c 100644 (file)
@@ -34,12 +34,12 @@ set g_balance_blaster_weaponthrowable 0
 // {{{ #2: Shotgun
 set g_balance_shotgun_primary_ammo 1
 set g_balance_shotgun_primary_animtime 0.2
-set g_balance_shotgun_primary_bullets 14
-set g_balance_shotgun_primary_damage 3.5
+set g_balance_shotgun_primary_bullets 12
+set g_balance_shotgun_primary_damage 4
 set g_balance_shotgun_primary_force 15
 set g_balance_shotgun_primary_refire 0.75
 set g_balance_shotgun_primary_solidpenetration 3.8
-set g_balance_shotgun_primary_spread 0.11
+set g_balance_shotgun_primary_spread 0.12
 set g_balance_shotgun_reload_ammo 0
 set g_balance_shotgun_reload_time 2
 set g_balance_shotgun_secondary 1
index 2e6d10e7b1d62b34202c7388d5c74979f0b051ad..1fa36d0c4985fbbb016e532453947a2a692e752c 100644 (file)
@@ -34,12 +34,12 @@ set g_balance_blaster_weaponthrowable 0
 // {{{ #2: Shotgun
 set g_balance_shotgun_primary_ammo 1
 set g_balance_shotgun_primary_animtime 0.2
-set g_balance_shotgun_primary_bullets 14
-set g_balance_shotgun_primary_damage 3.5
+set g_balance_shotgun_primary_bullets 12
+set g_balance_shotgun_primary_damage 4
 set g_balance_shotgun_primary_force 15
 set g_balance_shotgun_primary_refire 0.75
 set g_balance_shotgun_primary_solidpenetration 3.8
-set g_balance_shotgun_primary_spread 0.11
+set g_balance_shotgun_primary_spread 0.12
 set g_balance_shotgun_reload_ammo 0
 set g_balance_shotgun_reload_time 2
 set g_balance_shotgun_secondary 1
index 08ff39c0e700f843a9cc44e39c25829b9a5f625f..76ba515256438d98b65dbf5d694a78d121e64029 100644 (file)
@@ -155,7 +155,7 @@ set g_projectiles_damage -2
 // 0: only damage from contents (lava/slime) or exceptions
 // 1: only self damage or damage from contents or exceptions
 // 2: allow all damage to projectiles normally
-set g_projectiles_keep_owner 0
+set g_projectiles_keep_owner 1
 set g_projectiles_newton_style 0
 // possible values:
 // 0: absolute velocity projectiles (like Quake)
index c254bcdf8d5118efd4b5f1aec0d687c609c63388..e7855280edc2b2541c9895ecf5d6fd3a336279c7 100644 (file)
@@ -155,7 +155,7 @@ set g_projectiles_damage -2
 // 0: only damage from contents (lava/slime) or exceptions
 // 1: only self damage or damage from contents or exceptions
 // 2: allow all damage to projectiles normally
-set g_projectiles_keep_owner 0
+set g_projectiles_keep_owner 1
 set g_projectiles_newton_style 0
 // possible values:
 // 0: absolute velocity projectiles (like Quake)
index 4d44688a28c78a5682fade92d6cfa50afeb67745..fb341c5b8537f37c492a2de2c7148ebd39b9b579 100644 (file)
@@ -6,13 +6,13 @@
 seta crosshair 16
 seta crosshair_enabled 1 // main toggle for enabling/disabling crosshair rendering, used mostly just for the menu... 1 = with per-weapon crosshairs, 2 = custom crosshair
 seta crosshair_color "0.6 0.8 1"
-seta crosshair_alpha 0.75
-seta crosshair_size 0.3
+seta crosshair_alpha 0.8
+seta crosshair_size 0.4
 
 // crosshair dot settings
 seta crosshair_dot 0
 seta crosshair_dot_alpha 1
-seta crosshair_dot_size 0.600000
+seta crosshair_dot_size 0.6
 seta crosshair_dot_color "1 0 0"
 seta crosshair_dot_color_custom 1 "use a custom color for the crosshair dot"
 
index f598c3c76b361fdb6fe0e3cbc1f0285206e7ec17..19643ec210c93cd14460279935266435bb958584 100644 (file)
@@ -473,7 +473,7 @@ set g_botclip_collisions 1 "0 = disable collision testing against botclips, migh
 set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
 
 set g_spawn_alloweffects 1 "allow clients to enable spawn point and event effects such as particles and sounds, see cl_spawn_ cvars for more info"
-set g_spawn_furthest 0.5 "this amount of the spawns shall be far away from any players"
+set g_spawn_furthest 1.0 "this amount of the spawns shall be far away from any players"
 set g_spawn_useallspawns 0 "use all spawns, e.g. also team spawns in non-teamplay, and all spawns, even enemy spawns, in teamplay"
 // respawn delay
 set g_respawn_delay_small 2 "small game number of seconds you have to wait before you can respawn again"
diff --git a/gfx/crosshair29.tga b/gfx/crosshair29.tga
deleted file mode 100644 (file)
index c103751..0000000
Binary files a/gfx/crosshair29.tga and /dev/null differ
diff --git a/gfx/crosshair30.tga b/gfx/crosshair30.tga
deleted file mode 100644 (file)
index 093bff2..0000000
Binary files a/gfx/crosshair30.tga and /dev/null differ
index c7d59e3871baef29f05006690226656a25bd6365..d9779a13924b864652a915db624859bb178c1871 100644 (file)
Binary files a/gfx/crosshair31.tga and b/gfx/crosshair31.tga differ
index 0dae288c7a32192a2318b370e6738014fc5897dc..c50055477b1c217031b553f18d554605dfad374d 100644 (file)
Binary files a/gfx/crosshair32.tga and b/gfx/crosshair32.tga differ
index b3cc2359750da66867591c16715aa46eebc25d98..39843b41694de4cbaaa63e5e12fb2e8f6a83ca45 100644 (file)
Binary files a/gfx/crosshair33.tga and b/gfx/crosshair33.tga differ
index 9a2257b6297e30f2e08cafaabd8e01ba64e6d9c5..b8d74789db81ca91f2505506bec6b1f0e5cce6d7 100644 (file)
Binary files a/gfx/crosshair34.tga and b/gfx/crosshair34.tga differ
index aaa8c851c0548befcc4d4b09ccc8b7f53b29dccf..c88e5609228c46bd43356e44a73ec4a35ff56286 100644 (file)
Binary files a/gfx/crosshair35.tga and b/gfx/crosshair35.tga differ
index 87f01f262a2cad8d9c11f8b103adc0cc6fef58ae..dae534fa158740462f144c981c7e888be782166f 100644 (file)
Binary files a/gfx/crosshair36.tga and b/gfx/crosshair36.tga differ
index 50ae94bc97bb24979c3f98be1b18e1906256a7d2..06eb4fc700689e6ace8397047d684acef4c52fa5 100644 (file)
Binary files a/gfx/crosshair37.tga and b/gfx/crosshair37.tga differ
index 08e3436c2661ee773da7d0f18fa86b2f0437a431..68d2b54fd0e7cabd6f10fab73faa8b896484eeb8 100644 (file)
Binary files a/gfx/crosshair38.tga and b/gfx/crosshair38.tga differ
index 6a90b620c7c708d8f2563a9f4ba29da8fe547a65..ff1f4fb8b4037660430d71035f91d19e229a1151 100644 (file)
Binary files a/gfx/crosshair39.tga and b/gfx/crosshair39.tga differ
index d15801cf989ef2120d29e4f5b25b009e2cfdffcf..96e11b04363e5908578ae7b3ccb6c2080e86e609 100644 (file)
Binary files a/gfx/crosshair40.tga and b/gfx/crosshair40.tga differ
index 5e11a3c4f585870828bb3b466d32259c50441989..0b610b270d8517e1225af2f14b8c4c6afea5faa3 100644 (file)
Binary files a/gfx/crosshair41.tga and b/gfx/crosshair41.tga differ
index a78503adcdbdd538b9473ff9088e856df3a722af..9401c6a80d76305b284ffabc398814ad4bb4c096 100644 (file)
Binary files a/gfx/crosshair42.tga and b/gfx/crosshair42.tga differ
diff --git a/gfx/crosshair43.tga b/gfx/crosshair43.tga
new file mode 100644 (file)
index 0000000..183d257
Binary files /dev/null and b/gfx/crosshair43.tga differ
diff --git a/gfx/crosshair44.tga b/gfx/crosshair44.tga
new file mode 100644 (file)
index 0000000..83716cf
Binary files /dev/null and b/gfx/crosshair44.tga differ
diff --git a/gfx/crosshair45.tga b/gfx/crosshair45.tga
new file mode 100644 (file)
index 0000000..4142558
Binary files /dev/null and b/gfx/crosshair45.tga differ
diff --git a/gfx/crosshair46.tga b/gfx/crosshair46.tga
new file mode 100644 (file)
index 0000000..34f9ffd
Binary files /dev/null and b/gfx/crosshair46.tga differ
diff --git a/gfx/crosshair47.tga b/gfx/crosshair47.tga
new file mode 100644 (file)
index 0000000..2221887
Binary files /dev/null and b/gfx/crosshair47.tga differ
diff --git a/gfx/crosshair48.tga b/gfx/crosshair48.tga
new file mode 100644 (file)
index 0000000..31d58db
Binary files /dev/null and b/gfx/crosshair48.tga differ
diff --git a/gfx/crosshair49.tga b/gfx/crosshair49.tga
new file mode 100644 (file)
index 0000000..ee6b145
Binary files /dev/null and b/gfx/crosshair49.tga differ
diff --git a/gfx/crosshair50.tga b/gfx/crosshair50.tga
new file mode 100644 (file)
index 0000000..0785a4d
Binary files /dev/null and b/gfx/crosshair50.tga differ
diff --git a/gfx/crosshair51.tga b/gfx/crosshair51.tga
new file mode 100644 (file)
index 0000000..7da16bc
Binary files /dev/null and b/gfx/crosshair51.tga differ
diff --git a/gfx/crosshair52.tga b/gfx/crosshair52.tga
new file mode 100644 (file)
index 0000000..9449478
Binary files /dev/null and b/gfx/crosshair52.tga differ
diff --git a/gfx/crosshair53.tga b/gfx/crosshair53.tga
new file mode 100644 (file)
index 0000000..eb74110
Binary files /dev/null and b/gfx/crosshair53.tga differ
diff --git a/gfx/crosshair54.tga b/gfx/crosshair54.tga
new file mode 100644 (file)
index 0000000..46d0464
Binary files /dev/null and b/gfx/crosshair54.tga differ
diff --git a/gfx/crosshair55.tga b/gfx/crosshair55.tga
new file mode 100644 (file)
index 0000000..adf1950
Binary files /dev/null and b/gfx/crosshair55.tga differ
diff --git a/gfx/crosshair56.tga b/gfx/crosshair56.tga
new file mode 100644 (file)
index 0000000..61adf9a
Binary files /dev/null and b/gfx/crosshair56.tga differ
diff --git a/gfx/crosshair57.tga b/gfx/crosshair57.tga
new file mode 100644 (file)
index 0000000..d0d9220
Binary files /dev/null and b/gfx/crosshair57.tga differ
diff --git a/gfx/crosshair58.tga b/gfx/crosshair58.tga
new file mode 100644 (file)
index 0000000..0bdb7f9
Binary files /dev/null and b/gfx/crosshair58.tga differ
diff --git a/gfx/crosshair59.tga b/gfx/crosshair59.tga
new file mode 100644 (file)
index 0000000..8e48aa2
Binary files /dev/null and b/gfx/crosshair59.tga differ
diff --git a/gfx/crosshair60.tga b/gfx/crosshair60.tga
new file mode 100644 (file)
index 0000000..c03e19d
Binary files /dev/null and b/gfx/crosshair60.tga differ
diff --git a/gfx/crosshair61.tga b/gfx/crosshair61.tga
new file mode 100644 (file)
index 0000000..507853f
Binary files /dev/null and b/gfx/crosshair61.tga differ
diff --git a/gfx/crosshair62.tga b/gfx/crosshair62.tga
new file mode 100644 (file)
index 0000000..54031b1
Binary files /dev/null and b/gfx/crosshair62.tga differ
diff --git a/gfx/crosshair63.tga b/gfx/crosshair63.tga
new file mode 100644 (file)
index 0000000..1aa5d55
Binary files /dev/null and b/gfx/crosshair63.tga differ
diff --git a/gfx/crosshair64.tga b/gfx/crosshair64.tga
new file mode 100644 (file)
index 0000000..06893f8
Binary files /dev/null and b/gfx/crosshair64.tga differ
diff --git a/gfx/crosshair65.tga b/gfx/crosshair65.tga
new file mode 100644 (file)
index 0000000..ebf77c3
Binary files /dev/null and b/gfx/crosshair65.tga differ
diff --git a/gfx/crosshair66.tga b/gfx/crosshair66.tga
new file mode 100644 (file)
index 0000000..ccba58d
Binary files /dev/null and b/gfx/crosshair66.tga differ
diff --git a/gfx/crosshaircalibrate.tga b/gfx/crosshaircalibrate.tga
new file mode 100644 (file)
index 0000000..3abd29e
Binary files /dev/null and b/gfx/crosshaircalibrate.tga differ
index 143a372f8c4ea9dec113759d80f93147d577f518..eef0af18d7f3e2b791faf141b129c5e01a83bff2 100644 (file)
Binary files a/gfx/crosshairdot.tga and b/gfx/crosshairdot.tga differ
diff --git a/gfx/crosshairmoustache.tga b/gfx/crosshairmoustache.tga
new file mode 100644 (file)
index 0000000..0d2129f
Binary files /dev/null and b/gfx/crosshairmoustache.tga differ
index 6386052d5ebd1a2dd98f5e112528564eecd20a6c..fcd0337ce9e913cd773bf92fb4efb2b6dd7b4b91 100644 (file)
Binary files a/gfx/crosshairtuba.tga and b/gfx/crosshairtuba.tga differ
index be5af23f9c1ad9f6e2950369c28f5275abab9447..a803d8411011cb7e52f737bd6b0553eaa6cee958 100644 (file)
@@ -43,7 +43,7 @@ set g_overkill_100h_anyway 1
 set g_overkill_powerups_replace 1
 set g_overkill_superguns_respawn_time 20
 
-set g_overkill_ammo_charge 1
+set g_overkill_ammo_charge 0
 set g_overkill_ammo_charge_notice 1
 set g_overkill_ammo_charge_limit 1
 set g_overkill_ammo_charge_rate 0.5
index 6c14fc3a2bc5c7b4725c759a2cd3f282f0cf2772..6068a799f752892a2d1dc8f86b7d412537c0644c 100644 (file)
@@ -22,7 +22,7 @@ void Casing_Draw()
 {
        if(self.move_flags & FL_ONGROUND)
        {
-               self.move_angles.x = 0;
+               self.move_angles_x = 0;
                self.move_angles_z = 0;
                self.flags &= ~FL_ONGROUND;
        }
index e33b9b0203705e87c0895d687e609dec265492ba..105cce5f2ea850f6cc95fbc25283b304e726f325 100644 (file)
@@ -140,6 +140,12 @@ vector HUD_Get_Num_Color (float x, float maxvalue)
        return color;
 }
 
+float HUD_GetRowCount(float item_count, vector size, float item_aspect)
+{
+       float aspect = size_y / size_x;
+       return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
+}
+
 float stringwidth_colors(string s, vector theSize)
 {
        return stringwidth(s, true, theSize);
@@ -424,16 +430,13 @@ void HUD_Weapons(void)
        float screen_ar;
        vector center = '0 0 0';
        float weapon_count, weapon_id;
-       float row, column, rows = 0, columns = 0;
+       float row, column, rows = 0, columns;
        float aspect = autocvar_hud_panel_weapons_aspect;
 
-       float panel_weapon_accuracy;
-
        float timeout = autocvar_hud_panel_weapons_timeout;
        float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
        float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
 
-       float ammo_full;
        vector barsize = '0 0 0', baroffset = '0 0 0';
        vector ammo_color = '1 0 1';
        float ammo_alpha = 1;
@@ -497,15 +500,18 @@ void HUD_Weapons(void)
        if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
                complain_weapon = 0;
 
+       if(autocvar__hud_configure)
+       {
+               if(!weapons_stat)
+                       for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
+                               weapons_stat |= WepSet_FromWeapon(i);
+       }
+
        // determine which weapons are going to be shown
        if (autocvar_hud_panel_weapons_onlyowned)
        {
                if(autocvar__hud_configure)
                {
-                       if (!weapons_stat)
-                               for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
-                                       weapons_stat |= WepSet_FromWeapon(i);
-
                        if(menu_enabled != 2)
                                HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
                }
@@ -513,13 +519,9 @@ void HUD_Weapons(void)
                // do we own this weapon?
                weapon_count = 0;
                for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-                       if(weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon))
+                       if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
                                ++weapon_count;
 
-               // add it anyway if weaponcomplain is shown
-               if(complain_weapon)
-                       ++weapon_count;
-
                // might as well commit suicide now, no reason to live ;)
                if (weapon_count == 0)
                {
@@ -527,41 +529,58 @@ void HUD_Weapons(void)
                        return;
                }
 
-               vector max_panel_size = panel_size - '2 2 0' * panel_bg_padding;
+               vector old_panel_size = panel_size;
+               vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
 
-               // calculate distribution and size of table cells
-               if(max_panel_size.x > max_panel_size.y)
-               {
-                       while(weapon_count > columns * rows)
-                       {
-                               ++rows;
-                               columns = ceil(max_panel_size.x / (max_panel_size.y / rows * aspect));
-                       }
+               // get the all-weapons layout
+               rows = HUD_GetRowCount(WEP_COUNT, padded_panel_size, aspect);
+               columns = ceil(WEP_COUNT / rows);
+               weapon_size.x = padded_panel_size.x / columns;
+               weapon_size.y = padded_panel_size.y / rows;
 
-                       weapon_size.x = max_panel_size.x / columns;
-                       weapon_size.y = max_panel_size.y / rows;
+               // reduce rows and columns as needed
+               // NOTE: although weapons should aways look the same even if onlyowned is enabled,
+               // we enlarge them a bit when possible to better match the desired aspect ratio
+               if(padded_panel_size.y > padded_panel_size.x)
+               {
                        columns = ceil(weapon_count / rows);
+                       rows = ceil(weapon_count / columns);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
                }
                else
                {
-                       while(weapon_count > columns * rows)
-                       {
-                               ++columns;
-                               rows = ceil(max_panel_size.y / (max_panel_size.x / columns / aspect));
-                       }
-
-                       weapon_size.x = max_panel_size.x / columns;
-                       weapon_size.y = max_panel_size.y / rows;
                        rows = ceil(weapon_count / columns);
+                       columns = ceil(weapon_count / rows);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
                }
 
                // reduce size of the panel
                panel_size.x = columns * weapon_size.x;
                panel_size.y = rows * weapon_size.y;
-               panel_pos.x += (max_panel_size.x - panel_size.x) / 2;
-               panel_pos.y += (max_panel_size.y - panel_size.y) / 2;
-
                panel_size += '2 2 0' * panel_bg_padding;
+
+               // center the resized panel, or snap it to the screen edge when close enough
+               if(panel_pos.x > vid_conwidth * 0.001)
+               {
+                       if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
+                               panel_pos.x += old_panel_size.x - panel_size.x;
+                       else
+                               panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+               }
+               else if(old_panel_size.x > vid_conwidth * 0.999)
+                       panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+
+               if(panel_pos.y > vid_conheight * 0.001)
+               {
+                       if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
+                               panel_pos.y += old_panel_size.y - panel_size.y;
+                       else
+                               panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
+               }
+               else if(old_panel_size.y > vid_conheight * 0.999)
+                       panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
        }
        else
                weapon_count = WEP_COUNT;
@@ -672,8 +691,7 @@ void HUD_Weapons(void)
 
        if(!rows) // if rows is > 0 onlyowned code has already updated these vars
        {
-               rows = panel_size.y/panel_size.x;
-               rows = bound(1, floor((sqrt(4 * aspect * rows * weapon_count + rows * rows) + rows + 0.5) / 2), weapon_count);
+               rows = HUD_GetRowCount(weapon_count, panel_size, aspect);
                columns = ceil(weapon_count/rows);
                weapon_size = eX * panel_size.x*(1/columns) + eY * panel_size.y*(1/rows);
        }
@@ -729,7 +747,7 @@ void HUD_Weapons(void)
                // draw the weapon accuracy
                if(autocvar_hud_panel_weapons_accuracy)
                {
-                       panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
+                       float panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
                        if(panel_weapon_accuracy >= 0)
                        {
                                color = Accuracy_GetColor(panel_weapon_accuracy);
@@ -765,6 +783,7 @@ void HUD_Weapons(void)
                        // draw ammo status bar
                        if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
                        {
+                               float ammo_full;
                                a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
 
                                if(a > 0)
@@ -1015,15 +1034,10 @@ void HUD_Ammo(void)
        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
-
+       rows = HUD_GetRowCount(total_ammo_count, mySize, 3);
        columns = ceil((total_ammo_count)/rows);
-
        ammo_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
 
-
        vector offset = '0 0 0'; // fteqcc sucks
        float newSize;
        if(ammo_size.x/ammo_size.y > 3)
@@ -2309,12 +2323,8 @@ void HUD_Score(void)
                }
                if(spectatee_status == -1)
                {
-                       rows = mySize.y/mySize.x;
-                       rows = bound(1, floor((sqrt(4 * (3/1) * rows * team_count + rows * rows) + rows + 0.5) / 2), team_count);
-                       //                               ^^^ ammo item aspect goes here
-
+                       rows = HUD_GetRowCount(team_count, mySize, 3);
                        columns = ceil(team_count/rows);
-
                        score_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
 
                        float newSize;
@@ -2742,9 +2752,8 @@ void HUD_Mod_CA(vector myPos, vector mySize)
        else //if(gametype == MAPINFO_TYPE_FREEZETAG)
                layout = autocvar_hud_panel_modicons_freezetag_layout;
        float rows, columns, aspect_ratio;
-       rows = mySize.y/mySize.x;
        aspect_ratio = (layout) ? 2 : 1;
-       rows = bound(1, floor((sqrt((4 * aspect_ratio * team_count + rows) * rows) + rows + 0.5) / 2), team_count);
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
        columns = ceil(team_count/rows);
 
        int i;
@@ -3338,9 +3347,8 @@ void HUD_Mod_Dom(vector myPos, vector mySize)
 
        int layout = autocvar_hud_panel_modicons_dom_layout;
        float rows, columns, aspect_ratio;
-       rows = mySize.y/mySize.x;
        aspect_ratio = (layout) ? 3 : 1;
-       rows = bound(1, floor((sqrt((4 * aspect_ratio * team_count + rows) * rows) + rows + 0.5) / 2), team_count);
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
        columns = ceil(team_count/rows);
 
        int i;
index 91b8bca8f11525be871aa6b59f4f1a25184dc4ca..a74c6683a26824b0d9ac091e48012d6fb0258ab1 100644 (file)
@@ -87,16 +87,16 @@ void Ent_Laser()
 
        if(f & 1)
        {
-               self.origin.x = ReadCoord();
-               self.origin.y = ReadCoord();
-               self.origin.z = ReadCoord();
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
                setorigin(self, self.origin);
        }
        if(f & 8)
        {
-               self.colormod.x = ReadByte() / 255.0;
-               self.colormod.y = ReadByte() / 255.0;
-               self.colormod.z = ReadByte() / 255.0;
+               self.colormod_x = ReadByte() / 255.0;
+               self.colormod_y = ReadByte() / 255.0;
+               self.colormod_z = ReadByte() / 255.0;
                if(f & 0x40)
                        self.alpha = ReadByte() / 255.0;
                else
@@ -117,14 +117,14 @@ void Ent_Laser()
        {
                if(f & 0x80)
                {
-                       self.velocity.x = ReadCoord();
-                       self.velocity.y = ReadCoord();
-                       self.velocity.z = ReadCoord();
+                       self.velocity_x = ReadCoord();
+                       self.velocity_y = ReadCoord();
+                       self.velocity_z = ReadCoord();
                }
                else
                {
-                       self.angles.x = ReadAngle();
-                       self.angles.y = ReadAngle();
+                       self.angles_x = ReadAngle();
+                       self.angles_y = ReadAngle();
                }
        }
        if(f & 4)
index e1b469734207b091b1ca1e0e0187d8f3723bc6b2..bd6d82f806e7ad38a74808f12af71d4e14807e09 100644 (file)
@@ -1,9 +1,7 @@
 ../../csprogs.dat
 
 ../common/util-pre.qh
-sys-pre.qh
 ../dpdefs/csprogsdefs.qh
-sys-post.qh
 
 announcer.qc
 bgmscript.qc
diff --git a/qcsrc/client/sys-post.qh b/qcsrc/client/sys-post.qh
deleted file mode 100644 (file)
index 5dc83ef..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef SYS_POST_H
-#define SYS_POST_H
-
-#pragma noref 0
-
-#undef ATTEN_NORM
-#endif
diff --git a/qcsrc/client/sys-pre.qh b/qcsrc/client/sys-pre.qh
deleted file mode 100644 (file)
index 9764040..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SYS_PRE_H
-#define SYS_PRE_H
-
-#define ATTEN_NORM builtin_ATTEN_NORM
-
-#pragma noref 1
-
-#endif
index dec00043f9baf0300382d7867f0476a15ebf28c6..cd518e091d3c2ecdd3677aaf7c2ca50a5f6217aa 100644 (file)
@@ -1,98 +1,94 @@
 #include "tuba.qh"
 
-void tubasound(entity e, float restart)
+#define TUBA_STARTNOTE(i, n) strcat("weapons/tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n), ".wav")
+
+const int TUBA_MIN = -18;
+const int TUBA_MAX = 27;
+const int TUBA_INSTRUMENTS = 3;
+
+.int note;
+.bool tuba_attenuate;
+.float tuba_volume;
+.float tuba_volume_initial;
+.int tuba_instrument;
+
+int Tuba_PitchStep;
+
+void tubasound(entity e, bool restart)
 {
-       string snd1;
-
-       snd1 = string_null;
-
-       if(Tuba_PitchStep)
-       {
-               string snd2;
-               float f1, f2;
-               float p1, p2;
-               float m;
-
-               f1 = 1;
-               p1 = 1;
-               snd2 = string_null;
-               f2 = 0;
-               p2 = 1;
-
-               m = e.note % Tuba_PitchStep;
-               if(m)
-               {
-                       if(e.note - m < TUBA_MIN)
-                       {
-                               if(restart)
+       string snd1 = string_null;
+       if (Tuba_PitchStep) {
+               float vol1 = 1;
+               float speed1 = 1;
+               string snd2 = string_null;
+               float vol2 = 0;
+               float speed2 = 1;
+
+               int m = pymod(e.note, Tuba_PitchStep);
+               if (m) {
+                       if (e.note - m < TUBA_MIN) {
+                               if (restart) {
                                        snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m + Tuba_PitchStep);
-                               p1 = pow(2.0, (m - Tuba_PitchStep) / 12.0);
-                       }
-                       else if(e.note - m + Tuba_PitchStep > TUBA_MAX)
-                       {
-                               if(restart)
+                               }
+                               speed1 = pow(2.0, (m - Tuba_PitchStep) / 12.0);
+                       } else if (e.note - m + Tuba_PitchStep > TUBA_MAX) {
+                               if (restart) {
                                        snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m);
-                               p1 = pow(2.0, m / 12.0);
-                       }
-                       else
-                       {
-                               if(restart)
+                               }
+                               speed1 = pow(2.0, m / 12.0);
+                       } else {
+                               if (restart) {
                                        snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m);
-                               f1 = cos(M_PI_2 * m / Tuba_PitchStep);
-                               p1 = pow(2.0, m / 12.0);
-                               if(restart)
+                               }
+                               vol1 = cos(M_PI_2 * m / Tuba_PitchStep);
+                               speed1 = pow(2.0, m / 12.0);
+                               if (restart) {
                                        snd2 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m + Tuba_PitchStep);
-                               f2 = sin(M_PI_2 * m / Tuba_PitchStep);
-                               p2 = pow(2.0, (m - Tuba_PitchStep) / 12.0);
+                               }
+                               vol2 = sin(M_PI_2 * m / Tuba_PitchStep);
+                               speed2 = pow(2.0, (m - Tuba_PitchStep) / 12.0);
                        }
-               }
-               else
-               {
-                       if(restart)
-                               snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
+               } else if (restart) {
+                       snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
                }
 
-               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_SINGLE, snd2, e.cnt * f2, e.attenuate * autocvar_g_balance_tuba_attenuation, 100 * p2, 0);
-       }
-       else
-       {
-               if(restart)
+               sound7(e, CH_TUBA_SINGLE, snd1, e.tuba_volume * vol1, e.tuba_attenuate * autocvar_g_balance_tuba_attenuation, 100 * speed1, 0);
+               if (vol2) {
+                       sound7(e.enemy, CH_TUBA_SINGLE, snd2, e.tuba_volume * vol2, e.tuba_attenuate * autocvar_g_balance_tuba_attenuation, 100 * speed2, 0);
+               }
+       } else {
+               if (restart) {
                        snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
-               sound(e, CH_TUBA_SINGLE, snd1, e.cnt, e.attenuate * autocvar_g_balance_tuba_attenuation);
+               }
+               sound(e, CH_TUBA_SINGLE, snd1, e.tuba_volume, e.tuba_attenuate * autocvar_g_balance_tuba_attenuation);
        }
 }
 
 void Ent_TubaNote_Think()
 {
-       float f;
-       f = autocvar_g_balance_tuba_fadetime;
-       if(f > 0)
-               self.cnt -= frametime * self.count / f;
-       else
-               self.cnt = 0;
+       float f = autocvar_g_balance_tuba_fadetime;
+       if (f > 0) {
+               self.tuba_volume -= frametime * self.tuba_volume_initial / f;
+       } else {
+               self.tuba_volume = 0;
+       }
        self.nextthink = time;
-       if(self.cnt <= 0)
-       {
+       if (self.tuba_volume <= 0) {
                sound(self, CH_TUBA_SINGLE, "misc/null.wav", 0, 0);
-               if(self.enemy)
-               {
+               if (self.enemy) {
                        sound(self.enemy, CH_TUBA_SINGLE, "misc/null.wav", 0, 0);
                        remove(self.enemy);
                }
                remove(self);
-       }
-       else
-       {
+       } else {
                tubasound(self, 0);
        }
 }
 
 void Ent_TubaNote_UpdateSound()
 {
-       self.enemy.cnt = bound(0, VOL_BASE * autocvar_g_balance_tuba_volume, 1);
-       self.enemy.count = self.enemy.cnt;
+       self.enemy.tuba_volume = bound(0, VOL_BASE * autocvar_g_balance_tuba_volume, 1);
+       self.enemy.tuba_volume_initial = self.enemy.tuba_volume;
        self.enemy.note = self.note;
        self.enemy.tuba_instrument = self.tuba_instrument;
        tubasound(self.enemy, 1);
@@ -104,57 +100,47 @@ void Ent_TubaNote_StopSound()
        self.enemy = world;
 }
 
-void Ent_TubaNote(float bIsNew)
+void Ent_TubaNote(bool isNew)
 {
-    int f, n, i;
-       float att, upd;
-       f = ReadByte();
-
-       upd = 0;
-
-       if(f & 1)
-       {
-               n = ReadChar();
-               i = ReadByte();
-               att = (i & 1);
-               i = floor(i / 2);
-
-               if(n != self.note || i != self.tuba_instrument || bIsNew)
-               {
-                       if(self.enemy)
+       bool upd = false;
+       int f = ReadByte();
+       if (f & 1) {
+               int n = ReadChar();
+               int i = ReadByte();
+               bool att = (i & 1);
+               i >>= 1;
+
+               if (self.enemy) {
+                       if (n != self.note || i != self.tuba_instrument || isNew) {
                                Ent_TubaNote_StopSound();
-               }
-
-               if(!self.enemy)
-               {
+                       }
+               } else {
                        self.enemy = spawn();
                        self.enemy.classname = "tuba_note";
-                       if(Tuba_PitchStep)
-                       {
+                       if (Tuba_PitchStep) {
                                self.enemy.enemy = spawn();
                                self.enemy.enemy.classname = "tuba_note_2";
                        }
-                       bIsNew = true;
+                       isNew = true;
                }
 
-               self.enemy.attenuate = att;
+               self.enemy.tuba_attenuate = att;
 
-               if(bIsNew)
-               {
+               if (isNew) {
                        self.note = n;
                        self.tuba_instrument = i;
-                       upd = 1;
+                       upd = true;
                }
        }
 
-       if(f & 2)
-       {
+       if (f & 2) {
                self.enemy.origin_x = ReadCoord();
                self.enemy.origin_y = ReadCoord();
                self.enemy.origin_z = ReadCoord();
                setorigin(self.enemy, self.enemy.origin);
-               if(self.enemy.enemy)
+               if (self.enemy.enemy) {
                        setorigin(self.enemy.enemy, self.enemy.origin);
+               }
        }
 
        self.think = Ent_TubaNote_StopSound;
@@ -162,29 +148,25 @@ void Ent_TubaNote(float bIsNew)
        self.enemy.think = Ent_TubaNote_Think;
        self.enemy.nextthink = time + 10;
 
-       if(upd)
+       if (upd) {
                Ent_TubaNote_UpdateSound();
+       }
 }
 
 void Tuba_Precache()
 {
-       float i;
-    int n;
        Tuba_PitchStep = autocvar_g_balance_tuba_pitchstep;
-       if(Tuba_PitchStep)
-       {
-               if(!checkextension("DP_SND_SOUND7_WIP2") && !checkextension("DP_SND_SOUND7"))
-               {
+       if (Tuba_PitchStep) {
+               if (!checkextension("DP_SND_SOUND7_WIP2") && !checkextension("DP_SND_SOUND7")) {
                        print("^1NOTE:^7 requested pitch shifting, but not supported by this engine build\n");
                        Tuba_PitchStep = 0;
                }
        }
-       for(n = TUBA_MIN; n <= TUBA_MAX; ++n)
-       {
-               if(!Tuba_PitchStep || ((n % Tuba_PitchStep) == 0))
-               {
-                       for(i = 0; i < TUBA_INSTRUMENTS; ++i)
+       for (int n = TUBA_MIN; n <= TUBA_MAX; ++n) {
+               if (!Tuba_PitchStep || pymod(n, Tuba_PitchStep) == 0) {
+                       for (int i = 0; i < TUBA_INSTRUMENTS; ++i) {
                                precache_sound(TUBA_STARTNOTE(i, n));
+                       }
                }
        }
 }
index 81517b4e41bd7a452e0bb0360215ce17f41fdf9f..bdc1386eab666e352dd4d1ed9413a5d5fe237de3 100644 (file)
@@ -1,28 +1,5 @@
 #ifndef TUBA_H
 #define TUBA_H
-
-const float TUBA_MIN = -18;
-const float TUBA_MAX =  27;
-const float TUBA_INSTRUMENTS = 3;
-
-#define TUBA_STARTNOTE(i,n) strcat("weapons/tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n), ".wav")
-.int note; // note
-.float attenuate; // if set, attenuate it
-.float cnt; // current volume
-.float count; // initial volume
-.float tuba_instrument;
-
-int Tuba_PitchStep;
-
-void tubasound(entity e, float restart);
-
-void Ent_TubaNote_Think();
-
-void Ent_TubaNote_UpdateSound();
-
-void Ent_TubaNote_StopSound();
-
-void Ent_TubaNote(float bIsNew);
-
+void Ent_TubaNote(bool isNew);
 void Tuba_Precache();
 #endif
index f3d4eb4a17061434ebc370da65d28bb7430d467b..3fcd2ff0e9a0965ec08e682dca82942a77200a83 100644 (file)
@@ -65,7 +65,7 @@
 #define CSQCPLAYER_HOOK_POSTCAMERASETUP
 
 // force updates of player entities that often even if unchanged
-const float CSQCPLAYER_FORCE_UPDATES = 0.25;
+#define CSQCPLAYER_FORCE_UPDATES 0.25
 
 // mod must define:
 //vector PL_MIN  = ...;
index 366f35ed6eddde8c36e5fb5d23b009d5a5897c0f..c3f15d1937e4963b06a1f6343c0d896c6ac44ce4 100644 (file)
@@ -1287,11 +1287,11 @@ float MapInfo_CheckMap(string s) // returns 0 if the map can't be played with th
        return r;
 }
 
-void MapInfo_SwitchGameType(float t)
+void MapInfo_SwitchGameType(int t)
 {
-       entity e;
-       for(e = MapInfo_Type_first; e; e = e.enemy)
+       for (entity e = MapInfo_Type_first; e; e = e.enemy) {
                cvar_set(e.netname, (t == e.items) ? "1" : "0");
+       }
 }
 
 void MapInfo_LoadMap(string s, float reinit)
index 6083350fa92028cf2be820c251875847a0927e9e..54255ec8d2aa153abfb6da7242d08b3635c40423 100644 (file)
@@ -152,7 +152,7 @@ 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);
+void MapInfo_SwitchGameType(int t);
 
 // to be called from worldspawn to set up cvars
 void MapInfo_LoadMapSettings(string s);
index 1537c75fb5a16eef9112909da8349985f774324d..ed4ebcf0615d26dfa52ea907ea96a190b5f6a6f5 100644 (file)
     #define bool float
 
     // Boolean Constants
-    const bool true    = 1;
-    const bool false   = 0;
+    const int true     = 1;
+    const int false = 0;
 #endif
+
+// Transitional aliases
+[[deprecated("use true")]] [[alias("true")]] const bool TRUE;
+[[deprecated("use false")]] [[alias("false")]] const bool FALSE;
+
 #endif
index 64813f2f4506063f3e188aa315dd31f0b26b5db3..99fecda0bbfc2855600c02a3ec2629845511f730 100644 (file)
@@ -1,9 +1,10 @@
+#include "util.qh"
+
 #if defined(CSQC)
        #include "../dpdefs/csprogsdefs.qh"
     #include "../client/defs.qh"
     #include "constants.qh"
     #include "../warpzonelib/mathlib.qh"
-    #include "util.qh"
     #include "mapinfo.qh"
     #include "notifications.qh"
     #include "deathtypes.qh"
@@ -13,7 +14,6 @@
     #include "../dpdefs/dpextensions.qh"
     #include "../warpzonelib/mathlib.qh"
     #include "constants.qh"
-    #include "util.qh"
     #include "../server/autocvars.qh"
     #include "../server/defs.qh"
     #include "notifications.qh"
index 7de776dda392be70013202a76b7607a5d64cce87..8eaff86e35241899d5a760600f858b451e1c11f6 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '1 0.5 0.5',
 /* modelname */ "laser",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshairlaser 0.4",
+/* crosshair */ "gfx/crosshairlaser 0.5",
 /* wepimg    */ "weaponlaser",
 /* refname   */ "blaster",
 /* wepname   */ _("Blaster")
index ee4878fd4b059c5d7d45d55339e950ca22d7bea7..21a86e7da0c33f7d901584c194b4575a450ca47e 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '1 0.5 1',
 /* modelname */ "crylink",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshaircrylink 0.4",
+/* crosshair */ "gfx/crosshaircrylink 0.5",
 /* wepimg    */ "weaponcrylink",
 /* refname   */ "crylink",
 /* wepname   */ _("Crylink")
index dd167aac23c7e0ec1afdb61eae174e6d35458184..9e5f98a492033c49f1121aa6f72ce30e0793a8b5 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '1 1 0',
 /* modelname */ "rl",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshairrocketlauncher 0.5875",
+/* crosshair */ "gfx/crosshairrocketlauncher 0.7",
 /* wepimg    */ "weaponrocketlauncher",
 /* refname   */ "devastator",
 /* wepname   */ _("Devastator")
index eadfa0b3b45f322e26132b2506bbea29715b7192..3f5e75159b5b8339490f0eb2c8aff57664e2fa65 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '0 0.5 1',
 /* modelname */ "electro",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshairelectro 0.5",
+/* crosshair */ "gfx/crosshairelectro 0.6",
 /* wepimg    */ "weaponelectro",
 /* refname   */ "electro",
 /* wepname   */ _("Electro")
index ccc87fdc72601598be2990578afc25e4ca6b0423..f20872f7045067fb300a1c24ffd6240a0af5e773 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '0.5 1 0',
 /* modelname */ "campingrifle",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshairrifle 0.5",
+/* crosshair */ "gfx/crosshairrifle 0.6",
 /* wepimg    */ "weaponrifle",
 /* refname   */ "rifle",
 /* wepname   */ _("Rifle")
index b073a31704e8ab51dc93788cc5b94578d01ac4b9..387dc32d82eb5c891bc40b3a8fbbdd6e6a70a50e 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '0.5 0.5 0',
 /* modelname */ "ok_rl",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshairrocketlauncher 0.5875",
+/* crosshair */ "gfx/crosshairrocketlauncher 0.7",
 /* wepimg    */ "weaponrpc",
 /* refname   */ "rpc",
 /* wepname      */ _("Rocket Propelled Chainsaw")
index 0e78dbae93f98336bc5131ad90f9ea219c12f784..14377edb8651489cc9901c1d26d7c3c54658d74a 100644 (file)
@@ -9,7 +9,7 @@ REGISTER_WEAPON(
 /* color     */ '0.5 1 1',
 /* modelname */ "minstanex",
 /* simplemdl */ "foobar",
-/* crosshair */ "gfx/crosshairminstanex 0.4",
+/* crosshair */ "gfx/crosshairminstanex 0.6",
 /* wepimg    */ "weaponminstanex",
 /* refname   */ "vaporizer",
 /* wepname   */ _("Vaporizer")
index e0869559be204d30b4dab4f4d03de7f938d292ce..55fcc0e14ffa597cbfaace6da0d52f09a4329f4d 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef WEAPONS_C
 #define WEAPONS_C
 
+#include "weapons.qh"
+
 #if defined(CSQC)
        #include "../../dpdefs/csprogsdefs.qh"
        #include "../../client/defs.qh"
@@ -12,7 +14,6 @@
        #include "../../warpzonelib/client.qh"
        #include "../util.qh"
        #include "../buffs.qh"
-       #include "weapons.qh"
        #include "../../client/autocvars.qh"
        #include "../deathtypes.qh"
        #include "../../csqcmodellib/interpolate.qh"
@@ -35,7 +36,6 @@
     #include "../buffs.qh"
     #include "../monsters/monsters.qh"
     #include "config.qh"
-    #include "weapons.qh"
     #include "../../server/weapons/csqcprojectile.qh"
     #include "../../server/weapons/tracing.qh"
     #include "../../server/t_items.qh"
index 73f1e790521ed71d50137c43a4e60515c46cb4b8..b30d7e94b0daca67ea8f251fb0d7e2c341369846 100644 (file)
@@ -18,7 +18,7 @@
 #define CSQCPLAYER_HOOK_POSTCAMERASETUP
 
 // force updates of player entities that often even if unchanged
-const float CSQCPLAYER_FORCE_UPDATES = 0.25;
+#define CSQCPLAYER_FORCE_UPDATES 0.25
 
 // mod must define:
 //vector PL_MIN  = ...;
index 1eddb129b717b7f17796955ccb4efdd475b87524..cd4f8d797669a1aa1174b124a9c8c6ce91a0c07d 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef CSPROGSDEFS_H
 #define CSPROGSDEFS_H
+
+#pragma noref 1
+
 /*
 ==============================================================================
 
@@ -1418,6 +1421,12 @@ void(float fh, entity e) writetofile = #606;
 float(string s) isfunction = #607;
 void(entity e, string s) parseentitydata = #608;
 
+//DP_COVERAGE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//function definitions:
+void coverage() = #642;  // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
+
 // assorted builtins
 //const int STAT_MOVEVARS_TICRATE              = 240;
 //const int STAT_MOVEVARS_TIMESCALE            = 241;
@@ -1445,4 +1454,7 @@ vector gettaginfo_forward;
 vector gettaginfo_right;
 vector gettaginfo_up;
 float checkpvs(vector viewpos, entity viewee) = #240;
+
+#pragma noref 0
+
 #endif
index 26d351a209b80518c6295cc41b2d3d33ddee60ad..109e9195bb03cda7212ef627a29fbe8cd5785e4c 100644 (file)
@@ -437,7 +437,7 @@ void(entity e, entity tagentity, string tagname) setattachment = #443; // attach
 //darkplaces implementation: Blub\0
 //cvar definitions:
 //   utf8_enable: enable utf8 encoding
-//description: utf8 characters are allowed inside cvars, protocol strings, files, progs strings, etc.,
+//description: utf8 characters are allowed inside cvars, protocol strings, files, progs strings, etc., 
 //and count as 1 char for string functions like strlen, substring, etc.
 // note: utf8_enable is run-time cvar, could be changed during execution
 // note: beware that str2chr() could return value bigger than 255 once utf8 is enabled
@@ -499,7 +499,7 @@ void(entity e, entity tagentity, string tagname) setattachment = #443; // attach
 // description: allows alternative 'static' lightstyle syntax : "=value"
 // examples: "=0.5", "=2.0", "=2.75"
 // could be used to control switchable lights or making styled lights with brightness > 2
-// Warning: this extension is experimental. It safely works in CSQC, but SVQC use is limited by the fact
+// Warning: this extension is experimental. It safely works in CSQC, but SVQC use is limited by the fact 
 // that other engines (which do not support this extension) could connect to a game and misunderstand this kind of lightstyle syntax
 
 //DP_LITSPRITES
@@ -1359,14 +1359,14 @@ float(string sample) soundlength = #534; // returns length of sound sample in se
 //syntax of .dpsubs files: each line in .dpsubs file defines 1 subtitle, there are three tokens:
 //   <start> <end> "string"
 //   start: subtitle start time in seconds
-//     end: subtitle time-to-show in seconds, if 0 - subtitle will be showed until next subtitle is started,
+//     end: subtitle time-to-show in seconds, if 0 - subtitle will be showed until next subtitle is started, 
 //          if below 0 - show until next subtitles minus this number of seconds
 //    text: subtitle text, color codes (Q3-style and ^xRGB) are allowed
 //example of subtitle file:
 //   3 0       "Vengeance! Vengeance for my eternity of suffering!"
 //   9 0       "Whelp! As if you knew what eternity was!"
 //   13        0       "Grovel before your true master."
-//   17        0       "Never!"
+//   17        0       "Never!" 
 //   18        7       "I'll hack you from crotch to gizzard and feed what's left of you to your brides..."
 
 //DP_SOLIDCORPSE
@@ -1733,11 +1733,11 @@ const float FORCETYPE_TORQUE = 3;
 .vector massofs;      // offsets a mass center out of object center, if not set a center of model bounds is used
 .float  friction;     // a friction of object, get multiplied by second objects's friction on contact
 .float  bouncefactor;
-.float  bouncestop;
+.float  bouncestop; 
 .float  jointtype;    // type of joint
 .float  forcetype;    // type of force
-.float  erp;          // error restitution parameter, makes ODE solver attempt to fix errors in contacts,
-                      // bringing together 2 joints or fixing object being stuch in other object,
+.float  erp;          // error restitution parameter, makes ODE solver attempt to fix errors in contacts, 
+                      // bringing together 2 joints or fixing object being stuch in other object, 
                                  // a value of 0.1 will fix slightly, a value of 1.0 attempts to fix whole error in one frame
                                  // use with care as high values makes system unstable and likely to explode
 //builtin definitions:
@@ -2536,7 +2536,11 @@ void(float pause) setpause = #531;
 //
 //Note: it is worth considering that network-related functions may be called during the pause (including customizeentityforclient for example), and it is also important to consider the continued use of the KRIMZON_SV_PARSECLIENTCOMMAND extension while paused (chatting players, etc), players may also join/leave during the pause.  In other words, the only things that are not called are think and other time-related functions.
 
-
+//DP_COVERAGE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//function definitions:
+void coverage() = #642;  // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
 
 
 // EXPERIMENTAL (not finalized) EXTENSIONS:
@@ -2545,9 +2549,10 @@ void(float pause) setpause = #531;
 //idea: divVerent
 //darkplaces implementation: divVerent
 //field definitions: (SVQC)
-.string crypto_keyfp; // fingerprint of CA key the player used to authenticate, or string_null if not verified
-.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player, or string_null if not verified
+.string crypto_keyfp; // fingerprint of CA key the player used to authenticate
+.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player
 .string crypto_idfp; // fingerprint of ID used by the player entity, or string_null if not identified
+.float crypto_idfp_signed; // set if the player's ID has been signed
 .string crypto_encryptmethod; // the string "AES128" if encrypting, and string_null if plaintext
 .string crypto_signmethod; // the string "HMAC-SHA256" if signing, and string_null if plaintext
 // there is no field crypto_myidfp, as that info contains no additional information the QC may have a use for
index d01371c4c6e58ccf177c69dc855b065f1b3f27b8..d7423083f8b43a2eb06a391e421e8df6fba65a0f 100644 (file)
 #ifndef KEYCODES_H
 #define KEYCODES_H
 
+#pragma noref 1
+
 ///////////////////////////
 // key constants
 
 //
 // these are the key numbers that should be passed to Key_Event
 //
-float K_TAB                    =       9;
-float K_ENTER          =       13;
-float K_ESCAPE         =       27;
-float K_SPACE          =       32;
+int K_TAB                      = 9;
+int K_ENTER                = 13;
+int K_ESCAPE           = 27;
+int K_SPACE                = 32;
 
 // normal keys should be passed as lowercased ascii
 
-float K_BACKSPACE      =       127;
-float K_UPARROW                =       128;
-float K_DOWNARROW      =       129;
-float K_LEFTARROW      =       130;
-float K_RIGHTARROW     =       131;
-
-float K_ALT            =       132;
-float K_CTRL   =       133;
-float K_SHIFT  =       134;
-
-float K_F1             =       135;
-float K_F2             =       136;
-float K_F3             =       137;
-float K_F4             =       138;
-float K_F5             =       139;
-float K_F6             =       140;
-float K_F7             =       141;
-float K_F8             =       142;
-float K_F9             =       143;
-float K_F10            =       144;
-float K_F11            =       145;
-float K_F12            =       146;
-
-float K_INS            =       147;
-float K_DEL            =       148;
-float K_PGDN   =       149;
-float K_PGUP   =       150;
-float K_HOME   =       151;
-float K_END            =       152;
-
-float K_NUMLOCK                = 154;
-float K_CAPSLOCK       = 155;
-float K_SCROLLLOCK     = 156;
-
-float K_KP_0   =       157;
-float K_KP_INS =       157; // same as K_KP_0
-float K_KP_1   =       158;
-float K_KP_END =       158; // same as K_KP_1
-float K_KP_2   =       159;
-float K_KP_DOWNARROW = 159; // same as K_KP_2
-float K_KP_3   =       160;
-float K_KP_PGDN = 160; // same as K_KP_3
-float K_KP_4   =       161;
-float K_KP_LEFTARROW = 161; // same as K_KP_4
-float K_KP_5   =       162;
-float K_KP_6   =       163;
-float K_KP_RIGHTARROW = 163; // same as K_KP_6
-float K_KP_7   =       164;
-float K_KP_HOME = 164; // same as K_KP_7
-float K_KP_8   =       165;
-float K_KP_UPARROW = 165; // same as K_KP_8
-float K_KP_9   = 166;
-float K_KP_PGUP = 166; // same as K_KP_9
-float K_KP_PERIOD = 167;
-float K_KP_DEL = 167; // same as K_KP_PERIOD
-float K_KP_DIVIDE = 168;
-float K_KP_SLASH = 168; // same as K_KP_DIVIDE
-float K_KP_MULTIPLY = 169;
-float K_KP_MINUS       = 170;
-float K_KP_PLUS                = 171;
-float K_KP_ENTER       = 172;
-float K_KP_EQUALS      = 173;
+int K_BACKSPACE            = 127;
+int K_UPARROW          = 128;
+int K_DOWNARROW            = 129;
+int K_LEFTARROW            = 130;
+int K_RIGHTARROW       = 131;
+
+int K_ALT                  = 132;
+int K_CTRL             = 133;
+int K_SHIFT            = 134;
+
+int K_F1                   = 135;
+int K_F2                   = 136;
+int K_F3                   = 137;
+int K_F4                   = 138;
+int K_F5                   = 139;
+int K_F6                   = 140;
+int K_F7                   = 141;
+int K_F8                   = 142;
+int K_F9                   = 143;
+int K_F10                  = 144;
+int K_F11                  = 145;
+int K_F12                  = 146;
+
+int K_INS                  = 147;
+int K_DEL                  = 148;
+int K_PGDN             = 149;
+int K_PGUP             = 150;
+int K_HOME             = 151;
+int K_END                  = 152;
+
+int K_NUMLOCK          = 154;
+int K_CAPSLOCK     = 155;
+int K_SCROLLLOCK       = 156;
+
+int K_KP_0             = 157;
+int K_KP_INS       = 157; // same as K_KP_0
+int K_KP_1             = 158;
+int K_KP_END       = 158; // same as K_KP_1
+int K_KP_2             = 159;
+int K_KP_DOWNARROW  = 159; // same as K_KP_2
+int K_KP_3             = 160;
+int K_KP_PGDN       = 160; // same as K_KP_3
+int K_KP_4             = 161;
+int K_KP_LEFTARROW  = 161; // same as K_KP_4
+int K_KP_5             = 162;
+int K_KP_6             = 163;
+int K_KP_RIGHTARROW = 163; // same as K_KP_6
+int K_KP_7             = 164;
+int K_KP_HOME       = 164; // same as K_KP_7
+int K_KP_8             = 165;
+int K_KP_UPARROW    = 165; // same as K_KP_8
+int K_KP_9             = 166;
+int K_KP_PGUP       = 166; // same as K_KP_9
+int K_KP_PERIOD     = 167;
+int K_KP_DEL        = 167; // same as K_KP_PERIOD
+int K_KP_DIVIDE     = 168;
+int K_KP_SLASH      = 168; // same as K_KP_DIVIDE
+int K_KP_MULTIPLY   = 169;
+int K_KP_MINUS     = 170;
+int K_KP_PLUS          = 171;
+int K_KP_ENTER     = 172;
+int K_KP_EQUALS            = 173;
 
 // mouse buttons generate virtual keys
-float K_PAUSE  =       153;
+int K_PAUSE            = 153;
 
 //
 // joystick buttons
 //
-float K_JOY1 = 768;
-float K_JOY2 = 769;
-float K_JOY3 = 770;
-float K_JOY4 = 771;
+int K_JOY1          = 768;
+int K_JOY2          = 769;
+int K_JOY3          = 770;
+int K_JOY4          = 771;
 
 //
 //
 // aux keys are for multi-buttoned joysticks to generate so they can use
 // the normal binding process
 //
-float K_AUX1   =       772;
-float K_AUX2   =       773;
-float K_AUX3   =       774;
-float K_AUX4   =       775;
-float K_AUX5   =       776;
-float K_AUX6   =       777;
-float K_AUX7   =       778;
-float K_AUX8   =       779;
-float K_AUX9   =       780;
-float K_AUX10  =       781;
-float K_AUX11  =       782;
-float K_AUX12  =       783;
-float K_AUX13  =       784;
-float K_AUX14  =       785;
-float K_AUX15  =       786;
-float K_AUX16  =       787;
-float K_AUX17  =       788;
-float K_AUX18  =       789;
-float K_AUX19  =       790;
-float K_AUX20  =       791;
-float K_AUX21  =       792;
-float K_AUX22  =       793;
-float K_AUX23  =       794;
-float K_AUX24  =       795;
-float K_AUX25  =       796;
-float K_AUX26  =       797;
-float K_AUX27  =       798;
-float K_AUX28  =       799;
-float K_AUX29  =       800;
-float K_AUX30  =       801;
-float K_AUX31  =       802;
-float K_AUX32  =       803;
+int K_AUX1             = 772;
+int K_AUX2             = 773;
+int K_AUX3             = 774;
+int K_AUX4             = 775;
+int K_AUX5             = 776;
+int K_AUX6             = 777;
+int K_AUX7             = 778;
+int K_AUX8             = 779;
+int K_AUX9             = 780;
+int K_AUX10            = 781;
+int K_AUX11            = 782;
+int K_AUX12            = 783;
+int K_AUX13            = 784;
+int K_AUX14            = 785;
+int K_AUX15            = 786;
+int K_AUX16            = 787;
+int K_AUX17            = 788;
+int K_AUX18            = 789;
+int K_AUX19            = 790;
+int K_AUX20            = 791;
+int K_AUX21            = 792;
+int K_AUX22            = 793;
+int K_AUX23            = 794;
+int K_AUX24            = 795;
+int K_AUX25            = 796;
+int K_AUX26            = 797;
+int K_AUX27            = 798;
+int K_AUX28            = 799;
+int K_AUX29            = 800;
+int K_AUX30            = 801;
+int K_AUX31            = 802;
+int K_AUX32            = 803;
 
 //
 // mouse buttons generate virtual keys
 //
-float K_MOUSE1         =       512;
-float K_MOUSE2         =       513;
-float K_MOUSE3         =       514;
-float K_MWHEELUP       =       515;
-float K_MWHEELDOWN     =       516;
-float K_MOUSE4         =       517;
-float K_MOUSE5         =       518;
-float K_MOUSE6         =       519;
-float K_MOUSE7         =       520;
-float K_MOUSE8         =       521;
-float K_MOUSE9         =       522;
-float K_MOUSE10                =       523;
-float K_MOUSE11                =       524;
-float K_MOUSE12                =       525;
-float K_MOUSE13                =       526;
-float K_MOUSE14                =       527;
-float K_MOUSE15                =       528;
-float K_MOUSE16                =       529;
+int K_MOUSE1           = 512;
+int K_MOUSE2           = 513;
+int K_MOUSE3           = 514;
+int K_MWHEELUP     = 515;
+int K_MWHEELDOWN       = 516;
+int K_MOUSE4           = 517;
+int K_MOUSE5           = 518;
+int K_MOUSE6           = 519;
+int K_MOUSE7           = 520;
+int K_MOUSE8           = 521;
+int K_MOUSE9           = 522;
+int K_MOUSE10          = 523;
+int K_MOUSE11          = 524;
+int K_MOUSE12          = 525;
+int K_MOUSE13          = 526;
+int K_MOUSE14          = 527;
+int K_MOUSE15          = 528;
+int K_MOUSE16          = 529;
+
+#pragma noref 0
+
 #endif
index be17852052256045cc65dd0cc490151416054314..853fa25f21cbd2be4bdb80f9fe3af24618911b79 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MENUDEFS_H
 #define MENUDEFS_H
 
+#pragma noref 1
+
 //////////////////////////////////////////////////////////
 // sys globals
 
@@ -295,7 +297,7 @@ float       drawstring(vector position, string text, vector scale, vector rgb, float a
 float  drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) = #467;
 
 vector drawcolorcodedstring2(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #467;
-
 float  drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456;
 
 float  drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457;
@@ -345,6 +347,7 @@ float(string key) stringtokeynum = #341;
 //field definitions: (MENUQC)
 string(string serveraddress) crypto_getkeyfp = #633; // retrieves the cached host key's CA fingerprint of a server given by IP address
 string(string serveraddress) crypto_getidfp = #634; // retrieves the cached host key fingerprint of a server given by IP address
+float(string serveraddress) crypto_getidstatus = #643; // retrieves the cached host key's key status. See below for CRYPTO_IDSTATUS_ defines.
 string(string serveraddress) crypto_getencryptlevel = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each
 string(float i) crypto_getmykeyfp = #636; // retrieves the CA key fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
 string(float i) crypto_getmyidfp = #637; // retrieves the ID fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
@@ -522,6 +525,12 @@ float FIELD_FUNCTION = 6;
 //getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned.
 //putentityfieldstring puts the data returned by getentityfieldstring back into the entity.
 
+//DP_COVERAGE
+//idea: divVerent
+//darkplaces implementation: divVerent
+//function definitions:
+void coverage() = #642;  // Reports a coverage event. The engine counts for each of the calls to this builtin whether it has been called.
+
 // assorted undocumented extensions
 string(string, float) netaddress_resolve = #625;
 string(string search, string replace, string subject) strreplace = #484;
@@ -566,4 +575,7 @@ string      getextresponse(void) = #624;
 const string cvar_string(string name) = #71;
 const string cvar_defstring(string name) = #89;
 float  stringwidth(string text, float handleColors, vector size) = #468;
+
+#pragma noref 0
+
 #endif
index bff21707906c9919927ce8557a5934aacbaa4bff..3ef656744568ad3b0ebfd25768e5acf3267fbfe5 100644 (file)
@@ -150,22 +150,11 @@ void ModalController_draw(entity me)
                if(e.ModalController_state)
                {
                        if(front)
-                       {
                                me.switchState(me, front, 2, 0);
-                               if(front.ModalController_factor < 1)
-                                       animating = 1;
-                       }
                        front = e;
                }
        if(front)
-       {
                me.switchState(me, front, 1, 0);
-               if(front.ModalController_factor < 1)
-                       animating = 1;
-       }
-
-       if(front && front.Container_alpha == front.ModalController_initialAlpha)
-               goto update_done; // update isn't needed, everything stay as is
 
        df = frametime * 3; // animation speed
 
@@ -209,6 +198,7 @@ void ModalController_draw(entity me)
                                me.setAlphaOf(me, e, e.Container_alpha  * prevFactor);
                        else
                        {
+                               animating = 1;
                                targetFactor = df / (1 - f + df);
 
                                if(e.ModalController_state == 1)
@@ -234,7 +224,6 @@ void ModalController_draw(entity me)
                        e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
                }
        }
-       :update_done
 
        if(animating || !me.focused)
                me.setFocus(me, NULL);
index e18aacd84fb867e1d324b57ed1244b8528130715..a1fb38b1a12bec97dcc2026da161c364a779563b 100644 (file)
@@ -1,10 +1,8 @@
 ../../menu.dat
 
 ../common/util-pre.qh
-sys-pre.qh
 ../dpdefs/menudefs.qh
 ../dpdefs/keycodes.qh
-sys-post.qh
 
 oo/interface.qh
        classes.qc
index 90988703e0e5f9fa491ef0759e2a95a358b7fec3..9c38e0e04f4eed5bafe417a2fd31e2fd5286ec5b 100644 (file)
@@ -84,9 +84,9 @@ void XonoticFirstRunDialog_fill(entity me)
 
        me.gotoRC(me, me.rows - 3, 0);
        me.TDempty(me, 1.5);
-       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "1", ZCTX(_("ALWU2N^Yes"))));
-       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "0", ZCTX(_("ALWU2N^No"))));
-       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "-1", ZCTX(_("ALWU2N^Undecided"))));
+       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "1", _("Yes")));
+       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "0", _("No")));
+       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "-1", _("Undecided")));
 
        // because of the language selector, this is a menu_restart!
        me.gotoRC(me, me.rows - 1, 0);
index 04c67e727b088b30a15cfbcc09f8d562ad3621e4..4e76cbc6d3a5095560d41dd71da3bbb969476678 100644 (file)
@@ -187,6 +187,7 @@ void XonoticServerCreateTab_gameTypeChangeNotify(entity me)
                case MAPINFO_TYPE_ONSLAUGHT:  GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
                case MAPINFO_TYPE_CTS:        GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
                case MAPINFO_TYPE_INVASION:   GameType_ConfigureSliders(e, l, _("Point limit:"),     5,    0,  5, "");                         break;
+       case MAPINFO_TYPE_TEAM_DEATHMATCH:GameType_ConfigureSliders(e, l, _("Point limit:"),     5,  100,  5, "g_tdm_point_limit");        break;
                default:                      GameType_ConfigureSliders(e, l, _("Frag limit:"),      5,  100,  5, "fraglimit_override");       break;
        }
 
index a5a97c5503fe77f30a1064b657c2bdcd0fb67eee..136997eec0afae2a1b2451d1b5eb5d8e6af68e6f 100644 (file)
@@ -21,10 +21,10 @@ void XonoticDemoStartConfirmDialog_fill(entity me)
                me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
        me.TR(me);
        me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Yes"), '1 0 0'));
                        e.onClick = Handle_StartDemo_Click;
                        e.onClickEntity = demolist;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
                        e.onClick = Dialog_Close;
                        e.onClickEntity = me;
 }
index 5510710c2c21a4b22e0c874dcd3dbd489021e7de..5c9bf8cb3d12ba9d6b633d1f1cd8cf27448728f8 100644 (file)
@@ -21,10 +21,10 @@ void XonoticDemoTimeConfirmDialog_fill(entity me)
                me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
        me.TR(me);
        me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Yes"), '1 0 0'));
                        e.onClick = Handle_TimeDemo_Click;
                        e.onClickEntity = demolist;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
                        e.onClick = Dialog_Close;
                        e.onClickEntity = me;
 }
index 1adfb015eff1d85e192034eab19ce93c93f351cb..06bf7924444ffc6651b595f2e3536bb7c7b6f931 100644 (file)
@@ -142,9 +142,9 @@ void XonoticProfileTab_fill(entity me)
        #if 0
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gender:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("_cl_gender"));
-                       e.addValue(e, ZCTX(_("GENDER^Undisclosed")), "0");
-                       e.addValue(e, ZCTX(_("GENDER^Female")), "1");
-                       e.addValue(e, ZCTX(_("GENDER^Male")), "2");
+                       e.addValue(e, _("Undisclosed"), "0");
+                       e.addValue(e, _("Female"), "1");
+                       e.addValue(e, _("Male"), "2");
                        e.configureXonoticTextSliderValues(e);
        #else
                        me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gender")));
index 811cb0998f2774588359af13bee781431b1619f7..fcbbbbe0e19b6a740576762a673d725b16e21bd4 100644 (file)
@@ -148,9 +148,9 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Damage effects:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_damageeffect"));
-                       e.addValue(e, _("Disabled"), "0");
+                       e.addValue(e, ZCTX(_("DMGFX^Disabled")), "0");
                        e.addValue(e, _("Skeletal"), "1");
-                       e.addValue(e, _("All"), "2");
+                       e.addValue(e, ZCTX(_("DMGFX^All")), "2");
                        e.configureXonoticTextSliderValues(e);
 
        me.gotoRC(me, 1.25, 3.2); me.setFirstColumn(me, me.currentColumn);
index 0aa38e85af2d472be53c18f53c6d32003c946c86..28cf3708f3af0833b98028ef9b42e433a934292c 100644 (file)
@@ -40,8 +40,8 @@ void XonoticGameCrosshairSettingsTab_fill(entity me)
                me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
        me.TR(me);
                me.TDempty(me, 0.1);
-               for(i = 1; i <= 14; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+               for(i = 31; i <= 42; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
                                setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
                }
                // show a larger preview of the selected crosshair
@@ -50,14 +50,14 @@ void XonoticGameCrosshairSettingsTab_fill(entity me)
                        setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
        me.TR(me);
                me.TDempty(me, 0.1);
-               for(i = 15; i <= 28; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+               for(i = 43; i <= 54; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
                                setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
                }
        me.TR(me);
                me.TDempty(me, 0.1);
-               for(i = 29; i <= 42; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+               for(i = 55; i <= 66; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
                                setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
                }
        me.TR(me);
index fc7e3a136abb12250ac5af16ca22e38d4b7187f9..bb0587184be7b6ca1491c4cc2730a3eb9831091a 100644 (file)
@@ -142,9 +142,9 @@ void XonoticGameHUDSettingsTab_fill(entity me)
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Decolorize:")));
                        setDependent(e, "hud_shownames", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticTextSlider("hud_shownames_decolorize"));
-                       e.addValue(e, ZCTX(_("Never")), "0");
-                       e.addValue(e, ZCTX(_("Teamplay")), "1");
-                       e.addValue(e, ZCTX(_("Always")), "2");
+                       e.addValue(e, _("Never"), "0");
+                       e.addValue(e, _("Teamplay"), "1");
+                       e.addValue(e, _("Always"), "2");
                        e.configureXonoticTextSliderValues(e);
                        setDependent(e, "hud_shownames", 1, 1);
 
index 7749a148d96a5a6e77d5bb2c57123c19b106d528..9f327c3f51245c96cf4df83480c6eaceb88c92e5 100644 (file)
@@ -30,10 +30,10 @@ void XonoticHUDConfirmDialog_fill(entity me)
                me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you wish to start a local game to set up the HUD?")));
        me.TR(me);
        me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^Yes")), '1 0 0'));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Yes"), '1 0 0'));
                        e.onClick = HUDSetup_Start;
                        e.onClickEntity = me;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^No")), '0 1 0'));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
                        e.onClick = Dialog_Close;
                        e.onClickEntity = me;
 }
index f1707bd3f57fd414540c7ec9e026106107062a38..034608d096d396ca59142133ff54018ef5c9b62f 100644 (file)
@@ -52,10 +52,10 @@ void XonoticGameMessageSettingsTab_fill(entity me)
                me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Sprees in info messages:")));
                        setDependent(e, "notification_show_sprees", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticTextSlider("notification_show_sprees_info"));
-                       e.addValue(e, ZCTX(_("Disabled")), "0");
-                       e.addValue(e, ZCTX(_("Target")), "1");
-                       e.addValue(e, ZCTX(_("Attacker")), "2");
-                       e.addValue(e, ZCTX(_("Both")), "3");
+                       e.addValue(e, ZCTX(_("SPREES^Disabled")), "0");
+                       e.addValue(e, _("Target"), "1");
+                       e.addValue(e, _("Attacker"), "2");
+                       e.addValue(e, ZCTX(_("SPREES^Both")), "3");
                        e.configureXonoticTextSliderValues(e);
                        setDependent(e, "notification_show_sprees", 1, 1);
        #endif
index 0c454d3bc525de0cba701a058e704cd05850bf4c..b4ac6134834ba254d571ed93db991eede16e8bfd 100644 (file)
@@ -91,9 +91,9 @@ void XonoticInputSettingsTab_fill(entity me)
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Jetpack on jump:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_jetpack_jump"));
-                       e.addValue(e, _("Disabled"), "0");
+                       e.addValue(e, ZCTX(_("JPJUMP^Disabled")), "0");
                        e.addValue(e, _("Air only"), "1");
-                       e.addValue(e, _("All"), "2");
+                       e.addValue(e, ZCTX(_("JPJUMP^All")), "2");
                        e.configureXonoticTextSliderValues(e);
                        e.sendCvars = true;
        me.TR(me);
index feb1d89b133d2b4e040db7bd42d2828c500fc89f..0d36c836340f7b463d2c0af41c9197990ec67619 100644 (file)
@@ -31,12 +31,11 @@ entity makeXonoticGametypeList(void)
 }
 void XonoticGametypeList_configureXonoticGametypeList(entity me)
 {
-       float i;
        me.configureXonoticListBox(me);
        me.nItems = GameType_GetCount();
 
        // we want the pics mipmapped
-       for(i = 0; i < GameType_GetCount(); ++i)
+       for(int i = 0; i < GameType_GetCount(); ++i)
                draw_PreloadPictureWithFlags(GameType_GetIcon(i), PRECACHE_PIC_MIPMAP);
 
        me.loadCvars(me);
@@ -67,12 +66,15 @@ void XonoticGametypeList_loadCvars(entity me)
 }
 void XonoticGametypeList_saveCvars(entity me)
 {
-       float t;
-       t = GameType_GetID(me.selectedItem);
-       if(t == MapInfo_CurrentGametype())
+       int t = GameType_GetID(me.selectedItem);
+       if (t == MapInfo_CurrentGametype()) {
                return;
+       }
        MapInfo_SwitchGameType(t);
-       me.parent.gameTypeChangeNotify(me.parent);
+       entity owner = me.parent;
+       if (owner) { // not set immediately
+               owner.gameTypeChangeNotify(owner);
+       }
 }
 void XonoticGametypeList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
 {
index 0846526d0c66283fd46e94f0624414c0cec6d103..330b2bb726a0e89ccc19822ee8c8af0182b82e0e 100644 (file)
@@ -665,12 +665,11 @@ float updateCompression()
        //GAMETYPE(MAPINFO_TYPE_INVASION) \
        /* nothing */
 
-float GameType_GetID(float cnt)
+int GameType_GetID(int cnt)
 {
-       float i;
-       i = 0;
+       int i = 0;
 
-       #define GAMETYPE(id) { if(i++ == cnt) return id; }
+       #define GAMETYPE(id) { if (i++ == cnt) return id; }
        GAMETYPES
        #undef GAMETYPE
 
@@ -679,10 +678,9 @@ float GameType_GetID(float cnt)
        return 0;
 }
 
-float GameType_GetCount()
+int GameType_GetCount()
 {
-       float i;
-       i = 0;
+       int i = 0;
 
        #define GAMETYPE(id) ++i;
        GAMETYPES
@@ -691,9 +689,9 @@ float GameType_GetCount()
        return i;
 }
 
-string GameType_GetName(float cnt)
+string GameType_GetName(int cnt)
 {
-       float i = GameType_GetID(cnt);
+       int i = GameType_GetID(cnt);
 
        if(i)
                return MapInfo_Type_ToText(i);
@@ -701,9 +699,9 @@ string GameType_GetName(float cnt)
        return "";
 }
 
-string GameType_GetIcon(float cnt)
+string GameType_GetIcon(int cnt)
 {
-       float i = GameType_GetID(cnt);
+       int i = GameType_GetID(cnt);
 
        if(i)
                return strcat("gametype_", MapInfo_Type_ToString(i));
index 64072977f60b7baa7b7de06b7b39f848e62756a1..80803f8544df735f4363112b466441da3ad34f35 100644 (file)
@@ -34,11 +34,11 @@ void URI_Get_Callback(float id, float status, string data);
 
 // game type list box stuff (does not NEED to contain all game types, other
 // types stay available via console)
-float GameType_GetID(float cnt);
-string GameType_GetName(float cnt);
-string GameType_GetIcon(float cnt);
+int GameType_GetID(int cnt);
+string GameType_GetName(int cnt);
+string GameType_GetIcon(int cnt);
 //string GameType_GetTeams(float cnt);
-float GameType_GetCount();
+int GameType_GetCount();
 
 void dialog_hudpanel_common_notoggle(entity me, string panelname);
 #define DIALOG_HUDPANEL_COMMON_NOTOGGLE() \
index 5453f5199f6d4150ab93293c381db7c34e4e5293..424abc33beab48906baaa4893a79f7d76f2651f5 100644 (file)
@@ -1004,7 +1004,7 @@ float PlayerInIDList(entity p, string idlist)
        float n, i;
        string s;
 
-       // NOTE: we do NOT check crypto_keyfp here, an unsigned ID is fine too for this
+       // NOTE: we do NOT check crypto_idfp_signed here, an unsigned ID is fine too for this
        if (!p.crypto_idfp)
                return 0;
 
index 09314c745631dc119f5b32341c294c1bb488f148..5b7e761b7879077a18d841119ca0e0e2e4092c93 100644 (file)
@@ -48,13 +48,13 @@ float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
 }
 
 // if the client is not acceptable, return a string to be used for error messages
-string GetClientErrorString(float clienterror, string original_input)
+string GetClientErrorString_color(float clienterror, string original_input, string col)
 {
        switch(clienterror)
        {
-               case CLIENT_DOESNT_EXIST: { return strcat("Client '", original_input, "' doesn't exist"); }
-               case CLIENT_NOT_REAL: { return strcat("Client '", original_input, "' is not real"); }
-               case CLIENT_NOT_BOT: { return strcat("Client '", original_input, "' is not a bot"); }
+               case CLIENT_DOESNT_EXIST: { return strcat(col, "Client '", original_input, col, "' doesn't exist"); }
+               case CLIENT_NOT_REAL: { return strcat(col, "Client '", original_input, col, "' is not real"); }
+               case CLIENT_NOT_BOT: { return strcat(col, "Client '", original_input, col, "' is not a bot"); }
                default: { return "Incorrect usage of GetClientErrorString"; }
        }
 }
index 2a03041d90a56d373b98b36943cc28c9448f1d3e..ac99e32dc46d2583a677e3d687d6a067dde510ee 100644 (file)
@@ -58,7 +58,8 @@ float VerifyKickableEntity(entity client);
 float VerifyClientEntity(entity client, float must_be_real, float must_be_bots);
 
 // if the client is not acceptable, return a string to be used for error messages
-string GetClientErrorString(float clienterror, string original_input);
+string GetClientErrorString_color(float clienterror, string original_input, string col);
+#define GetClientErrorString(clienterror,original_input) GetClientErrorString_color(clienterror,original_input,"^7")
 
 // is this entity number even in the possible range of entities?
 float VerifyClientNumber(float tmp_number);
index 118fbd4924d6d1d4b2845049bd742a1c31aadb7f..73e5108795525bd072c60cc5bd86bcd58cc25da5 100644 (file)
@@ -414,7 +414,7 @@ float RadarMap_Make(float argc)
                                case "--res": // minor alias
                                case "--resolution": { ++i; radarmapper.size_x = stof(argv(i)); ++i; radarmapper.size_y = stof(argv(i)); break; }
                                case "--qual": // minor alias
-                               case "--quality": { ++i; radarmapper.size.z = stof(argv(i)); break; }
+                               case "--quality": { ++i; radarmapper.size_z = stof(argv(i)); break; }
 
                                default:
                                        i = argc;
index bd9880839d69f33ab220fd54a40eed7f87281460..9591ee8baa9d9b7620d5b5fbe32f430a8e0a22cb 100644 (file)
@@ -361,7 +361,7 @@ float Ban_GetClientIP(entity client)
        float i1, i2, i3, i4;
        string s;
 
-       if(client.crypto_keyfp)
+       if(client.crypto_idfp_signed)
                ban_idfp = client.crypto_idfp;
        else
                ban_idfp = string_null;
index 8ef3018fd1e3469c5614bbf8e587c50504d88d53..1655d39545349b57db9e76aec27c7fed2e7715dd 100644 (file)
@@ -518,6 +518,267 @@ vector randompos(vector m1, vector m2)
     return  v;
 }
 
+float want_weapon(entity weaponinfo, float allguns) // WEAPONTODO: what still needs done?
+{
+       int i = weaponinfo.weapon;
+       int d = 0;
+
+       if (!i)
+               return 0;
+
+       if (g_lms || g_ca || allguns)
+       {
+               if(weaponinfo.spawnflags & WEP_FLAG_NORMAL)
+                       d = true;
+               else
+                       d = false;
+       }
+       else if (g_cts)
+               d = (i == WEP_SHOTGUN);
+       else if (g_nexball)
+               d = 0; // weapon is set a few lines later
+       else
+               d = !(!weaponinfo.weaponstart);
+
+       if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
+               d |= (i == WEP_HOOK);
+       if(!g_cts && (weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED)) // never default mutator blocked guns
+               d = 0;
+
+       float t = weaponinfo.weaponstartoverride;
+
+       //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n"));
+
+       // bit order in t:
+       // 1: want or not
+       // 2: is default?
+       // 4: is set by default?
+       if(t < 0)
+               t = 4 | (3 * d);
+       else
+               t |= (2 * d);
+
+       return t;
+}
+
+void readplayerstartcvars()
+{
+       entity e;
+       float i, j, t;
+       string s;
+
+       // initialize starting values for players
+       start_weapons = '0 0 0';
+       start_weapons_default = '0 0 0';
+       start_weapons_defaultmask = '0 0 0';
+       start_items = 0;
+       start_ammo_shells = 0;
+       start_ammo_nails = 0;
+       start_ammo_rockets = 0;
+       start_ammo_cells = 0;
+       start_ammo_plasma = 0;
+       start_health = cvar("g_balance_health_start");
+       start_armorvalue = cvar("g_balance_armor_start");
+
+       g_weaponarena = 0;
+       g_weaponarena_weapons = '0 0 0';
+
+       s = cvar_string("g_weaponarena");
+       if (s == "0" || s == "")
+       {
+               if(g_ca)
+                       s = "most";
+       }
+
+       if (s == "0" || s == "")
+       {
+               // no arena
+       }
+       else if (s == "off")
+       {
+               // forcibly turn off weaponarena
+       }
+       else if (s == "all" || s == "1")
+       {
+               g_weaponarena = 1;
+               g_weaponarena_list = "All Weapons";
+               for (j = WEP_FIRST; j <= WEP_LAST; ++j)
+               {
+                       e = get_weaponinfo(j);
+                       if (!(e.spawnflags & WEP_FLAG_MUTATORBLOCKED))
+                               g_weaponarena_weapons |= WepSet_FromWeapon(j);
+               }
+       }
+       else if (s == "most")
+       {
+               g_weaponarena = 1;
+               g_weaponarena_list = "Most Weapons";
+               for (j = WEP_FIRST; j <= WEP_LAST; ++j)
+               {
+                       e = get_weaponinfo(j);
+                       if (!(e.spawnflags & WEP_FLAG_MUTATORBLOCKED))
+                               if (e.spawnflags & WEP_FLAG_NORMAL)
+                                       g_weaponarena_weapons |= WepSet_FromWeapon(j);
+               }
+       }
+       else if (s == "none")
+       {
+               g_weaponarena = 1;
+               g_weaponarena_list = "No Weapons";
+       }
+       else
+       {
+               g_weaponarena = 1;
+               t = tokenize_console(s);
+               g_weaponarena_list = "";
+               for (i = 0; i < t; ++i)
+               {
+                       s = argv(i);
+                       for (j = WEP_FIRST; j <= WEP_LAST; ++j)
+                       {
+                               e = get_weaponinfo(j);
+                               if (e.netname == s)
+                               {
+                                       g_weaponarena_weapons |= WepSet_FromWeapon(j);
+                                       g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
+                                       break;
+                               }
+                       }
+                       if (j > WEP_LAST)
+                       {
+                               print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
+                       }
+               }
+               g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
+       }
+
+       if(g_weaponarena)
+               g_weaponarena_random = cvar("g_weaponarena_random");
+       else
+               g_weaponarena_random = 0;
+       g_weaponarena_random_with_blaster = cvar("g_weaponarena_random_with_blaster");
+
+       if (g_weaponarena)
+       {
+               g_weapon_stay = 0; // incompatible
+               start_weapons = g_weaponarena_weapons;
+               start_items |= IT_UNLIMITED_AMMO;
+       }
+       else
+       {
+               for (i = WEP_FIRST; i <= WEP_LAST; ++i)
+               {
+                       e = get_weaponinfo(i);
+                       int w = want_weapon(e, false);
+                       if(w & 1)
+                               start_weapons |= WepSet_FromWeapon(i);
+                       if(w & 2)
+                               start_weapons_default |= WepSet_FromWeapon(i);
+                       if(w & 4)
+                               start_weapons_defaultmask |= WepSet_FromWeapon(i);
+               }
+       }
+
+       if(!cvar("g_use_ammunition"))
+               start_items |= IT_UNLIMITED_AMMO;
+
+       if(start_items & IT_UNLIMITED_WEAPON_AMMO)
+       {
+               start_ammo_shells = 999;
+               start_ammo_nails = 999;
+               start_ammo_rockets = 999;
+               start_ammo_cells = 999;
+               start_ammo_plasma = 999;
+               start_ammo_fuel = 999;
+       }
+       else
+       {
+               start_ammo_shells = cvar("g_start_ammo_shells");
+               start_ammo_nails = cvar("g_start_ammo_nails");
+               start_ammo_rockets = cvar("g_start_ammo_rockets");
+               start_ammo_cells = cvar("g_start_ammo_cells");
+               start_ammo_plasma = cvar("g_start_ammo_plasma");
+               start_ammo_fuel = cvar("g_start_ammo_fuel");
+       }
+
+       if (warmup_stage)
+       {
+               warmup_start_ammo_shells = start_ammo_shells;
+               warmup_start_ammo_nails = start_ammo_nails;
+               warmup_start_ammo_rockets = start_ammo_rockets;
+               warmup_start_ammo_cells = start_ammo_cells;
+               warmup_start_ammo_plasma = start_ammo_plasma;
+               warmup_start_ammo_fuel = start_ammo_fuel;
+               warmup_start_health = start_health;
+               warmup_start_armorvalue = start_armorvalue;
+               warmup_start_weapons = start_weapons;
+               warmup_start_weapons_default = start_weapons_default;
+               warmup_start_weapons_defaultmask = start_weapons_defaultmask;
+
+               if (!g_weaponarena && !g_ca)
+               {
+                       warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
+                       warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
+                       warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
+                       warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
+                       warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma");
+                       warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
+                       warmup_start_health = cvar("g_warmup_start_health");
+                       warmup_start_armorvalue = cvar("g_warmup_start_armor");
+                       warmup_start_weapons = '0 0 0';
+                       warmup_start_weapons_default = '0 0 0';
+                       warmup_start_weapons_defaultmask = '0 0 0';
+                       for (i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       {
+                               e = get_weaponinfo(i);
+                               int w = want_weapon(e, g_warmup_allguns);
+                               if(w & 1)
+                                       warmup_start_weapons |= WepSet_FromWeapon(i);
+                               if(w & 2)
+                                       warmup_start_weapons_default |= WepSet_FromWeapon(i);
+                               if(w & 4)
+                                       warmup_start_weapons_defaultmask |= WepSet_FromWeapon(i);
+                       }
+               }
+       }
+
+       if (g_jetpack)
+               start_items |= IT_JETPACK;
+
+       MUTATOR_CALLHOOK(SetStartItems);
+
+       if ((start_items & IT_JETPACK) || (g_grappling_hook && (start_weapons & WEPSET_HOOK)))
+       {
+               start_items |= IT_FUEL_REGEN;
+               start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
+               warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
+       }
+
+       WepSet precache_weapons = start_weapons;
+       if (g_warmup_allguns != 1)
+               precache_weapons |= warmup_start_weapons;
+       for (i = WEP_FIRST; i <= WEP_LAST; ++i)
+       {
+               e = get_weaponinfo(i);
+               if(precache_weapons & WepSet_FromWeapon(i))
+                       WEP_ACTION(i, WR_INIT);
+       }
+
+       start_ammo_shells = max(0, start_ammo_shells);
+       start_ammo_nails = max(0, start_ammo_nails);
+       start_ammo_rockets = max(0, start_ammo_rockets);
+       start_ammo_cells = max(0, start_ammo_cells);
+       start_ammo_plasma = max(0, start_ammo_plasma);
+       start_ammo_fuel = max(0, start_ammo_fuel);
+
+       warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
+       warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
+       warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
+       warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
+       warmup_start_ammo_plasma = max(0, warmup_start_ammo_plasma);
+       warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
+}
+
 float sound_allowed(float destin, entity e)
 {
     // sounds from world may always pass
index 016285fb1650869060e0529385b60dd0b8349e68..fc2bf4be991cf6f6b28bc069e7a5573f59586fba 100644 (file)
@@ -240,266 +240,8 @@ float warmup_start_health;
 float warmup_start_armorvalue;
 float g_weapon_stay;
 
-float want_weapon(entity weaponinfo, float allguns) // WEAPONTODO: what still needs done?
-{
-       int i = weaponinfo.weapon;
-       int d = 0;
-
-       if (!i)
-               return 0;
-
-       if (g_lms || g_ca || allguns)
-       {
-               if(weaponinfo.spawnflags & WEP_FLAG_NORMAL)
-                       d = true;
-               else
-                       d = false;
-       }
-       else if (g_cts)
-               d = (i == WEP_SHOTGUN);
-       else if (g_nexball)
-               d = 0; // weapon is set a few lines later
-       else
-               d = !(!weaponinfo.weaponstart);
-
-       if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
-               d |= (i == WEP_HOOK);
-       if(!g_cts && (weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED)) // never default mutator blocked guns
-               d = 0;
-
-       float t = weaponinfo.weaponstartoverride;
-
-       //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n"));
-
-       // bit order in t:
-       // 1: want or not
-       // 2: is default?
-       // 4: is set by default?
-       if(t < 0)
-               t = 4 | (3 * d);
-       else
-               t |= (2 * d);
-
-       return t;
-}
-
-void readplayerstartcvars()
-{
-       entity e;
-       float i, j, t;
-       string s;
-
-       // initialize starting values for players
-       start_weapons = '0 0 0';
-       start_weapons_default = '0 0 0';
-       start_weapons_defaultmask = '0 0 0';
-       start_items = 0;
-       start_ammo_shells = 0;
-       start_ammo_nails = 0;
-       start_ammo_rockets = 0;
-       start_ammo_cells = 0;
-       start_ammo_plasma = 0;
-       start_health = cvar("g_balance_health_start");
-       start_armorvalue = cvar("g_balance_armor_start");
-
-       g_weaponarena = 0;
-       g_weaponarena_weapons = '0 0 0';
-
-       s = cvar_string("g_weaponarena");
-       if (s == "0" || s == "")
-       {
-               if(g_ca)
-                       s = "most";
-       }
-
-       if (s == "0" || s == "")
-       {
-               // no arena
-       }
-       else if (s == "off")
-       {
-               // forcibly turn off weaponarena
-       }
-       else if (s == "all" || s == "1")
-       {
-               g_weaponarena = 1;
-               g_weaponarena_list = "All Weapons";
-               for (j = WEP_FIRST; j <= WEP_LAST; ++j)
-               {
-                       e = get_weaponinfo(j);
-                       if (!(e.spawnflags & WEP_FLAG_MUTATORBLOCKED))
-                               g_weaponarena_weapons |= WepSet_FromWeapon(j);
-               }
-       }
-       else if (s == "most")
-       {
-               g_weaponarena = 1;
-               g_weaponarena_list = "Most Weapons";
-               for (j = WEP_FIRST; j <= WEP_LAST; ++j)
-               {
-                       e = get_weaponinfo(j);
-                       if (!(e.spawnflags & WEP_FLAG_MUTATORBLOCKED))
-                               if (e.spawnflags & WEP_FLAG_NORMAL)
-                                       g_weaponarena_weapons |= WepSet_FromWeapon(j);
-               }
-       }
-       else if (s == "none")
-       {
-               g_weaponarena = 1;
-               g_weaponarena_list = "No Weapons";
-       }
-       else
-       {
-               g_weaponarena = 1;
-               t = tokenize_console(s);
-               g_weaponarena_list = "";
-               for (i = 0; i < t; ++i)
-               {
-                       s = argv(i);
-                       for (j = WEP_FIRST; j <= WEP_LAST; ++j)
-                       {
-                               e = get_weaponinfo(j);
-                               if (e.netname == s)
-                               {
-                                       g_weaponarena_weapons |= WepSet_FromWeapon(j);
-                                       g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
-                                       break;
-                               }
-                       }
-                       if (j > WEP_LAST)
-                       {
-                               print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
-                       }
-               }
-               g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
-       }
-
-       if(g_weaponarena)
-               g_weaponarena_random = cvar("g_weaponarena_random");
-       else
-               g_weaponarena_random = 0;
-       g_weaponarena_random_with_blaster = cvar("g_weaponarena_random_with_blaster");
-
-       if (g_weaponarena)
-       {
-               g_weapon_stay = 0; // incompatible
-               start_weapons = g_weaponarena_weapons;
-               start_items |= IT_UNLIMITED_AMMO;
-       }
-       else
-       {
-               for (i = WEP_FIRST; i <= WEP_LAST; ++i)
-               {
-                       e = get_weaponinfo(i);
-                       int w = want_weapon(e, false);
-                       if(w & 1)
-                               start_weapons |= WepSet_FromWeapon(i);
-                       if(w & 2)
-                               start_weapons_default |= WepSet_FromWeapon(i);
-                       if(w & 4)
-                               start_weapons_defaultmask |= WepSet_FromWeapon(i);
-               }
-       }
-
-       if(!cvar("g_use_ammunition"))
-               start_items |= IT_UNLIMITED_AMMO;
-
-       if(start_items & IT_UNLIMITED_WEAPON_AMMO)
-       {
-               start_ammo_shells = 999;
-               start_ammo_nails = 999;
-               start_ammo_rockets = 999;
-               start_ammo_cells = 999;
-               start_ammo_plasma = 999;
-               start_ammo_fuel = 999;
-       }
-       else
-       {
-               start_ammo_shells = cvar("g_start_ammo_shells");
-               start_ammo_nails = cvar("g_start_ammo_nails");
-               start_ammo_rockets = cvar("g_start_ammo_rockets");
-               start_ammo_cells = cvar("g_start_ammo_cells");
-               start_ammo_plasma = cvar("g_start_ammo_plasma");
-               start_ammo_fuel = cvar("g_start_ammo_fuel");
-       }
-
-       if (warmup_stage)
-       {
-               warmup_start_ammo_shells = start_ammo_shells;
-               warmup_start_ammo_nails = start_ammo_nails;
-               warmup_start_ammo_rockets = start_ammo_rockets;
-               warmup_start_ammo_cells = start_ammo_cells;
-               warmup_start_ammo_plasma = start_ammo_plasma;
-               warmup_start_ammo_fuel = start_ammo_fuel;
-               warmup_start_health = start_health;
-               warmup_start_armorvalue = start_armorvalue;
-               warmup_start_weapons = start_weapons;
-               warmup_start_weapons_default = start_weapons_default;
-               warmup_start_weapons_defaultmask = start_weapons_defaultmask;
-
-               if (!g_weaponarena && !g_ca)
-               {
-                       warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
-                       warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
-                       warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
-                       warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
-                       warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma");
-                       warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
-                       warmup_start_health = cvar("g_warmup_start_health");
-                       warmup_start_armorvalue = cvar("g_warmup_start_armor");
-                       warmup_start_weapons = '0 0 0';
-                       warmup_start_weapons_default = '0 0 0';
-                       warmup_start_weapons_defaultmask = '0 0 0';
-                       for (i = WEP_FIRST; i <= WEP_LAST; ++i)
-                       {
-                               e = get_weaponinfo(i);
-                               int w = want_weapon(e, g_warmup_allguns);
-                               if(w & 1)
-                                       warmup_start_weapons |= WepSet_FromWeapon(i);
-                               if(w & 2)
-                                       warmup_start_weapons_default |= WepSet_FromWeapon(i);
-                               if(w & 4)
-                                       warmup_start_weapons_defaultmask |= WepSet_FromWeapon(i);
-                       }
-               }
-       }
-
-       if (g_jetpack)
-               start_items |= IT_JETPACK;
-
-       MUTATOR_CALLHOOK(SetStartItems);
-
-       if ((start_items & IT_JETPACK) || (g_grappling_hook && (start_weapons & WEPSET_HOOK)))
-       {
-               start_items |= IT_FUEL_REGEN;
-               start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
-               warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
-       }
-
-       WepSet precache_weapons = start_weapons;
-       if (g_warmup_allguns != 1)
-               precache_weapons |= warmup_start_weapons;
-       for (i = WEP_FIRST; i <= WEP_LAST; ++i)
-       {
-               e = get_weaponinfo(i);
-               if(precache_weapons & WepSet_FromWeapon(i))
-                       WEP_ACTION(i, WR_INIT);
-       }
-
-       start_ammo_shells = max(0, start_ammo_shells);
-       start_ammo_nails = max(0, start_ammo_nails);
-       start_ammo_rockets = max(0, start_ammo_rockets);
-       start_ammo_cells = max(0, start_ammo_cells);
-       start_ammo_plasma = max(0, start_ammo_plasma);
-       start_ammo_fuel = max(0, start_ammo_fuel);
-
-       warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
-       warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
-       warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
-       warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
-       warmup_start_ammo_plasma = max(0, warmup_start_ammo_plasma);
-       warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
-}
+float want_weapon(entity weaponinfo, float allguns); // WEAPONTODO: what still needs done?
+void readplayerstartcvars();
 
 float g_bugrigs;
 float g_bugrigs_planar_movement;
@@ -636,8 +378,8 @@ void readlevelcvars(void)
        if (!warmup_stage)
                game_starttime = time + cvar("g_start_delay");
 
-    for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
-       WEP_ACTION(i, WR_INIT);
+       for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+               WEP_ACTION(i, WR_INIT);
 
        readplayerstartcvars();
 }
index 5e80483b96bff6ddeba62aa3cb97870015abd406..3143699f2d7b18064466b4e3df3714850cd590c4 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef SERVER_SYS_POST_H
 #define SERVER_SYS_POST_H
 
-#pragma noref 0
-
-#undef ATTEN_NORM
 #undef objerror
 #undef droptofloor
 #undef sound
@@ -15,4 +12,7 @@
 var float(string name) cvar;
 var string(string name) cvar_string;
 var void(string name, string value) cvar_set;
+
+#pragma noref 0
+
 #endif
index b31194fb9a4e0ada97f1b0bbd5d86a43edb7ef38..bfdcdb860e267fff7a385d17fa76cd4c6fa4c3ab 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef SERVER_SYS_PRE_H
 #define SERVER_SYS_PRE_H
 
-#define ATTEN_NORM builtin_ATTEN_NORM
 #define objerror builtin_objerror
 #define droptofloor builtin_droptofloor
 #define sound builtin_sound
@@ -11,4 +10,5 @@
 #define cvar builtin_cvar
 
 #pragma noref 1
+
 #endif
diff --git a/qcsrc/server/t_plats.qc b/qcsrc/server/t_plats.qc
new file mode 100644 (file)
index 0000000..7b2bc99
--- /dev/null
@@ -0,0 +1,2392 @@
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+       #include "../dpdefs/progsdefs.qh"
+    #include "../dpdefs/dpextensions.qh"
+    #include "../warpzonelib/mathlib.qh"
+    #include "../warpzonelib/common.qh"
+    #include "../warpzonelib/util_server.qh"
+    #include "../common/constants.qh"
+    #include "../common/util.qh"
+    #include "../common/weapons/weapons.qh"
+    #include "constants.qh"
+    #include "defs.qh"
+    #include "../common/notifications.qh"
+    #include "../common/deathtypes.qh"
+    #include "command/common.qh"
+    #include "../csqcmodellib/sv_model.qh"
+#endif
+
+#ifdef SVQC
+
+.float dmgtime2;
+void generic_plat_blocked()
+{
+    if(self.dmg && other.takedamage != DAMAGE_NO) {
+        if(self.dmgtime2 < time) {
+            Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+            self.dmgtime2 = time + self.dmgtime;
+        }
+
+        // Gib dead/dying stuff
+        if(other.deadflag != DEAD_NO)
+            Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+    }
+}
+
+
+.entity trigger_field;
+
+void() plat_center_touch;
+void() plat_outside_touch;
+void() plat_trigger_use;
+void() plat_go_up;
+void() plat_go_down;
+void() plat_crush;
+const float PLAT_LOW_TRIGGER = 1;
+
+void plat_spawn_inside_trigger()
+{
+       entity trigger;
+       vector tmin, tmax;
+
+       trigger = spawn();
+       trigger.touch = plat_center_touch;
+       trigger.movetype = MOVETYPE_NONE;
+       trigger.solid = SOLID_TRIGGER;
+       trigger.enemy = self;
+
+       tmin = self.absmin + '25 25 0';
+       tmax = self.absmax - '25 25 -8';
+       tmin.z = tmax.z - (self.pos1_z - self.pos2_z + 8);
+       if (self.spawnflags & PLAT_LOW_TRIGGER)
+               tmax.z = tmin.z + 8;
+
+       if (self.size.x <= 50)
+       {
+               tmin.x = (self.mins.x + self.maxs.x) / 2;
+               tmax.x = tmin.x + 1;
+       }
+       if (self.size.y <= 50)
+       {
+               tmin.y = (self.mins.y + self.maxs.y) / 2;
+               tmax.y = tmin.y + 1;
+       }
+
+       if(tmin.x < tmax.x)
+               if(tmin.y < tmax.y)
+                       if(tmin.z < tmax.z)
+                       {
+                               setsize (trigger, tmin, tmax);
+                               return;
+                       }
+
+       // otherwise, something is fishy...
+       remove(trigger);
+       objerror("plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
+}
+
+void plat_hit_top()
+{
+       sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       self.state = 1;
+       self.think = plat_go_down;
+       self.nextthink = self.ltime + 3;
+}
+
+void plat_hit_bottom()
+{
+       sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       self.state = 2;
+}
+
+void plat_go_down()
+{
+       sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
+       self.state = 3;
+       SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, plat_hit_bottom);
+}
+
+void plat_go_up()
+{
+       sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
+       self.state = 4;
+       SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, plat_hit_top);
+}
+
+void plat_center_touch()
+{
+       if (!other.iscreature)
+               return;
+
+       if (other.health <= 0)
+               return;
+
+       self = self.enemy;
+       if (self.state == 2)
+               plat_go_up ();
+       else if (self.state == 1)
+               self.nextthink = self.ltime + 1;        // delay going down
+}
+
+void plat_outside_touch()
+{
+       if (!other.iscreature)
+               return;
+
+       if (other.health <= 0)
+               return;
+
+       self = self.enemy;
+       if (self.state == 1)
+               plat_go_down ();
+}
+
+void plat_trigger_use()
+{
+       if (self.think)
+               return;         // already activated
+       plat_go_down();
+}
+
+
+void plat_crush()
+{
+    if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
+        Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+    } else {
+        if((self.dmg) && (other.takedamage != DAMAGE_NO)) {   // Shall we bite?
+            Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+            // Gib dead/dying stuff
+            if(other.deadflag != DEAD_NO)
+                Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+        }
+
+        if (self.state == 4)
+            plat_go_down ();
+        else if (self.state == 3)
+            plat_go_up ();
+       // when in other states, then the plat_crush event came delayed after
+       // plat state already had changed
+       // this isn't a bug per se!
+    }
+}
+
+void plat_use()
+{
+       self.use = func_null;
+       if (self.state != 4)
+               objerror ("plat_use: not in up state");
+       plat_go_down();
+}
+
+.string sound1, sound2;
+
+void plat_reset()
+{
+       IFTARGETED
+       {
+               setorigin (self, self.pos1);
+               self.state = 4;
+               self.use = plat_use;
+       }
+       else
+       {
+               setorigin (self, self.pos2);
+               self.state = 2;
+               self.use = plat_trigger_use;
+       }
+}
+
+.float platmovetype_start_default, platmovetype_end_default;
+float set_platmovetype(entity e, string s)
+{
+       // sets platmovetype_start and platmovetype_end based on a string consisting of two values
+
+       float n;
+       n = tokenize_console(s);
+       if(n > 0)
+               e.platmovetype_start = stof(argv(0));
+       else
+               e.platmovetype_start = 0;
+
+       if(n > 1)
+               e.platmovetype_end = stof(argv(1));
+       else
+               e.platmovetype_end = e.platmovetype_start;
+
+       if(n > 2)
+               if(argv(2) == "force")
+                       return true; // no checking, return immediately
+
+       if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
+       {
+               objerror("Invalid platform move type; platform would go in reverse, which is not allowed.");
+               return false;
+       }
+
+       return true;
+}
+
+void spawnfunc_path_corner()
+{
+       // setup values for overriding train movement
+       // if a second value does not exist, both start and end speeds are the single value specified
+       if(!set_platmovetype(self, self.platmovetype))
+               return;
+}
+void spawnfunc_func_plat()
+{
+       if (self.sounds == 0)
+               self.sounds = 2;
+
+    if(self.spawnflags & 4)
+        self.dmg = 10000;
+
+    if(self.dmg && (self.message == ""))
+               self.message = "was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+
+       if (self.sounds == 1)
+       {
+               precache_sound ("plats/plat1.wav");
+               precache_sound ("plats/plat2.wav");
+               self.noise = "plats/plat1.wav";
+               self.noise1 = "plats/plat2.wav";
+       }
+
+       if (self.sounds == 2)
+       {
+               precache_sound ("plats/medplat1.wav");
+               precache_sound ("plats/medplat2.wav");
+               self.noise = "plats/medplat1.wav";
+               self.noise1 = "plats/medplat2.wav";
+       }
+
+       if (self.sound1)
+       {
+               precache_sound (self.sound1);
+               self.noise = self.sound1;
+       }
+       if (self.sound2)
+       {
+               precache_sound (self.sound2);
+               self.noise1 = self.sound2;
+       }
+
+       self.mangle = self.angles;
+       self.angles = '0 0 0';
+
+       self.classname = "plat";
+       if (!InitMovingBrushTrigger())
+               return;
+       self.effects |= EF_LOWPRECISION;
+       setsize (self, self.mins , self.maxs);
+
+       self.blocked = plat_crush;
+
+       if (!self.speed)
+               self.speed = 150;
+       if (!self.lip)
+               self.lip = 16;
+       if (!self.height)
+               self.height = self.size.z - self.lip;
+
+       self.pos1 = self.origin;
+       self.pos2 = self.origin;
+       self.pos2_z = self.origin.z - self.height;
+
+       self.reset = plat_reset;
+       plat_reset();
+
+       plat_spawn_inside_trigger ();   // the "start moving" trigger
+}
+
+.float train_wait_turning;
+void() train_next;
+void train_wait()
+{
+       entity oldself;
+       oldself = self;
+       self = self.enemy;
+       SUB_UseTargets();
+       self = oldself;
+       self.enemy = world;
+
+       // if turning is enabled, the train will turn toward the next point while waiting
+       if(self.platmovetype_turn && !self.train_wait_turning)
+       {
+               entity targ, cp;
+               vector ang;
+               targ = find(world, targetname, self.target);
+               if((self.spawnflags & 1) && targ.curvetarget)
+                       cp = find(world, targetname, targ.curvetarget);
+               else
+                       cp = world;
+
+               if(cp) // bezier curves movement
+                       ang = cp.origin - (self.origin - self.view_ofs); // use the origin of the control point of the next path_corner
+               else // linear movement
+                       ang = targ.origin - (self.origin - self.view_ofs); // use the origin of the next path_corner
+               ang = vectoangles(ang);
+               ang.x = -ang.x; // flip up / down orientation
+
+               if(self.wait > 0) // slow turning
+                       SUB_CalcAngleMove(ang, TSPEED_TIME, self.ltime - time + self.wait, train_wait);
+               else // instant turning
+                       SUB_CalcAngleMove(ang, TSPEED_TIME, 0.0000001, train_wait);
+               self.train_wait_turning = true;
+               return;
+       }
+
+       if(self.noise != "")
+               stopsoundto(MSG_BROADCAST, self, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
+
+       if(self.wait < 0 || self.train_wait_turning) // no waiting or we already waited while turning
+       {
+               self.train_wait_turning = false;
+               train_next();
+       }
+       else
+       {
+               self.think = train_next;
+               self.nextthink = self.ltime + self.wait;
+       }
+}
+
+void train_next()
+{
+       entity targ, cp = world;
+       vector cp_org = '0 0 0';
+
+       targ = find(world, targetname, self.target);
+       self.target = targ.target;
+       if (self.spawnflags & 1)
+       {
+               if(targ.curvetarget)
+               {
+                       cp = find(world, targetname, targ.curvetarget); // get its second target (the control point)
+                       cp_org = cp.origin - self.view_ofs; // no control point found, assume a straight line to the destination
+               }
+       }
+       if (self.target == "")
+               objerror("train_next: no next target");
+       self.wait = targ.wait;
+       if (!self.wait)
+               self.wait = 0.1;
+
+       if(targ.platmovetype)
+       {
+               // this path_corner contains a movetype overrider, apply it
+               self.platmovetype_start = targ.platmovetype_start;
+               self.platmovetype_end = targ.platmovetype_end;
+       }
+       else
+       {
+               // this path_corner doesn't contain a movetype overrider, use the train's defaults
+               self.platmovetype_start = self.platmovetype_start_default;
+               self.platmovetype_end = self.platmovetype_end_default;
+       }
+
+       if (targ.speed)
+       {
+               if (cp)
+                       SUB_CalcMove_Bezier(cp_org, targ.origin - self.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
+               else
+                       SUB_CalcMove(targ.origin - self.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
+       }
+       else
+       {
+               if (cp)
+                       SUB_CalcMove_Bezier(cp_org, targ.origin - self.view_ofs, TSPEED_LINEAR, self.speed, train_wait);
+               else
+                       SUB_CalcMove(targ.origin - self.view_ofs, TSPEED_LINEAR, self.speed, train_wait);
+       }
+
+       if(self.noise != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+}
+
+void func_train_find()
+{
+       entity targ;
+       targ = find(world, targetname, self.target);
+       self.target = targ.target;
+       if (self.target == "")
+               objerror("func_train_find: no next target");
+       setorigin(self, targ.origin - self.view_ofs);
+       self.nextthink = self.ltime + 1;
+       self.think = train_next;
+}
+
+/*QUAKED spawnfunc_func_train (0 .5 .8) ?
+Ridable platform, targets spawnfunc_path_corner path to follow.
+speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
+target : targetname of first spawnfunc_path_corner (starts here)
+*/
+void spawnfunc_func_train()
+{
+       if (self.noise != "")
+               precache_sound(self.noise);
+
+       if (self.target == "")
+               objerror("func_train without a target");
+       if (!self.speed)
+               self.speed = 100;
+
+       if (!InitMovingBrushTrigger())
+               return;
+       self.effects |= EF_LOWPRECISION;
+
+       if (self.spawnflags & 2)
+       {
+               self.platmovetype_turn = true;
+               self.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
+       }
+       else
+               self.view_ofs = self.mins;
+
+       // wait for targets to spawn
+       InitializeEntity(self, func_train_find, INITPRIO_SETLOCATION);
+
+       self.blocked = generic_plat_blocked;
+       if(self.dmg && (self.message == ""))
+               self.message = " was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+       if(self.dmg && (!self.dmgtime))
+               self.dmgtime = 0.25;
+       self.dmgtime2 = time;
+
+       if(!set_platmovetype(self, self.platmovetype))
+               return;
+       self.platmovetype_start_default = self.platmovetype_start;
+       self.platmovetype_end_default = self.platmovetype_end;
+
+       // TODO make a reset function for this one
+}
+
+void func_rotating_setactive(float astate)
+{
+
+       if (astate == ACTIVE_TOGGLE)
+       {
+               if(self.active == ACTIVE_ACTIVE)
+                       self.active = ACTIVE_NOT;
+               else
+                       self.active = ACTIVE_ACTIVE;
+       }
+       else
+               self.active = astate;
+
+       if(self.active  == ACTIVE_NOT)
+               self.avelocity = '0 0 0';
+       else
+               self.avelocity = self.pos1;
+}
+
+/*QUAKED spawnfunc_func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
+Brush model that spins in place on one axis (default Z).
+speed   : speed to rotate (in degrees per second)
+noise   : path/name of looping .wav file to play.
+dmg     : Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime : See above.
+*/
+
+void spawnfunc_func_rotating()
+{
+       if (self.noise != "")
+       {
+               precache_sound(self.noise);
+               ambientsound(self.origin, self.noise, VOL_BASE, ATTEN_IDLE);
+       }
+
+       self.active = ACTIVE_ACTIVE;
+       self.setactive = func_rotating_setactive;
+
+       if (!self.speed)
+               self.speed = 100;
+       // FIXME: test if this turns the right way, then remove this comment (negate as needed)
+       if (self.spawnflags & 4) // X (untested)
+               self.avelocity = '0 0 1' * self.speed;
+       // FIXME: test if this turns the right way, then remove this comment (negate as needed)
+       else if (self.spawnflags & 8) // Y (untested)
+               self.avelocity = '1 0 0' * self.speed;
+       // FIXME: test if this turns the right way, then remove this comment (negate as needed)
+       else // Z
+               self.avelocity = '0 1 0' * self.speed;
+
+       self.pos1 = self.avelocity;
+
+    if(self.dmg && (self.message == ""))
+        self.message = " was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+
+
+    if(self.dmg && (!self.dmgtime))
+        self.dmgtime = 0.25;
+
+    self.dmgtime2 = time;
+
+       if (!InitMovingBrushTrigger())
+               return;
+       // no EF_LOWPRECISION here, as rounding angles is bad
+
+    self.blocked = generic_plat_blocked;
+
+       // wait for targets to spawn
+       self.nextthink = self.ltime + 999999999;
+       self.think = SUB_NullThink; // for PushMove
+
+       // TODO make a reset function for this one
+}
+
+.float height;
+void func_bobbing_controller_think()
+{
+       vector v;
+       self.nextthink = time + 0.1;
+
+       if(self.owner.active != ACTIVE_ACTIVE)
+       {
+               self.owner.velocity = '0 0 0';
+               return;
+       }
+
+       // calculate sinewave using makevectors
+       makevectors((self.nextthink * self.owner.cnt + self.owner.phase * 360) * '0 1 0');
+       v = self.owner.destvec + self.owner.movedir * v_forward.y;
+       if(self.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed
+               // * 10 so it will arrive in 0.1 sec
+               self.owner.velocity = (v - self.owner.origin) * 10;
+}
+
+/*QUAKED spawnfunc_func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
+Brush model that moves back and forth on one axis (default Z).
+speed : how long one cycle takes in seconds (default 4)
+height : how far the cycle moves (default 32)
+phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
+noise : path/name of looping .wav file to play.
+dmg : Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime : See above.
+*/
+void spawnfunc_func_bobbing()
+{
+       entity controller;
+       if (self.noise != "")
+       {
+               precache_sound(self.noise);
+               soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+       }
+       if (!self.speed)
+               self.speed = 4;
+       if (!self.height)
+               self.height = 32;
+       // center of bobbing motion
+       self.destvec = self.origin;
+       // time scale to get degrees
+       self.cnt = 360 / self.speed;
+
+       self.active = ACTIVE_ACTIVE;
+
+       // damage when blocked
+       self.blocked = generic_plat_blocked;
+       if(self.dmg && (self.message == ""))
+               self.message = " was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+       if(self.dmg && (!self.dmgtime))
+               self.dmgtime = 0.25;
+       self.dmgtime2 = time;
+
+       // how far to bob
+       if (self.spawnflags & 1) // X
+               self.movedir = '1 0 0' * self.height;
+       else if (self.spawnflags & 2) // Y
+               self.movedir = '0 1 0' * self.height;
+       else // Z
+               self.movedir = '0 0 1' * self.height;
+
+       if (!InitMovingBrushTrigger())
+               return;
+
+       // wait for targets to spawn
+       controller = spawn();
+       controller.classname = "func_bobbing_controller";
+       controller.owner = self;
+       controller.nextthink = time + 1;
+       controller.think = func_bobbing_controller_think;
+       self.nextthink = self.ltime + 999999999;
+       self.think = SUB_NullThink; // for PushMove
+
+       // Savage: Reduce bandwith, critical on e.g. nexdm02
+       self.effects |= EF_LOWPRECISION;
+
+       // TODO make a reset function for this one
+}
+
+.float freq;
+void func_pendulum_controller_think()
+{
+       float v;
+       self.nextthink = time + 0.1;
+
+       if (!(self.owner.active == ACTIVE_ACTIVE))
+       {
+               self.owner.avelocity_x = 0;
+               return;
+       }
+
+       // calculate sinewave using makevectors
+       makevectors((self.nextthink * self.owner.freq + self.owner.phase) * '0 360 0');
+       v = self.owner.speed * v_forward.y + self.cnt;
+       if(self.owner.classname == "func_pendulum") // don't brake stuff if the func_bobbing was killtarget'ed
+       {
+               // * 10 so it will arrive in 0.1 sec
+               self.owner.avelocity_z = (remainder(v - self.owner.angles.z, 360)) * 10;
+       }
+}
+
+void spawnfunc_func_pendulum()
+{
+       entity controller;
+       if (self.noise != "")
+       {
+               precache_sound(self.noise);
+               soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+       }
+
+       self.active = ACTIVE_ACTIVE;
+
+       // keys: angle, speed, phase, noise, freq
+
+       if(!self.speed)
+               self.speed = 30;
+       // not initializing self.dmg to 2, to allow damageless pendulum
+
+       if(self.dmg && (self.message == ""))
+               self.message = " was squished";
+       if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+       if(self.dmg && (!self.dmgtime))
+               self.dmgtime = 0.25;
+       self.dmgtime2 = time;
+
+       self.blocked = generic_plat_blocked;
+
+       self.avelocity_z = 0.0000001;
+       if (!InitMovingBrushTrigger())
+               return;
+
+       if(!self.freq)
+       {
+               // find pendulum length (same formula as Q3A)
+               self.freq = 1 / (M_PI * 2) * sqrt(autocvar_sv_gravity / (3 * max(8, fabs(self.mins.z))));
+       }
+
+       // copy initial angle
+       self.cnt = self.angles.z;
+
+       // wait for targets to spawn
+       controller = spawn();
+       controller.classname = "func_pendulum_controller";
+       controller.owner = self;
+       controller.nextthink = time + 1;
+       controller.think = func_pendulum_controller_think;
+       self.nextthink = self.ltime + 999999999;
+       self.think = SUB_NullThink; // for PushMove
+
+       //self.effects |= EF_LOWPRECISION;
+
+       // TODO make a reset function for this one
+}
+
+// button and multiple button
+
+void() button_wait;
+void() button_return;
+
+void button_wait()
+{
+       self.state = STATE_TOP;
+       self.nextthink = self.ltime + self.wait;
+       self.think = button_return;
+       activator = self.enemy;
+       SUB_UseTargets();
+       self.frame = 1;                 // use alternate textures
+}
+
+void button_done()
+{
+       self.state = STATE_BOTTOM;
+}
+
+void button_return()
+{
+       self.state = STATE_DOWN;
+       SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, button_done);
+       self.frame = 0;                 // use normal textures
+       if (self.health)
+               self.takedamage = DAMAGE_YES;   // can be shot again
+}
+
+
+void button_blocked()
+{
+       // do nothing, just don't come all the way back out
+}
+
+
+void button_fire()
+{
+       self.health = self.max_health;
+       self.takedamage = DAMAGE_NO;    // will be reset upon return
+
+       if (self.state == STATE_UP || self.state == STATE_TOP)
+               return;
+
+       if (self.noise != "")
+               sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+
+       self.state = STATE_UP;
+       SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, button_wait);
+}
+
+void button_reset()
+{
+       self.health = self.max_health;
+       setorigin(self, self.pos1);
+       self.frame = 0;                 // use normal textures
+       self.state = STATE_BOTTOM;
+       if (self.health)
+               self.takedamage = DAMAGE_YES;   // can be shot again
+}
+
+void button_use()
+{
+       if(self.active != ACTIVE_ACTIVE)
+               return;
+
+       self.enemy = activator;
+       button_fire ();
+}
+
+void button_touch()
+{
+       if (!other)
+               return;
+       if (!other.iscreature)
+               return;
+       if(other.velocity * self.movedir < 0)
+               return;
+       self.enemy = other;
+       if (other.owner)
+               self.enemy = other.owner;
+       button_fire ();
+}
+
+void button_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       if(self.spawnflags & DOOR_NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       self.health = self.health - damage;
+       if (self.health <= 0)
+       {
+               self.enemy = damage_attacker;
+               button_fire ();
+       }
+}
+
+
+/*QUAKED spawnfunc_func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle"                determines the opening direction
+"target"       all entities with a matching targetname will be used
+"speed"                override the default 40 speed
+"wait"         override the default 1 second wait (-1 = never return)
+"lip"          override the default 4 pixel lip remaining at end of move
+"health"       if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the InstaGib laser
+"sounds"
+0) steam metal
+1) wooden clunk
+2) metallic click
+3) in-out
+*/
+void spawnfunc_func_button()
+{
+       SetMovedir ();
+
+       if (!InitMovingBrushTrigger())
+               return;
+       self.effects |= EF_LOWPRECISION;
+
+       self.blocked = button_blocked;
+       self.use = button_use;
+
+//     if (self.health == 0) // all buttons are now shootable
+//             self.health = 10;
+       if (self.health)
+       {
+               self.max_health = self.health;
+               self.event_damage = button_damage;
+               self.takedamage = DAMAGE_YES;
+       }
+       else
+               self.touch = button_touch;
+
+       if (!self.speed)
+               self.speed = 40;
+       if (!self.wait)
+               self.wait = 1;
+       if (!self.lip)
+               self.lip = 4;
+
+    if(self.noise != "")
+        precache_sound(self.noise);
+
+       self.active = ACTIVE_ACTIVE;
+
+       self.pos1 = self.origin;
+       self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
+    self.flags |= FL_NOTARGET;
+
+       button_reset();
+}
+
+
+const float DOOR_START_OPEN = 1;
+const float DOOR_DONT_LINK = 4;
+const float DOOR_TOGGLE = 32;
+
+/*
+
+Doors are similar to buttons, but can spawn a fat trigger field around them
+to open without a touch, and they link together to form simultanious
+double/quad doors.
+
+Door.owner is the master door.  If there is only one door, it points to itself.
+If multiple doors, all will point to a single one.
+
+Door.enemy chains from the master door through all doors linked in the chain.
+
+*/
+
+/*
+=============================================================================
+
+THINK FUNCTIONS
+
+=============================================================================
+*/
+
+void() door_go_down;
+void() door_go_up;
+void() door_rotating_go_down;
+void() door_rotating_go_up;
+
+void door_blocked()
+{
+
+    if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
+        Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+    } else {
+
+        if((self.dmg) && (other.takedamage == DAMAGE_YES))    // Shall we bite?
+            Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+
+         //Dont chamge direction for dead or dying stuff
+        if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
+            if (self.wait >= 0)
+            {
+                if (self.state == STATE_DOWN)
+                       if (self.classname == "door")
+                       {
+                               door_go_up ();
+                       } else
+                       {
+                               door_rotating_go_up ();
+                       }
+                else
+                       if (self.classname == "door")
+                       {
+                               door_go_down ();
+                       } else
+                       {
+                               door_rotating_go_down ();
+                       }
+            }
+        } else {
+            //gib dying stuff just to make sure
+            if((self.dmg) && (other.takedamage != DAMAGE_NO))    // Shall we bite?
+                Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+        }
+    }
+
+       //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
+// if a door has a negative wait, it would never come back if blocked,
+// so let it just squash the object to death real fast
+/*     if (self.wait >= 0)
+       {
+               if (self.state == STATE_DOWN)
+                       door_go_up ();
+               else
+                       door_go_down ();
+       }
+*/
+}
+
+
+void door_hit_top()
+{
+       if (self.noise1 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       self.state = STATE_TOP;
+       if (self.spawnflags & DOOR_TOGGLE)
+               return;         // don't come down automatically
+       if (self.classname == "door")
+       {
+               self.think = door_go_down;
+       } else
+       {
+               self.think = door_rotating_go_down;
+       }
+       self.nextthink = self.ltime + self.wait;
+}
+
+void door_hit_bottom()
+{
+       if (self.noise1 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       self.state = STATE_BOTTOM;
+}
+
+void door_go_down()
+{
+       if (self.noise2 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       if (self.max_health)
+       {
+               self.takedamage = DAMAGE_YES;
+               self.health = self.max_health;
+       }
+
+       self.state = STATE_DOWN;
+       SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, door_hit_bottom);
+}
+
+void door_go_up()
+{
+       if (self.state == STATE_UP)
+               return;         // already going up
+
+       if (self.state == STATE_TOP)
+       {       // reset top wait time
+               self.nextthink = self.ltime + self.wait;
+               return;
+       }
+
+       if (self.noise2 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       self.state = STATE_UP;
+       SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, door_hit_top);
+
+       string oldmessage;
+       oldmessage = self.message;
+       self.message = "";
+       SUB_UseTargets();
+       self.message = oldmessage;
+}
+
+
+
+/*
+=============================================================================
+
+ACTIVATION FUNCTIONS
+
+=============================================================================
+*/
+
+float door_check_keys(void) {
+       entity door = self.owner ? self.owner : self;
+
+       // no key needed
+       if (!door.itemkeys)
+               return true;
+
+       // this door require a key
+       // only a player can have a key
+       if (!IS_PLAYER(other))
+               return false;
+
+       if (item_keys_usekey(door, other)) {
+               // some keys were used
+               if (other.key_door_messagetime <= time) {
+                       play2(other, "misc/talk.wav");
+                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
+                       other.key_door_messagetime = time + 2;
+               }
+       } else {
+               // no keys were used
+               if (other.key_door_messagetime <= time) {
+                       play2(other, "misc/talk.wav");
+                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
+                       other.key_door_messagetime = time + 2;
+               }
+       }
+
+       if (door.itemkeys) {
+               // door is now unlocked
+               play2(other, "misc/talk.wav");
+               Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_UNLOCKED);
+               return true;
+       } else
+               return false;
+}
+
+
+void door_fire()
+{
+       entity  oself;
+       entity  starte;
+
+       if (self.owner != self)
+               objerror ("door_fire: self.owner != self");
+
+       oself = self;
+
+       if (self.spawnflags & DOOR_TOGGLE)
+       {
+               if (self.state == STATE_UP || self.state == STATE_TOP)
+               {
+                       starte = self;
+                       do
+                       {
+                               if (self.classname == "door")
+                               {
+                                       door_go_down ();
+                               }
+                               else
+                               {
+                                       door_rotating_go_down ();
+                               }
+                               self = self.enemy;
+                       } while ( (self != starte) && (self != world) );
+                       self = oself;
+                       return;
+               }
+       }
+
+// trigger all paired doors
+       starte = self;
+       do
+       {
+               if (self.classname == "door")
+               {
+                       door_go_up ();
+               } else
+               {
+                       // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
+                       if ((self.spawnflags & 2) && other.trigger_reverse!=0 && self.lip!=666 && self.state == STATE_BOTTOM)
+                       {
+                               self.lip = 666; // self.lip is used to remember reverse opening direction for door_rotating
+                               self.pos2 = '0 0 0' - self.pos2;
+                       }
+                       // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
+                       if (!((self.spawnflags & 2) &&  (self.spawnflags & 8) && self.state == STATE_DOWN
+                           && (((self.lip==666) && (other.trigger_reverse==0)) || ((self.lip!=666) && (other.trigger_reverse!=0)))))
+                       {
+                               door_rotating_go_up ();
+                       }
+               }
+               self = self.enemy;
+       } while ( (self != starte) && (self != world) );
+       self = oself;
+}
+
+
+void door_use()
+{
+       entity oself;
+
+       //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
+
+       if (self.owner)
+       {
+               oself = self;
+               self = self.owner;
+               door_fire ();
+               self = oself;
+       }
+}
+
+
+void door_trigger_touch()
+{
+       if (other.health < 1)
+               if (!(other.iscreature && other.deadflag == DEAD_NO))
+                       return;
+
+       if (time < self.attack_finished_single)
+               return;
+
+       // check if door is locked
+       if (!door_check_keys())
+               return;
+
+       self.attack_finished_single = time + 1;
+
+       activator = other;
+
+       self = self.owner;
+       door_use ();
+}
+
+
+void door_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       entity oself;
+       if(self.spawnflags & DOOR_NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       self.health = self.health - damage;
+
+       if (self.itemkeys) {
+               // don't allow opening doors through damage if keys are required
+               return;
+       }
+
+       if (self.health <= 0)
+       {
+               oself = self;
+               self = self.owner;
+               self.health = self.max_health;
+               self.takedamage = DAMAGE_NO;    // wil be reset upon return
+               door_use ();
+               self = oself;
+       }
+}
+
+
+/*
+================
+door_touch
+
+Prints messages
+================
+*/
+void door_touch()
+{
+       if (!IS_PLAYER(other))
+               return;
+       if (self.owner.attack_finished_single > time)
+               return;
+
+       self.owner.attack_finished_single = time + 2;
+
+       if (!(self.owner.dmg) && (self.owner.message != ""))
+       {
+               if (IS_CLIENT(other))
+                       centerprint(other, self.owner.message);
+               play2(other, "misc/talk.wav");
+       }
+}
+
+
+void door_generic_plat_blocked()
+{
+
+    if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
+        Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+    } else {
+
+        if((self.dmg) && (other.takedamage == DAMAGE_YES))    // Shall we bite?
+            Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+
+         //Dont chamge direction for dead or dying stuff
+        if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
+            if (self.wait >= 0)
+            {
+                if (self.state == STATE_DOWN)
+                    door_rotating_go_up ();
+                else
+                    door_rotating_go_down ();
+            }
+        } else {
+            //gib dying stuff just to make sure
+            if((self.dmg) && (other.takedamage != DAMAGE_NO))    // Shall we bite?
+                Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+        }
+    }
+
+       //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
+// if a door has a negative wait, it would never come back if blocked,
+// so let it just squash the object to death real fast
+/*     if (self.wait >= 0)
+       {
+               if (self.state == STATE_DOWN)
+                       door_rotating_go_up ();
+               else
+                       door_rotating_go_down ();
+       }
+*/
+}
+
+
+void door_rotating_hit_top()
+{
+       if (self.noise1 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       self.state = STATE_TOP;
+       if (self.spawnflags & DOOR_TOGGLE)
+               return;         // don't come down automatically
+       self.think = door_rotating_go_down;
+       self.nextthink = self.ltime + self.wait;
+}
+
+void door_rotating_hit_bottom()
+{
+       if (self.noise1 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       if (self.lip==666) // self.lip is used to remember reverse opening direction for door_rotating
+       {
+               self.pos2 = '0 0 0' - self.pos2;
+               self.lip = 0;
+       }
+       self.state = STATE_BOTTOM;
+}
+
+void door_rotating_go_down()
+{
+       if (self.noise2 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       if (self.max_health)
+       {
+               self.takedamage = DAMAGE_YES;
+               self.health = self.max_health;
+       }
+
+       self.state = STATE_DOWN;
+       SUB_CalcAngleMove (self.pos1, TSPEED_LINEAR, self.speed, door_rotating_hit_bottom);
+}
+
+void door_rotating_go_up()
+{
+       if (self.state == STATE_UP)
+               return;         // already going up
+
+       if (self.state == STATE_TOP)
+       {       // reset top wait time
+               self.nextthink = self.ltime + self.wait;
+               return;
+       }
+       if (self.noise2 != "")
+               sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       self.state = STATE_UP;
+       SUB_CalcAngleMove (self.pos2, TSPEED_LINEAR, self.speed, door_rotating_hit_top);
+
+       string oldmessage;
+       oldmessage = self.message;
+       self.message = "";
+       SUB_UseTargets();
+       self.message = oldmessage;
+}
+
+
+
+
+/*
+=============================================================================
+
+SPAWNING FUNCTIONS
+
+=============================================================================
+*/
+
+
+entity spawn_field(vector fmins, vector fmaxs)
+{
+       entity  trigger;
+       vector  t1, t2;
+
+       trigger = spawn();
+       trigger.classname = "doortriggerfield";
+       trigger.movetype = MOVETYPE_NONE;
+       trigger.solid = SOLID_TRIGGER;
+       trigger.owner = self;
+       trigger.touch = door_trigger_touch;
+
+       t1 = fmins;
+       t2 = fmaxs;
+       setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
+       return (trigger);
+}
+
+
+entity LinkDoors_nextent(entity cur, entity near, entity pass)
+{
+       while((cur = find(cur, classname, self.classname)) && ((cur.spawnflags & 4) || cur.enemy))
+       {
+       }
+       return cur;
+}
+
+float LinkDoors_isconnected(entity e1, entity e2, entity pass)
+{
+       float DELTA = 4;
+       if (e1.absmin.x > e2.absmax.x + DELTA)
+               return false;
+       if (e1.absmin.y > e2.absmax.y + DELTA)
+               return false;
+       if (e1.absmin.z > e2.absmax.z + DELTA)
+               return false;
+       if (e2.absmin.x > e1.absmax.x + DELTA)
+               return false;
+       if (e2.absmin.y > e1.absmax.y + DELTA)
+               return false;
+       if (e2.absmin.z > e1.absmax.z + DELTA)
+               return false;
+       return true;
+}
+
+/*
+=============
+LinkDoors
+
+
+=============
+*/
+void LinkDoors()
+{
+       entity  t;
+       vector  cmins, cmaxs;
+
+       if (self.enemy)
+               return;         // already linked by another door
+       if (self.spawnflags & 4)
+       {
+               self.owner = self.enemy = self;
+
+               if (self.health)
+                       return;
+               IFTARGETED
+                       return;
+               if (self.items)
+                       return;
+               self.trigger_field = spawn_field(self.absmin, self.absmax);
+
+               return;         // don't want to link this door
+       }
+
+       FindConnectedComponent(self, enemy, LinkDoors_nextent, LinkDoors_isconnected, world);
+
+       // set owner, and make a loop of the chain
+       dprint("LinkDoors: linking doors:");
+       for(t = self; ; t = t.enemy)
+       {
+               dprint(" ", etos(t));
+               t.owner = self;
+               if(t.enemy == world)
+               {
+                       t.enemy = self;
+                       break;
+               }
+       }
+       dprint("\n");
+
+       // collect health, targetname, message, size
+       cmins = self.absmin;
+       cmaxs = self.absmax;
+       for(t = self; ; t = t.enemy)
+       {
+               if(t.health && !self.health)
+                       self.health = t.health;
+               if((t.targetname != "") && (self.targetname == ""))
+                       self.targetname = t.targetname;
+               if((t.message != "") && (self.message == ""))
+                       self.message = t.message;
+               if (t.absmin.x < cmins.x)
+                       cmins.x = t.absmin.x;
+               if (t.absmin.y < cmins.y)
+                       cmins.y = t.absmin.y;
+               if (t.absmin.z < cmins.z)
+                       cmins.z = t.absmin.z;
+               if (t.absmax.x > cmaxs.x)
+                       cmaxs.x = t.absmax.x;
+               if (t.absmax.y > cmaxs.y)
+                       cmaxs.y = t.absmax.y;
+               if (t.absmax.z > cmaxs.z)
+                       cmaxs.z = t.absmax.z;
+               if(t.enemy == self)
+                       break;
+       }
+
+       // distribute health, targetname, message
+       for(t = self; t; t = t.enemy)
+       {
+               t.health = self.health;
+               t.targetname = self.targetname;
+               t.message = self.message;
+               if(t.enemy == self)
+                       break;
+       }
+
+       // shootable, or triggered doors just needed the owner/enemy links,
+       // they don't spawn a field
+
+       if (self.health)
+               return;
+       IFTARGETED
+               return;
+       if (self.items)
+               return;
+
+       self.trigger_field = spawn_field(cmins, cmaxs);
+}
+
+
+/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+
+GOLD_KEY causes the door to open only if the activator holds a gold key.
+
+SILVER_KEY causes the door to open only if the activator holds a silver key.
+
+"message"      is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"                determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"       if set, door must be shot open
+"speed"                movement speed (100 default)
+"wait"         wait before returning (3 default, -1 = never return)
+"lip"          lip remaining at end of move (8 default)
+"dmg"          damage to inflict when blocked (2 default)
+"sounds"
+0)     no sound
+1)     stone
+2)     base
+3)     stone chain
+4)     screechy metal
+FIXME: only one sound set available at the time being
+
+*/
+
+void door_init_startopen()
+{
+       setorigin (self, self.pos2);
+       self.pos2 = self.pos1;
+       self.pos1 = self.origin;
+}
+
+void door_reset()
+{
+       setorigin(self, self.pos1);
+       self.velocity = '0 0 0';
+       self.state = STATE_BOTTOM;
+       self.think = func_null;
+       self.nextthink = 0;
+}
+
+// spawnflags require key (for now only func_door)
+const float SPAWNFLAGS_GOLD_KEY = 8;
+const float SPAWNFLAGS_SILVER_KEY = 16;
+void spawnfunc_func_door()
+{
+       // Quake 1 keys compatibility
+       if (self.spawnflags & SPAWNFLAGS_GOLD_KEY)
+               self.itemkeys |= ITEM_KEY_BIT(0);
+       if (self.spawnflags & SPAWNFLAGS_SILVER_KEY)
+               self.itemkeys |= ITEM_KEY_BIT(1);
+
+       //if (!self.deathtype) // map makers can override this
+       //      self.deathtype = " got in the way";
+       SetMovedir ();
+
+       self.max_health = self.health;
+       if (!InitMovingBrushTrigger())
+               return;
+       self.effects |= EF_LOWPRECISION;
+       self.classname = "door";
+
+       self.blocked = door_blocked;
+       self.use = door_use;
+
+       // FIXME: undocumented flag 8, originally (Q1) GOLD_KEY
+       // if(self.spawnflags & 8)
+       //      self.dmg = 10000;
+
+    if(self.dmg && (self.message == ""))
+               self.message = "was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+
+       if (self.sounds > 0)
+       {
+               precache_sound ("plats/medplat1.wav");
+               precache_sound ("plats/medplat2.wav");
+               self.noise2 = "plats/medplat1.wav";
+               self.noise1 = "plats/medplat2.wav";
+       }
+
+       if (!self.speed)
+               self.speed = 100;
+       if (!self.wait)
+               self.wait = 3;
+       if (!self.lip)
+               self.lip = 8;
+
+       self.pos1 = self.origin;
+       self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+       if (self.spawnflags & DOOR_START_OPEN)
+               InitializeEntity(self, door_init_startopen, INITPRIO_SETLOCATION);
+
+       self.state = STATE_BOTTOM;
+
+       if (self.health)
+       {
+               self.takedamage = DAMAGE_YES;
+               self.event_damage = door_damage;
+       }
+
+       if (self.items)
+               self.wait = -1;
+
+       self.touch = door_touch;
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+       InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
+
+       self.reset = door_reset;
+}
+
+/*QUAKED spawnfunc_func_door_rotating (0 .5 .8) ? START_OPEN BIDIR DOOR_DONT_LINK BIDIR_IN_DOWN x TOGGLE X_AXIS Y_AXIS
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor.
+The usage of bidirectional doors requires two manually instantiated triggers (trigger_multiple), the one to open it in the other direction
+must have set trigger_reverse to 1.
+BIDIR_IN_DOWN will the door prevent from reopening while closing if it is triggered from the other side.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
+
+"message"      is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"                determines the destination angle for opening. negative values reverse the direction.
+"targetname"    if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"       if set, door must be shot open
+"speed"                movement speed (100 default)
+"wait"         wait before returning (3 default, -1 = never return)
+"dmg"          damage to inflict when blocked (2 default)
+"sounds"
+0)     no sound
+1)     stone
+2)     base
+3)     stone chain
+4)     screechy metal
+FIXME: only one sound set available at the time being
+*/
+
+void door_rotating_reset()
+{
+       self.angles = self.pos1;
+       self.avelocity = '0 0 0';
+       self.state = STATE_BOTTOM;
+       self.think = func_null;
+       self.nextthink = 0;
+}
+
+void door_rotating_init_startopen()
+{
+       self.angles = self.movedir;
+       self.pos2 = '0 0 0';
+       self.pos1 = self.movedir;
+}
+
+
+void spawnfunc_func_door_rotating()
+{
+
+       //if (!self.deathtype) // map makers can override this
+       //      self.deathtype = " got in the way";
+
+       // I abuse "movedir" for denoting the axis for now
+       if (self.spawnflags & 64) // X (untested)
+               self.movedir = '0 0 1';
+       else if (self.spawnflags & 128) // Y (untested)
+               self.movedir = '1 0 0';
+       else // Z
+               self.movedir = '0 1 0';
+
+       if (self.angles.y ==0) self.angles_y = 90;
+
+       self.movedir = self.movedir * self.angles.y;
+       self.angles = '0 0 0';
+
+       self.max_health = self.health;
+       self.avelocity = self.movedir;
+       if (!InitMovingBrushTrigger())
+               return;
+       self.velocity = '0 0 0';
+       //self.effects |= EF_LOWPRECISION;
+       self.classname = "door_rotating";
+
+       self.blocked = door_blocked;
+       self.use = door_use;
+
+    if(self.spawnflags & 8)
+        self.dmg = 10000;
+
+    if(self.dmg && (self.message == ""))
+               self.message = "was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+
+    if (self.sounds > 0)
+       {
+               precache_sound ("plats/medplat1.wav");
+               precache_sound ("plats/medplat2.wav");
+               self.noise2 = "plats/medplat1.wav";
+               self.noise1 = "plats/medplat2.wav";
+       }
+
+       if (!self.speed)
+               self.speed = 50;
+       if (!self.wait)
+               self.wait = 1;
+       self.lip = 0; // self.lip is used to remember reverse opening direction for door_rotating
+
+       self.pos1 = '0 0 0';
+       self.pos2 = self.movedir;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+       if (self.spawnflags & DOOR_START_OPEN)
+               InitializeEntity(self, door_rotating_init_startopen, INITPRIO_SETLOCATION);
+
+       self.state = STATE_BOTTOM;
+
+       if (self.health)
+       {
+               self.takedamage = DAMAGE_YES;
+               self.event_damage = door_damage;
+       }
+
+       if (self.items)
+               self.wait = -1;
+
+       self.touch = door_touch;
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+       InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
+
+       self.reset = door_rotating_reset;
+}
+
+/*
+=============================================================================
+
+SECRET DOORS
+
+=============================================================================
+*/
+
+void() fd_secret_move1;
+void() fd_secret_move2;
+void() fd_secret_move3;
+void() fd_secret_move4;
+void() fd_secret_move5;
+void() fd_secret_move6;
+void() fd_secret_done;
+
+const float SECRET_OPEN_ONCE = 1;              // stays open
+const float SECRET_1ST_LEFT = 2;               // 1st move is left of arrow
+const float SECRET_1ST_DOWN = 4;               // 1st move is down from arrow
+const float SECRET_NO_SHOOT = 8;               // only opened by trigger
+const float SECRET_YES_SHOOT = 16;     // shootable even if targeted
+
+void fd_secret_use()
+{
+       float temp;
+       string message_save;
+
+       self.health = 10000;
+       self.bot_attack = true;
+
+       // exit if still moving around...
+       if (self.origin != self.oldorigin)
+               return;
+
+       message_save = self.message;
+       self.message = ""; // no more message
+       SUB_UseTargets();                               // fire all targets / killtargets
+       self.message = message_save;
+
+       self.velocity = '0 0 0';
+
+       // Make a sound, wait a little...
+
+       if (self.noise1 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       self.nextthink = self.ltime + 0.1;
+
+       temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
+       makevectors(self.mangle);
+
+       if (!self.t_width)
+       {
+               if (self.spawnflags & SECRET_1ST_DOWN)
+                       self.t_width = fabs(v_up * self.size);
+               else
+                       self.t_width = fabs(v_right * self.size);
+       }
+
+       if (!self.t_length)
+               self.t_length = fabs(v_forward * self.size);
+
+       if (self.spawnflags & SECRET_1ST_DOWN)
+               self.dest1 = self.origin - v_up * self.t_width;
+       else
+               self.dest1 = self.origin + v_right * (self.t_width * temp);
+
+       self.dest2 = self.dest1 + v_forward * self.t_length;
+       SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move1);
+       if (self.noise2 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       fd_secret_use();
+}
+
+// Wait after first movement...
+void fd_secret_move1()
+{
+       self.nextthink = self.ltime + 1.0;
+       self.think = fd_secret_move2;
+       if (self.noise3 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+// Start moving sideways w/sound...
+void fd_secret_move2()
+{
+       if (self.noise2 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       SUB_CalcMove(self.dest2, TSPEED_LINEAR, self.speed, fd_secret_move3);
+}
+
+// Wait here until time to go back...
+void fd_secret_move3()
+{
+       if (self.noise3 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+       if (!(self.spawnflags & SECRET_OPEN_ONCE))
+       {
+               self.nextthink = self.ltime + self.wait;
+               self.think = fd_secret_move4;
+       }
+}
+
+// Move backward...
+void fd_secret_move4()
+{
+       if (self.noise2 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move5);
+}
+
+// Wait 1 second...
+void fd_secret_move5()
+{
+       self.nextthink = self.ltime + 1.0;
+       self.think = fd_secret_move6;
+       if (self.noise3 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_move6()
+{
+       if (self.noise2 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
+       SUB_CalcMove(self.oldorigin, TSPEED_LINEAR, self.speed, fd_secret_done);
+}
+
+void fd_secret_done()
+{
+       if (self.spawnflags&SECRET_YES_SHOOT)
+       {
+               self.health = 10000;
+               self.takedamage = DAMAGE_YES;
+               //self.th_pain = fd_secret_use;
+       }
+       if (self.noise3 != "")
+               sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+void secret_blocked()
+{
+       if (time < self.attack_finished_single)
+               return;
+       self.attack_finished_single = time + 0.5;
+       //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
+}
+
+/*
+==============
+secret_touch
+
+Prints messages
+================
+*/
+void secret_touch()
+{
+       if (!other.iscreature)
+               return;
+       if (self.attack_finished_single > time)
+               return;
+
+       self.attack_finished_single = time + 2;
+
+       if (self.message)
+       {
+               if (IS_CLIENT(other))
+                       centerprint(other, self.message);
+               play2(other, "misc/talk.wav");
+       }
+}
+
+void secret_reset()
+{
+       if (self.spawnflags&SECRET_YES_SHOOT)
+       {
+               self.health = 10000;
+               self.takedamage = DAMAGE_YES;
+       }
+       setorigin(self, self.oldorigin);
+       self.think = func_null;
+       self.nextthink = 0;
+}
+
+/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
+Basic secret door. Slides back, then to the side. Angle determines direction.
+wait  = # of seconds before coming back
+1st_left = 1st move is left of arrow
+1st_down = 1st move is down from arrow
+always_shoot = even if targeted, keep shootable
+t_width = override WIDTH to move back (or height if going down)
+t_length = override LENGTH to move sideways
+"dmg"          damage to inflict when blocked (2 default)
+
+If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
+"sounds"
+1) medieval
+2) metal
+3) base
+*/
+
+void spawnfunc_func_door_secret()
+{
+       /*if (!self.deathtype) // map makers can override this
+               self.deathtype = " got in the way";*/
+
+       if (!self.dmg)
+               self.dmg = 2;
+
+       // Magic formula...
+       self.mangle = self.angles;
+       self.angles = '0 0 0';
+       self.classname = "door";
+       if (!InitMovingBrushTrigger())
+               return;
+       self.effects |= EF_LOWPRECISION;
+
+       self.touch = secret_touch;
+       self.blocked = secret_blocked;
+       self.speed = 50;
+       self.use = fd_secret_use;
+       IFTARGETED
+       {
+       }
+       else
+               self.spawnflags |= SECRET_YES_SHOOT;
+
+       if(self.spawnflags&SECRET_YES_SHOOT)
+       {
+               self.health = 10000;
+               self.takedamage = DAMAGE_YES;
+               self.event_damage = fd_secret_damage;
+       }
+       self.oldorigin = self.origin;
+       if (!self.wait)
+               self.wait = 5;          // 5 seconds before closing
+
+       self.reset = secret_reset;
+       secret_reset();
+}
+
+/*QUAKED spawnfunc_func_fourier (0 .5 .8) ?
+Brush model that moves in a pattern of added up sine waves, can be used e.g. for circular motions.
+netname: list of <frequencymultiplier> <phase> <x> <y> <z> quadruples, separated by spaces; note that phase 0 represents a sine wave, and phase 0.25 a cosine wave (by default, it uses 1 0 0 0 1, to match func_bobbing's defaults
+speed: how long one cycle of frequency multiplier 1 in seconds (default 4)
+height: amplitude modifier (default 32)
+phase: cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
+noise: path/name of looping .wav file to play.
+dmg: Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime: See above.
+*/
+
+void func_fourier_controller_think()
+{
+       vector v;
+       float n, i, t;
+
+       self.nextthink = time + 0.1;
+       if(self.owner.active != ACTIVE_ACTIVE)
+       {
+               self.owner.velocity = '0 0 0';
+               return;
+       }
+
+
+       n = floor((tokenize_console(self.owner.netname)) / 5);
+       t = self.nextthink * self.owner.cnt + self.owner.phase * 360;
+
+       v = self.owner.destvec;
+
+       for(i = 0; i < n; ++i)
+       {
+               makevectors((t * stof(argv(i*5)) + stof(argv(i*5+1)) * 360) * '0 1 0');
+               v = v + ('1 0 0' * stof(argv(i*5+2)) + '0 1 0' * stof(argv(i*5+3)) + '0 0 1' * stof(argv(i*5+4))) * self.owner.height * v_forward.y;
+       }
+
+       if(self.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed
+               // * 10 so it will arrive in 0.1 sec
+               self.owner.velocity = (v - self.owner.origin) * 10;
+}
+
+void spawnfunc_func_fourier()
+{
+       entity controller;
+       if (self.noise != "")
+       {
+               precache_sound(self.noise);
+               soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+       }
+
+       if (!self.speed)
+               self.speed = 4;
+       if (!self.height)
+               self.height = 32;
+       self.destvec = self.origin;
+       self.cnt = 360 / self.speed;
+
+       self.blocked = generic_plat_blocked;
+       if(self.dmg && (self.message == ""))
+               self.message = " was squished";
+    if(self.dmg && (self.message2 == ""))
+               self.message2 = "was squished by";
+       if(self.dmg && (!self.dmgtime))
+               self.dmgtime = 0.25;
+       self.dmgtime2 = time;
+
+       if(self.netname == "")
+               self.netname = "1 0 0 0 1";
+
+       if (!InitMovingBrushTrigger())
+               return;
+
+       self.active = ACTIVE_ACTIVE;
+
+       // wait for targets to spawn
+       controller = spawn();
+       controller.classname = "func_fourier_controller";
+       controller.owner = self;
+       controller.nextthink = time + 1;
+       controller.think = func_fourier_controller_think;
+       self.nextthink = self.ltime + 999999999;
+       self.think = SUB_NullThink; // for PushMove
+
+       // Savage: Reduce bandwith, critical on e.g. nexdm02
+       self.effects |= EF_LOWPRECISION;
+
+       // TODO make a reset function for this one
+}
+
+// reusing some fields havocbots declared
+.entity wp00, wp01, wp02, wp03;
+
+.float targetfactor, target2factor, target3factor, target4factor;
+.vector targetnormal, target2normal, target3normal, target4normal;
+
+vector func_vectormamamam_origin(entity o, float t)
+{
+       vector v, p;
+       float f;
+       entity e;
+
+       f = o.spawnflags;
+       v = '0 0 0';
+
+       e = o.wp00;
+       if(e)
+       {
+               p = e.origin + t * e.velocity;
+               if(f & 1)
+                       v = v + (p * o.targetnormal) * o.targetnormal * o.targetfactor;
+               else
+                       v = v + (p - (p * o.targetnormal) * o.targetnormal) * o.targetfactor;
+       }
+
+       e = o.wp01;
+       if(e)
+       {
+               p = e.origin + t * e.velocity;
+               if(f & 2)
+                       v = v + (p * o.target2normal) * o.target2normal * o.target2factor;
+               else
+                       v = v + (p - (p * o.target2normal) * o.target2normal) * o.target2factor;
+       }
+
+       e = o.wp02;
+       if(e)
+       {
+               p = e.origin + t * e.velocity;
+               if(f & 4)
+                       v = v + (p * o.target3normal) * o.target3normal * o.target3factor;
+               else
+                       v = v + (p - (p * o.target3normal) * o.target3normal) * o.target3factor;
+       }
+
+       e = o.wp03;
+       if(e)
+       {
+               p = e.origin + t * e.velocity;
+               if(f & 8)
+                       v = v + (p * o.target4normal) * o.target4normal * o.target4factor;
+               else
+                       v = v + (p - (p * o.target4normal) * o.target4normal) * o.target4factor;
+       }
+
+       return v;
+}
+
+void func_vectormamamam_controller_think()
+{
+       self.nextthink = time + 0.1;
+
+       if(self.owner.active != ACTIVE_ACTIVE)
+       {
+               self.owner.velocity = '0 0 0';
+               return;
+       }
+
+       if(self.owner.classname == "func_vectormamamam") // don't brake stuff if the func_vectormamamam was killtarget'ed
+               self.owner.velocity = (self.owner.destvec + func_vectormamamam_origin(self.owner, 0.1) - self.owner.origin) * 10;
+}
+
+void func_vectormamamam_findtarget()
+{
+       if(self.target != "")
+               self.wp00 = find(world, targetname, self.target);
+
+       if(self.target2 != "")
+               self.wp01 = find(world, targetname, self.target2);
+
+       if(self.target3 != "")
+               self.wp02 = find(world, targetname, self.target3);
+
+       if(self.target4 != "")
+               self.wp03 = find(world, targetname, self.target4);
+
+       if(!self.wp00 && !self.wp01 && !self.wp02 && !self.wp03)
+               objerror("No reference entity found, so there is nothing to move. Aborting.");
+
+       self.destvec = self.origin - func_vectormamamam_origin(self, 0);
+
+       entity controller;
+       controller = spawn();
+       controller.classname = "func_vectormamamam_controller";
+       controller.owner = self;
+       controller.nextthink = time + 1;
+       controller.think = func_vectormamamam_controller_think;
+}
+
+void spawnfunc_func_vectormamamam()
+{
+       if (self.noise != "")
+       {
+               precache_sound(self.noise);
+               soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
+       }
+
+       if(!self.targetfactor)
+               self.targetfactor = 1;
+
+       if(!self.target2factor)
+               self.target2factor = 1;
+
+       if(!self.target3factor)
+               self.target3factor = 1;
+
+       if(!self.target4factor)
+               self.target4factor = 1;
+
+       if(vlen(self.targetnormal))
+               self.targetnormal = normalize(self.targetnormal);
+
+       if(vlen(self.target2normal))
+               self.target2normal = normalize(self.target2normal);
+
+       if(vlen(self.target3normal))
+               self.target3normal = normalize(self.target3normal);
+
+       if(vlen(self.target4normal))
+               self.target4normal = normalize(self.target4normal);
+
+       self.blocked = generic_plat_blocked;
+       if(self.dmg && (self.message == ""))
+               self.message = " was squished";
+    if(self.dmg && (self.message == ""))
+               self.message2 = "was squished by";
+       if(self.dmg && (!self.dmgtime))
+               self.dmgtime = 0.25;
+       self.dmgtime2 = time;
+
+       if(self.netname == "")
+               self.netname = "1 0 0 0 1";
+
+       if (!InitMovingBrushTrigger())
+               return;
+
+       // wait for targets to spawn
+       self.nextthink = self.ltime + 999999999;
+       self.think = SUB_NullThink; // for PushMove
+
+       // Savage: Reduce bandwith, critical on e.g. nexdm02
+       self.effects |= EF_LOWPRECISION;
+
+       self.active = ACTIVE_ACTIVE;
+
+       InitializeEntity(self, func_vectormamamam_findtarget, INITPRIO_FINDTARGET);
+}
+
+#endif
+
+void conveyor_think()
+{
+#ifdef CSQC
+       float dt = time - self.move_time;
+       self.move_time = time;
+       if(dt <= 0) { return; }
+#endif
+       entity e;
+
+       // set myself as current conveyor where possible
+       for(e = world; (e = findentity(e, conveyor, self)); )
+               e.conveyor = world;
+
+       if(self.state)
+       {
+               for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
+                       if(!e.conveyor.state)
+#ifdef SVQC
+                               if(isPushable(e))
+#elif defined(CSQC)
+                               if(e.isplayermodel)
+#endif
+                               {
+                                       vector emin = e.absmin;
+                                       vector emax = e.absmax;
+                                       if(self.solid == SOLID_BSP)
+                                       {
+                                               emin -= '1 1 1';
+                                               emax += '1 1 1';
+                                       }
+                                       if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
+                                               if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
+                                                       e.conveyor = self;
+                               }
+
+               for(e = world; (e = findentity(e, conveyor, self)); )
+               {
+#ifdef SVQC
+                       if(IS_CLIENT(e)) // doing it via velocity has quite some advantages
+                               continue; // done in SV_PlayerPhysics
+#elif defined(CSQC)
+                       if(e.isplayermodel)
+                               continue;
+#endif
+
+                       setorigin(e, e.origin + self.movedir * PHYS_INPUT_FRAMETIME);
+                       move_out_of_solid(e);
+#ifdef SVQC
+                       UpdateCSQCProjectile(e);
+#endif
+                       /*
+                       // stupid conveyor code
+                       tracebox(e.origin, e.mins, e.maxs, e.origin + self.movedir * sys_frametime, MOVE_NORMAL, e);
+                       if(trace_fraction > 0)
+                               setorigin(e, trace_endpos);
+                       */
+               }
+       }
+
+#ifdef SVQC
+       self.nextthink = time;
+#endif
+}
+
+#ifdef SVQC
+
+void conveyor_use()
+{
+       self.state = !self.state;
+
+       self.SendFlags |= 2;
+}
+
+void conveyor_reset()
+{
+       self.state = (self.spawnflags & 1);
+
+       self.SendFlags |= 2;
+}
+
+float conveyor_send(entity to, float sf)
+{
+       WriteByte(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
+       WriteByte(MSG_ENTITY, sf);
+
+       if(sf & 1)
+       {
+               WriteByte(MSG_ENTITY, self.warpzone_isboxy);
+               WriteCoord(MSG_ENTITY, self.origin_x);
+               WriteCoord(MSG_ENTITY, self.origin_y);
+               WriteCoord(MSG_ENTITY, self.origin_z);
+
+               WriteCoord(MSG_ENTITY, self.mins_x);
+               WriteCoord(MSG_ENTITY, self.mins_y);
+               WriteCoord(MSG_ENTITY, self.mins_z);
+               WriteCoord(MSG_ENTITY, self.maxs_x);
+               WriteCoord(MSG_ENTITY, self.maxs_y);
+               WriteCoord(MSG_ENTITY, self.maxs_z);
+
+               WriteCoord(MSG_ENTITY, self.movedir_x);
+               WriteCoord(MSG_ENTITY, self.movedir_y);
+               WriteCoord(MSG_ENTITY, self.movedir_z);
+
+               WriteByte(MSG_ENTITY, self.speed);
+               WriteByte(MSG_ENTITY, self.state);
+
+               WriteString(MSG_ENTITY, self.targetname);
+               WriteString(MSG_ENTITY, self.target);
+       }
+
+       if(sf & 2)
+               WriteByte(MSG_ENTITY, self.state);
+
+       return true;
+}
+
+void conveyor_init()
+{
+       if (!self.speed)
+               self.speed = 200;
+       self.movedir = self.movedir * self.speed;
+       self.think = conveyor_think;
+       self.nextthink = time;
+       IFTARGETED
+       {
+               self.use = conveyor_use;
+               self.reset = conveyor_reset;
+               conveyor_reset();
+       }
+       else
+               self.state = 1;
+
+       Net_LinkEntity(self, 0, false, conveyor_send);
+
+       self.SendFlags |= 1;
+}
+
+void spawnfunc_trigger_conveyor()
+{
+       SetMovedir();
+       EXACTTRIGGER_INIT;
+       conveyor_init();
+}
+
+void spawnfunc_func_conveyor()
+{
+       SetMovedir();
+       InitMovingBrushTrigger();
+       self.movetype = MOVETYPE_NONE;
+       conveyor_init();
+}
+
+#elif defined(CSQC)
+
+void conveyor_init()
+{
+       self.draw = conveyor_think;
+       self.drawmask = MASK_NORMAL;
+
+       self.movetype = MOVETYPE_NONE;
+       self.model = "";
+       self.solid = SOLID_TRIGGER;
+       self.move_origin = self.origin;
+       self.move_time = time;
+}
+
+void ent_conveyor()
+{
+       float sf = ReadByte();
+
+       if(sf & 1)
+       {
+               self.warpzone_isboxy = ReadByte();
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+               setorigin(self, self.origin);
+
+               self.mins_x = ReadCoord();
+               self.mins_y = ReadCoord();
+               self.mins_z = ReadCoord();
+               self.maxs_x = ReadCoord();
+               self.maxs_y = ReadCoord();
+               self.maxs_z = ReadCoord();
+               setsize(self, self.mins, self.maxs);
+
+               self.movedir_x = ReadCoord();
+               self.movedir_y = ReadCoord();
+               self.movedir_z = ReadCoord();
+
+               self.speed = ReadByte();
+               self.state = ReadByte();
+
+               self.targetname = strzone(ReadString());
+               self.target = strzone(ReadString());
+
+               conveyor_init();
+       }
+
+       if(sf & 2)
+               self.state = ReadByte();
+}
+
+#endif
index b948b203eeb36ac4a06d00b6a91ab038b6dc1be3..d86af8a00ec786760c15a9440b525a7160d4a0ab 100644 (file)
@@ -175,6 +175,20 @@ float tgamma(float x)
        return exp(v.x) * v.y;
 }
 
+/**
+ * Pythonic mod:
+ * TODO: %% operator?
+ *
+ *  1 %  2 ==  1
+ * -1 %  2 ==  1
+ *  1 % -2 == -1
+ * -1 % -2 == -1
+ */
+float pymod(float x, float y)
+{
+       return x - y * floor(x / y);
+}
+
 float nearbyint(float x)
 {
        return rint(x);
index 7eebd032c43d75c4d85f736518265115c34ef276..a37ba63de6c63b87ed3dad63d12ea1ad4637fe52 100644 (file)
@@ -60,6 +60,17 @@ float erfc(float x);
 vector lgamma(float x); // value in _x, sign in _y
 float tgamma(float x);
 
+/**
+ * Pythonic mod:
+ * TODO: %% operator?
+ *
+ *  1 %  2 ==  1
+ * -1 %  2 ==  1
+ *  1 % -2 == -1
+ * -1 % -2 == -1
+ */
+float pymod(float x, float y);
+
 //float ceil(float x);
 //float floor(float x);
 float nearbyint(float x);
index df09de330756e3c2a3f98966e95e54bd7989c6e2..503c23979284e6f796268c6dfbed02b885eec214 100644 (file)
@@ -4,6 +4,7 @@ Ant "Antibody" Zucaro
 Marvin "Mirio" Beck
 Merlijn Hofstra
 Peter "Morphed" Pielak
+Ruszkai "CuBe0wL" Ákos
 Samual "Ares" Lenks
 Tyler "-z-" Mulligan
 Zac "Mario" Jardine
@@ -19,6 +20,7 @@ Jan "zykure" Behrens
 JH0nny
 Łukasz "kuniu the frogg" Polek
 Matthias "matthiaskrgr" Krüger
+Mattia "Melanosuchus" Basaglia
 MrBougo
 Nick "bitbomb" Lucca
 nilyt/nyov
@@ -69,7 +71,7 @@ MintOX
 packer
 Pearce "theShadow" Michal
 Rasmus "FruitieX" Eskola
-Ruszkai "C.Brutail" Ákos
+Ruszkai "CuBe0wL" Ákos
 Severin "sev" Meyer
 
 *Music / Sound FX
@@ -96,7 +98,7 @@ Zac "Mario" Jardine
 
 *Marketing / PR
 Tyler "-z-" Mulligan
-Ruszkai "C.Brutail" Ákos
+Ruszkai "CuBe0wL" Ákos
 Samual "Ares" Lenks
 Saulo "mand1nga" Gil
 
@@ -123,7 +125,6 @@ Dale "graphitemaster" Weiler
 **Other Active Contributors
 Erik "Ablu" Schilling
 Jope "Sless" Withers
-Mattia "Melanosuchus" Basaglia
 Mircea "Taoki" Kitsune
 Robert "ai" Kuroto
 
@@ -143,19 +144,15 @@ set_killer
 
 *Czech
 shogun assassin/woky
+Tomáš "CZHeron" Volavka
 
 *Dutch
 Alexander "freefang" van Dam
 PinkRobot
 vegiburger
 
-*German
-cvcxc
-Erik "Ablu" Schilling
-Jope "Sless" Withers
-Marvin "Mirio" Beck
-Rudolf "divVerent" Polzer
-Yepoleb
+*English (Australia)
+Zac "Mario" Jardine
 
 *Finnish
 Henry "Exitium" Sanmark
@@ -167,6 +164,14 @@ Maxime "Taximus" Paradis
 RedGuff
 Yannick "SpiKe" Le Guen
 
+*German
+cvcxc
+Erik "Ablu" Schilling
+Jope "Sless" Withers
+Marvin "Mirio" Beck
+Rudolf "divVerent" Polzer
+Yepoleb
+
 *Greek
 Γιάννης "Evropi" Α.
 Konstantinos "LDinos" Mihalenas
@@ -174,7 +179,7 @@ Savoritias
 Vindex
 
 *Hungarian
-Ruszkai "C.Brutail" Ákos
+Ruszkai "CuBe0wL" Ákos
 xaN1C4n3
 
 *Japanese
@@ -188,6 +193,7 @@ XCostaX
 
 *Polish
 4m
+Alex "tiprogrammierer.alex" Progger
 Amadeusz "amade/proraide" Sławiński
 
 *Portuguese
@@ -197,9 +203,11 @@ xXxCHAOTICxXx
 *Romanian
 BusterDBK
 Mircea "Taoki" Kitsune
+Tudor "TropiKo" Ionel
 
 *Russian
 Alex "alextalker7" Talker
+Alexandr "zrg"
 Andrei "adem4ik" Stepanov
 gravicappa
 Hot Dog
@@ -218,7 +226,7 @@ Alan "aagp" Garcia
 Ari_tent
 brunodeleo
 Kammy
-roader_gentto
+roader_gentoo
 Rodrigo Mouton Laudin
 SouL