Merge branch 'master' into terencehill/unlimited_ammo_fixes
authorterencehill <piuntn@gmail.com>
Sun, 5 Apr 2015 22:54:48 +0000 (00:54 +0200)
committerterencehill <piuntn@gmail.com>
Sun, 5 Apr 2015 22:54:48 +0000 (00:54 +0200)
44 files changed:
bal-wep-xonotic.cfg
bal-wep-xpm.cfg
balance-xonotic.cfg
balance-xpm.cfg
defaultXonotic.cfg
mutators.cfg
qcsrc/client/effects.qc
qcsrc/client/hud.qc
qcsrc/client/tuba.qc
qcsrc/client/tuba.qh
qcsrc/client/view.qc
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/common/weapons/w_shockwave.qc
qcsrc/common/weapons/w_vaporizer.qc
qcsrc/dpdefs/csprogsdefs.qh
qcsrc/dpdefs/dpextensions.qh
qcsrc/dpdefs/menudefs.qh
qcsrc/menu/item/modalcontroller.qc
qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc
qcsrc/menu/xonotic/gametypelist.qc
qcsrc/menu/xonotic/slider_resolution.qc
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/util.qh
qcsrc/server/autocvars.qh
qcsrc/server/cl_client.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/defs.qh
qcsrc/server/func_breakable.qc
qcsrc/server/g_world.qc
qcsrc/server/ipban.qc
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/mutator_instagib.qc
qcsrc/server/mutators/mutator_nades.qc
qcsrc/server/mutators/mutator_overkill.qc
qcsrc/server/target_spawn.qc
qcsrc/warpzonelib/mathlib.qc
qcsrc/warpzonelib/mathlib.qh
qcsrc/warpzonelib/server.qc
qcsrc/warpzonelib/util_server.qc
xonotic-credits.txt

index 2e6d10e..1fa36d0 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 2e6d10e..1fa36d0 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 08ff39c..76ba515 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 c254bcd..e785528 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 034b3bb..4f02d14 100644 (file)
@@ -472,7 +472,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"
@@ -545,6 +545,7 @@ gl_picmip_other 1 // so, picmip -1 is best possible quality
 r_mipsprites 1
 r_mipskins 1
 r_shadow_realtime_world_lightmaps 1
+r_shadow_realtime_world_importlightentitiesfrommap 0 // Whether build process uses keepLights is nontransparent and may change, so better make keepLights not matter.
 cl_decals_fadetime 5
 cl_decals_time 1
 seta cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
index be5af23..2960588 100644 (file)
@@ -41,9 +41,9 @@ set g_overkill 0 "enable overkill"
 set g_overkill_100a_anyway 1
 set g_overkill_100h_anyway 1
 set g_overkill_powerups_replace 1
-set g_overkill_superguns_respawn_time 20
+set g_overkill_superguns_respawn_time 120
 
-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
@@ -175,6 +175,7 @@ set g_random_gravity_negative 1000 "negative gravity multiplier"
 //  Nades
 // =======
 set g_nades 0 "enable off-hand grenades"
+set g_nades_throw_offset "0 0 0" "nade throwing offset"
 set g_nades_spawn 1 "give nades right away when player spawns rather than delaying entire refire"
 set g_nades_client_select 0 "allow client side selection of nade type"
 set g_nades_nade_lifetime 3.5
index df68846..9562350 100644 (file)
@@ -46,7 +46,9 @@ void cl_effects_lightningarc(vector from, vector to,float seglength,float drifts
     if(length < 1)
         return;
 
-    steps      = floor(length / seglength);
+    // Use at most 16 te_lightning1 segments, as these eat up beam list segments.
+    // TODO: Change this to R_BeginPolygon code, then we no longer have this limit.
+    steps      = min(16, floor(length / seglength));
     if(steps < 1)
     {
         te_lightning1(world,from,to);
@@ -64,8 +66,9 @@ void cl_effects_lightningarc(vector from, vector to,float seglength,float drifts
             dirnew = normalize(direction * (1 - drift) + randomvec() * drift);
             pos = pos_l +  dirnew * steplength;
             te_lightning1(world,pos_l,pos);
-            if(random() < branchfactor)
-                cl_effects_lightningarc(pos, pos + (dirnew * length * 0.25),seglength,drifts,drifte,min(branchfactor + branchfactor_add,1),branchfactor_add);
+            // WTF endless recursion if branchfactor is 1.0 (possibly due to adding branchfactor_add). FIXME
+            // if(random() < branchfactor)
+            //     cl_effects_lightningarc(pos, pos + (dirnew * length * 0.25),seglength,drifts,drifte,min(branchfactor + branchfactor_add,1),branchfactor_add);
 
             pos_l = pos;
         }
index 024a076..a596208 100644 (file)
@@ -146,6 +146,46 @@ float HUD_GetRowCount(float item_count, vector size, float item_aspect)
        return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
 }
 
+vector HUD_GetTableSize(float item_count, vector psize, float item_aspect)
+{
+       float columns, rows;
+       float ratio, best_ratio = 0;
+       float best_columns = 1, best_rows = 1;
+       bool vertical = (psize.x / psize.y >= item_aspect);
+       if(vertical)
+       {
+               psize = eX * psize.y + eY * psize.x;
+               item_aspect = 1 / item_aspect;
+       }
+
+       rows = ceil(sqrt(item_count));
+       columns = ceil(item_count/rows);
+       while(columns >= 1)
+       {
+               ratio = (psize.x/columns) / (psize.y/rows);
+               if(ratio > item_aspect)
+                       ratio = item_aspect * item_aspect / ratio;
+
+               if(ratio <= best_ratio)
+                       break; // ratio starts decreasing by now, skip next configurations
+
+               best_columns = columns;
+               best_rows = rows;
+               best_ratio = ratio;
+
+               if(columns == 1)
+                       break;
+
+               --columns;
+               rows = ceil(item_count/columns);
+       }
+
+       if(vertical)
+               return eX * best_rows + eY * best_columns;
+       else
+               return eX * best_columns + eY * best_rows;
+}
+
 float stringwidth_colors(string s, vector theSize)
 {
        return stringwidth(s, true, theSize);
@@ -430,7 +470,8 @@ void HUD_Weapons(void)
        float screen_ar;
        vector center = '0 0 0';
        float weapon_count, weapon_id;
-       float row, column, rows = 0, columns;
+       float row, column, rows = 0, columns = 0;
+       bool vertical_order = true;
        float aspect = autocvar_hud_panel_weapons_aspect;
 
        float timeout = autocvar_hud_panel_weapons_timeout;
@@ -505,6 +546,17 @@ void HUD_Weapons(void)
                if(!weapons_stat)
                        for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
                                weapons_stat |= WepSet_FromWeapon(i);
+
+               #if 0
+               /// debug code
+               if(cvar("wep_add"))
+               {
+                       weapons_stat = '0 0 0';
+                       float countw = 1 + floor((floor(time * cvar("wep_add"))) % WEP_COUNT);
+                       for(i = WEP_FIRST; i <= countw; ++i)
+                               weapons_stat |= WepSet_FromWeapon(i);
+               }
+               #endif
        }
 
        // determine which weapons are going to be shown
@@ -522,6 +574,7 @@ void HUD_Weapons(void)
                        if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
                                ++weapon_count;
 
+
                // might as well commit suicide now, no reason to live ;)
                if (weapon_count == 0)
                {
@@ -530,35 +583,62 @@ void HUD_Weapons(void)
                }
 
                vector old_panel_size = panel_size;
-               if(panel_bg_padding)
-                       old_panel_size -= '2 2 0' * panel_bg_padding;
-
-               // NOTE: the goal is to use the all-weapons layout and remove unneeded cells
-               // this way weapon icons always have the same size regardless of owned weapon count
+               vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
 
                // get the all-weapons layout
-               rows = HUD_GetRowCount(WEP_COUNT, old_panel_size, aspect);
-               columns = ceil(WEP_COUNT/rows);
-               weapon_size.x = old_panel_size.x / columns;
-               weapon_size.y = old_panel_size.y / rows;
-
-               // reduce rows and columns as needed
-               columns = ceil(weapon_count / rows);
-               rows = ceil(weapon_count / columns);
+               vector table_size = HUD_GetTableSize(WEP_COUNT, padded_panel_size, aspect);
+               columns = table_size.x;
+               rows = table_size.y;
+               weapon_size.x = padded_panel_size.x / columns;
+               weapon_size.y = padded_panel_size.y / rows;
 
-               // NOTE: although weapons should aways look the same even if onlyowned is disabled,
+               // 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
-               // as they look much better
-               weapon_size.x = min(old_panel_size.x / columns, aspect * weapon_size.y);
-               weapon_size.y = min(old_panel_size.y / rows, weapon_size.x / aspect);
+               if(padded_panel_size.x / padded_panel_size.y < aspect)
+               {
+                       // maximum number of rows that allows to display items with the desired aspect ratio
+                       float max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
+                       columns = min(columns, ceil(weapon_count / max_rows));
+                       rows = ceil(weapon_count / columns);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       vertical_order = false;
+               }
+               else
+               {
+                       float max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
+                       rows = min(rows, ceil(weapon_count / max_columns));
+                       columns = ceil(weapon_count / rows);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       vertical_order = true;
+               }
 
                // reduce size of the panel
                panel_size.x = columns * weapon_size.x;
                panel_size.y = rows * weapon_size.y;
-               panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
-               panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
-               if(panel_bg_padding)
-                       panel_size += '2 2 0' * panel_bg_padding;
+               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;
@@ -669,9 +749,12 @@ void HUD_Weapons(void)
 
        if(!rows) // if rows is > 0 onlyowned code has already updated these vars
        {
-               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);
+               vector table_size = HUD_GetTableSize(WEP_COUNT, panel_size, aspect);
+               columns = table_size.x;
+               rows = table_size.y;
+               weapon_size.x = panel_size.x / columns;
+               weapon_size.y = panel_size.y / rows;
+               vertical_order = (panel_size.x / panel_size.y >= aspect);
        }
 
        // calculate position/size for visual bar displaying ammount of ammo status
@@ -828,12 +911,33 @@ void HUD_Weapons(void)
                        drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
                }
 
+               #if 0
+               /// debug code
+               if(!autocvar_hud_panel_weapons_onlyowned)
+               {
+                       drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
+                       drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               #endif
+
                // continue with new position for the next weapon
-               ++row;
-               if(row >= rows)
+               if(vertical_order)
                {
-                       row = 0;
                        ++column;
+                       if(column >= columns)
+                       {
+                               column = 0;
+                               ++row;
+                       }
+               }
+               else
+               {
+                       ++row;
+                       if(row >= rows)
+                       {
+                               row = 0;
+                               ++column;
+                       }
                }
        }
 
index dec0004..cd518e0 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 81517b4..bdc1386 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 ee8ef32..26e7093 100644 (file)
@@ -763,7 +763,7 @@ void UpdateCrosshair()
                wcross_alpha_goal_prev = wcross_alpha;
                wcross_color_goal_prev = wcross_color;
 
-               if(shottype == SHOTTYPE_HITTEAM || (shottype == SHOTTYPE_HITOBSTRUCTION && autocvar_crosshair_hittest_blur && !autocvar_chase_active))
+               if(spectatee_status == -1 && shottype == SHOTTYPE_HITTEAM || (shottype == SHOTTYPE_HITOBSTRUCTION && autocvar_crosshair_hittest_blur && !autocvar_chase_active))
                {
                        wcross_blur = 1;
                        wcross_alpha *= 0.75;
index 366f35e..c3f15d1 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 6083350..54255ec 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 99fecda..49d707f 100644 (file)
@@ -500,19 +500,6 @@ string ScoreString(int pFlags, float pValue)
        return valstr;
 }
 
-float dotproduct(vector a, vector b)
-{
-       return a.x * b.x + a.y * b.y + a.z * b.z;
-}
-
-vector cross(vector a, vector b)
-{
-       return
-               '1 0 0' * (a.y * b.z - a.z * b.y)
-       +       '0 1 0' * (a.z * b.x - a.x * b.z)
-       +       '0 0 1' * (a.x * b.y - a.y * b.x);
-}
-
 // compressed vector format:
 // like MD3, just even shorter
 //   4 bit pitch (16 angles), 0 is -90, 8 is 0, 16 would be 90
index 4de610f..b2cdf8d 100644 (file)
@@ -109,9 +109,6 @@ const float TIME_FACTOR = 100;
 
 string ScoreString(float vflags, float value);
 
-float dotproduct(vector a, vector b);
-vector cross(vector a, vector b);
-
 void compressShortVector_init();
 vector decompressShortVector(float data);
 float compressShortVector(vector vec);
index 24b8634..3f40c53 100644 (file)
@@ -553,13 +553,11 @@ void W_Shockwave_Attack(void)
                        center = CENTER_OR_VIEWOFS(head);
 
                        // find the closest point on the enemy to the center of the attack
-                       float ang; // angle between shotdir and h
                        float h; // hypotenuse, which is the distance between attacker to head
                        float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
 
                        h = vlen(center - self.origin);
-                       ang = acos(dotproduct(normalize(center - self.origin), w_shotdir));
-                       a = h * cos(ang);
+                       a = h * (normalize(center - self.origin) * w_shotdir);
                        // WEAPONTODO: replace with simpler method
 
                        vector nearest_on_line = (w_shotorg + a * w_shotdir);
index 14377ed..b67056f 100644 (file)
@@ -164,8 +164,10 @@ float W_Vaporizer(float req)
                                                W_DecreaseAmmo(WEP_CVAR_SEC(vaporizer, ammo));
 
                                        // ugly instagib hack to reuse the fire mode of the laser
+                                       int oldwep = self.weapon; // we can't avoid this hack
+                                       self.weapon = WEP_BLASTER;
                                        W_Blaster_Attack(
-                                               WEP_VAPORIZER | HITTYPE_SECONDARY,
+                                               WEP_BLASTER | HITTYPE_SECONDARY,
                                                WEP_CVAR_SEC(vaporizer, shotangle),
                                                WEP_CVAR_SEC(vaporizer, damage),
                                                WEP_CVAR_SEC(vaporizer, edgedamage),
@@ -176,6 +178,7 @@ float W_Vaporizer(float req)
                                                WEP_CVAR_SEC(vaporizer, delay),
                                                WEP_CVAR_SEC(vaporizer, lifetime)
                                        );
+                                       self.weapon = oldwep;
 
                                        // now do normal refire
                                        weapon_thinkf(WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready);
index 6f820c7..4effe64 100644 (file)
@@ -1420,6 +1420,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;
index 26d351a..109e919 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 83cb073..853fa25 100644 (file)
@@ -297,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;
@@ -347,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
@@ -524,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;
index bff2170..3ef6567 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 9f327c3..2c6f76f 100644 (file)
@@ -13,7 +13,7 @@ ENDCLASS(XonoticHUDConfirmDialog)
 void HUDSetup_Start(entity me, entity btn)
 {
        if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
-               localcmd("map hudsetup/hudsetup", "\n");
+               localcmd("map hudsetup", "\n");
        else
                localcmd("togglemenu 0\n");
 
index feb1d89..0d36c83 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 476c441..c144362 100644 (file)
@@ -7,6 +7,8 @@ CLASS(XonoticResolutionSlider) EXTENDS(XonoticTextSlider)
        METHOD(XonoticResolutionSlider, saveCvars, void(entity))
        METHOD(XonoticResolutionSlider, draw, void(entity))
        ATTRIB(XonoticResolutionSlider, vid_fullscreen, float, -1)
+       ATTRIB(XonoticResolutionSlider, maxAllowedWidth, float, 0)
+       ATTRIB(XonoticResolutionSlider, maxAllowedHeight, float, 0)
 ENDCLASS(XonoticResolutionSlider)
 entity makeXonoticResolutionSlider();
 float updateConwidths(float width, float height, float pixelheight);
@@ -87,6 +89,10 @@ entity makeXonoticResolutionSlider()
 }
 void XonoticResolutionSlider_addResolution(entity me, float w, float h, float pixelheight)
 {
+       if (me.maxAllowedWidth && w > me.maxAllowedWidth)
+               return;
+       if (me.maxAllowedHeight && h > me.maxAllowedHeight)
+               return;
        float i;
        for (i = 0; i < me.nValues; ++i)
        {
@@ -138,6 +144,8 @@ void XonoticResolutionSlider_loadResolutions(entity me, float fullscreen)
        }
        // NOW we can safely clear.
        me.clearValues(me);
+       me.maxAllowedWidth = 0;
+       me.maxAllowedHeight = 0;
 
        if (fullscreen)
        {
@@ -161,6 +169,21 @@ void XonoticResolutionSlider_loadResolutions(entity me, float fullscreen)
 
        if(me.nValues == 0)
        {
+               // Get workarea.
+               r = getresolution(-2);
+               // If workarea is not supported, get desktop size.
+               if(r.x == 0 && r.y == 0)
+                       r = getresolution(-1);
+
+               // Add it, and limit all other resolutions to the workarea/desktop size.
+               if(r.x != 0 || r.y != 0)
+               {
+                       me.maxAllowedWidth = r.x;
+                       me.maxAllowedHeight = r.y;
+                       me.addResolution(me, r.x, r.y, r.z);
+               }
+
+               // Add nice hardcoded defaults.
                me.addResolution(me, 640, 480, 1); // pc res
 #if 0
                me.addResolution(me, 720, 480, 1.125); // DVD NTSC 4:3
index 0846526..330b2bb 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 6407297..80803f8 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 bcb9d28..015c13f 100644 (file)
@@ -785,6 +785,7 @@ float autocvar_g_random_gravity_positive;
 float autocvar_g_random_gravity_negative;
 float autocvar_g_random_gravity_delay;
 float autocvar_g_nades;
+vector autocvar_g_nades_throw_offset;
 float autocvar_g_nades_spawn;
 float autocvar_g_nades_spawn_count;
 float autocvar_g_nades_client_select;
index 89647d5..3bc5cc7 100644 (file)
@@ -1000,7 +1000,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;
 
@@ -1249,6 +1249,13 @@ void ClientConnect (void)
        if(IS_REAL_CLIENT(self))
                sv_notice_join();
 
+       for (entity e = world; (e = findfloat(e, init_for_player_needed, 1)); ) {
+               entity oldself = self;
+               self = e;
+               e.init_for_player(oldself);
+               self = oldself;
+       }
+
        MUTATOR_CALLHOOK(ClientConnect);
 }
 /*
index 4a8b59e..14e0f20 100644 (file)
@@ -825,6 +825,15 @@ void ClientCommand_macro_write_aliases(float fh)
 
 void SV_ParseClientCommand(string command)
 {
+       // If invalid UTF-8, don't even parse it
+       string command2 = "";
+       float len = strlen(command);
+       float i;
+       for (i = 0; i < len; ++i)
+               command2 = strcat(command2, chr2str(str2chr(command, i)));
+       if (command != command2)
+               return;
+
        // if we're banned, don't even parse the command
        if(Ban_MaybeEnforceBanOnce(self))
                return;
index 6edccaf..61fd2f3 100644 (file)
@@ -235,7 +235,7 @@ void VoteCount(float first_count)
                switch(tmp_player.vote_selection)
                {
                        case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
-                       case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
+                       case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(IS_PLAYER(tmp_player)) ++vote_real_accept_count; } break; }
                        case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break; }
                        default: break;
                }
index 175179b..822c516 100644 (file)
@@ -623,4 +623,8 @@ const int MIF_GUIDED_TAG = 128;
 .string playernick;
 .float elos;
 .float ranks;
+
+.float init_for_player_needed;
+.void(entity) init_for_player;
+
 #endif
index c0e54d1..be6104f 100644 (file)
@@ -91,7 +91,7 @@ void func_breakable_look_destroyed()
                self.dropped_origin = self.origin;
 
        if(self.mdl_dead == "")
-               self.model = "";
+               self.effects |= EF_NODRAW;
        else {
                if (self.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
                        floorZ = self.absmin.z;
@@ -99,16 +99,24 @@ void func_breakable_look_destroyed()
                        self.origin_z = floorZ;
                }
                setmodel(self, self.mdl_dead);
+               self.effects &= ~EF_NODRAW;
        }
 
+       CSQCMODEL_AUTOUPDATE();
+
        self.solid = SOLID_NOT;
 }
 
 void func_breakable_look_restore()
 {
        setmodel(self, self.mdl);
+       self.effects &= ~EF_NODRAW;
+
        if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
                setorigin(self, self.dropped_origin);
+
+       CSQCMODEL_AUTOUPDATE();
+
        self.solid = SOLID_BSP;
 }
 
@@ -120,6 +128,8 @@ void func_breakable_behave_destroyed()
        self.event_damage = func_null;
        self.state = 1;
        func_breakable_colormod();
+       if (self.noise1)
+               stopsound (self, CH_TRIGGER_SINGLE);
 }
 
 void func_breakable_behave_restore()
@@ -136,6 +146,17 @@ void func_breakable_behave_restore()
        self.state = 0;
        self.nextthink = 0; // cancel auto respawn
        func_breakable_colormod();
+       if (self.noise1)
+               sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+}
+
+void func_breakable_init_for_player(entity player)
+{
+       if (self.noise1 && self.state == 0 && clienttype(player) == CLIENTTYPE_REAL)
+       {
+               msg_entity = player;
+               soundto (MSG_ONE, self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
+       }
 }
 
 void func_breakable_destroyed()
@@ -270,6 +291,8 @@ void spawnfunc_func_breakable() {
                precache_model(argv(i));
        if(self.noise)
                precache_sound(self.noise);
+       if(self.noise1)
+               precache_sound(self.noise1);
 
        self.team_saved = self.team;
        self.dropped_origin = self.origin;
@@ -277,6 +300,9 @@ void spawnfunc_func_breakable() {
        self.reset = func_breakable_reset;
        func_breakable_reset();
 
+       self.init_for_player_needed = 1;
+       self.init_for_player = func_breakable_init_for_player;
+
        CSQCMODEL_AUTOINIT();
 }
 
index 0a27083..04f8ff7 100644 (file)
@@ -314,15 +314,21 @@ void cvar_changes_init()
                // does nothing visible
                BADCVAR("captureleadlimit_override");
                BADCVAR("g_balance_kill_delay");
+               BADCVAR("g_ca_point_limit");
                BADCVAR("g_ca_point_leadlimit");
                BADCVAR("g_ctf_captimerecord_always");
                BADCVAR("g_ctf_flag_glowtrails");
                BADCVAR("g_ctf_flag_pickup_verbosename");
                BADCVAR("g_domination_point_leadlimit");
                BADCVAR("g_forced_respawn");
+               BADCVAR("g_freezetag_point_limit");
+               BADCVAR("g_freezetag_point_leadlimit");
                BADCVAR("g_keyhunt_point_leadlimit");
                BADPREFIX("g_mod_");
+               BADCVAR("g_invasion_point_limit");
                BADCVAR("g_nexball_goalleadlimit");
+               BADCVAR("g_tdm_point_limit");
+               BADCVAR("g_tdm_point_leadlimit");
                BADCVAR("leadlimit_and_fraglimit");
                BADCVAR("leadlimit_override");
                BADCVAR("pausable");
index bd98808..9591ee8 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 2e6eb4f..5ea2924 100644 (file)
@@ -89,13 +89,11 @@ float ctf_CheckPassDirection(vector head_center, vector passer_center, vector pa
                makevectors(passer_angle);
 
                // find the closest point on the enemy to the center of the attack
-               float ang; // angle between shotdir and h
                float h; // hypotenuse, which is the distance between attacker to head
                float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
 
                h = vlen(head_center - passer_center);
-               ang = acos(dotproduct(normalize(head_center - passer_center), v_forward));
-               a = h * cos(ang);
+               a = h * (normalize(head_center - passer_center) * v_forward);
 
                vector nearest_on_line = (passer_center + a * v_forward);
                float distance_from_line = vlen(nearest_to_passer - nearest_on_line);
index 141172e..b3502b0 100644 (file)
@@ -247,6 +247,18 @@ MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
                if(IS_PLAYER(frag_attacker))
                if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
                {
+                       if(frag_target.armorvalue)
+                       {
+                               frag_target.armorvalue -= 1;
+                               frag_damage = 0;
+                               frag_target.damage_dealt += 1;
+                               frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
+                               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
+                       }
+               }
+
+               if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+               {
                        if(frag_deathtype & HITTYPE_SECONDARY)
                        {
                                frag_damage = frag_mirrordamage = 0;
@@ -257,14 +269,6 @@ MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
                                        frag_force = '0 0 0';
                                }
                        }
-                       else if(frag_target.armorvalue)
-                       {
-                               frag_target.armorvalue -= 1;
-                               frag_damage = 0;
-                               frag_target.damage_dealt += 1;
-                               frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
-                               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
-                       }
                }
        }
 
@@ -281,7 +285,7 @@ MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
                frag_mirrordamage = 0;
        }
 
-       if(frag_target.items & IT_STRENGTH)
+       if((frag_target.buffs & BUFF_INVISIBLE) || (frag_target.items & IT_STRENGTH))
                yoda = 1;
 
        return false;
index 3932ce4..60b2acc 100644 (file)
@@ -551,12 +551,12 @@ void nade_boom()
 
 void nade_touch()
 {
-       float is_weapclip = 0;
+       /*float is_weapclip = 0;
        if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
        if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID))
        if (!(trace_dphitcontents & DPCONTENTS_OPAQUE))
-               is_weapclip = 1;
-       if(ITEM_TOUCH_NEEDKILL() || is_weapclip)
+               is_weapclip = 1;*/
+       if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
        {
                remove(self);
                return;
@@ -666,7 +666,13 @@ void toss_nade(entity e, vector _velocity, float _time)
 
        Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
 
-       setorigin(_nade, w_shotorg + (v_right * 25) * -1);
+       vector offset = (v_forward * autocvar_g_nades_throw_offset.x)
+                                 + (v_right * autocvar_g_nades_throw_offset.y)
+                                 + (v_up * autocvar_g_nades_throw_offset.z);
+       if(autocvar_g_nades_throw_offset == '0 0 0')
+               offset = '0 0 0';
+
+       setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1);
        //setmodel(_nade, "models/weapons/v_ok_grenade.md3");
        //setattachment(_nade, world, "");
        PROJECTILE_MAKETRIGGER(_nade);
@@ -677,7 +683,7 @@ void toss_nade(entity e, vector _velocity, float _time)
        if (trace_startsolid)
                setorigin(_nade, e.origin);
 
-       if(self.v_angle.x >= 70 && self.v_angle.x <= 110)
+       if(self.v_angle.x >= 70 && self.v_angle.x <= 110 && self.BUTTON_CROUCH)
                _nade.velocity = '0 0 100';
        else if(autocvar_g_nades_nade_newton_style == 1)
                _nade.velocity = e.velocity + _velocity;
index 1d151fc..78a6151 100644 (file)
@@ -64,6 +64,7 @@ MUTATOR_HOOKFUNCTION(ok_PlayerDamage_SplitHealthArmor)
 MUTATOR_HOOKFUNCTION(ok_PlayerDies)
 {
        entity oldself = self;
+       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
 
        if(self.flags & FL_MONSTER)
        {
@@ -80,7 +81,7 @@ MUTATOR_HOOKFUNCTION(ok_PlayerDies)
        self.gravity = 1;
        self.reset = SUB_Remove;
        setorigin(self, frag_target.origin + '0 0 32');
-       self.velocity = '0 0 200' + normalize(frag_attacker.origin - self.origin) * 500;
+       self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
        self.classname = "droppedweapon"; // hax
        SUB_SetFade(self, time + 5, 1);
        self = oldself;
@@ -137,6 +138,8 @@ MUTATOR_HOOKFUNCTION(ok_PlayerPreThink)
                self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
                makevectors(self.v_angle);
 
+               int oldwep = self.weapon;
+               self.weapon = WEP_BLASTER;
                W_Blaster_Attack(
                        WEP_BLASTER | HITTYPE_SECONDARY,
                        WEP_CVAR_SEC(vaporizer, shotangle),
@@ -149,6 +152,7 @@ MUTATOR_HOOKFUNCTION(ok_PlayerPreThink)
                        WEP_CVAR_SEC(vaporizer, delay),
                        WEP_CVAR_SEC(vaporizer, lifetime)
                );
+               self.weapon = oldwep;
        }
 
        self.weapon_blocked = false;
index 28145a2..b4b9b18 100644 (file)
@@ -229,6 +229,9 @@ void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity
 
                        self = oldself;
                        activator = oldactivator;
+
+                       // We called an external function, so we have to re-tokenize msg.
+                       n = tokenize_console(msg);
                }
                else
                {
index b948b20..c9cde90 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);
@@ -276,3 +290,11 @@ int isunordered(float x, float y)
 {
        return !(x < y || x == y || x > y);
 }
+
+vector cross(vector a, vector b)
+{
+       return
+               '1 0 0' * (a.y * b.z - a.z * b.y)
+       +       '0 1 0' * (a.z * b.x - a.x * b.z)
+       +       '0 0 1' * (a.x * b.y - a.y * b.x);
+}
index 7eebd03..ddd494d 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);
@@ -101,4 +112,8 @@ const float M_2_PI     = 0.63661977236758134308;  /* 2/pi */
 const float M_2_SQRTPI = 1.12837916709551257390;  /* 2/sqrt(pi) */
 const float M_SQRT2    = 1.41421356237309504880;  /* sqrt(2) */
 const float M_SQRT1_2  = 0.70710678118654752440;  /* 1/sqrt(2) */
+
+// Non-<math.h> stuff follows here.
+vector cross(vector a, vector b);
+
 #endif
index 5d529c1..c4dc728 100644 (file)
@@ -537,7 +537,7 @@ void WarpZone_InitStep_UpdateTransform()
 {
        vector org, ang, norm, point;
        float area;
-       vector tri, a, b, c, p, q, n;
+       vector tri, a, b, c, n;
        float i_s, i_t, n_t;
        string tex;
 
@@ -561,11 +561,7 @@ void WarpZone_InitStep_UpdateTransform()
                        a = getsurfacepoint(self, i_s, tri.x);
                        b = getsurfacepoint(self, i_s, tri.y);
                        c = getsurfacepoint(self, i_s, tri.z);
-                       p = b - a;
-                       q = c - a;
-                       n =     '1 0 0' * (q.y * p.z - q.z * p.y)
-                       +       '0 1 0' * (q.z * p.x - q.x * p.z)
-                       +       '0 0 1' * (q.x * p.y - q.y * p.x);
+                       n = cross(c - a, b - a);
                        area = area + vlen(n);
                        norm = norm + n;
                        point = point + vlen(n) * (a + b + c);
index 79cff01..b94eafb 100644 (file)
@@ -77,8 +77,12 @@ void WarpZoneLib_ExactTrigger_Init()
                makevectors (self.angles);
                self.movedir = v_forward;
        }
-       self.warpzone_isboxy = 1;
-       if(self.model != "")
+       if(self.model == "")
+       {
+               // It's a box! No need to match with exacttriggers.
+               self.warpzone_isboxy = 1;
+       }
+       else
        {
                mi = self.mins;
                ma = self.maxs;
@@ -87,11 +91,11 @@ void WarpZoneLib_ExactTrigger_Init()
                // let mapper-set mins/maxs override the model's bounds if set
                if(mi != '0 0 0' || ma != '0 0 0')
                {
+                       // It's a box! No need to match with exacttriggers.
                        self.mins = mi;
                        self.maxs = ma;
+                       self.warpzone_isboxy = 1;
                }
-               else
-                       self.warpzone_isboxy = 0; // enable exacttrigger matching
        }
        setorigin(self, self.origin);
        if(self.scale)
index 6808bae..503c239 100644 (file)
@@ -20,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
@@ -124,7 +125,6 @@ Dale "graphitemaster" Weiler
 **Other Active Contributors
 Erik "Ablu" Schilling
 Jope "Sless" Withers
-Mattia "Melanosuchus" Basaglia
 Mircea "Taoki" Kitsune
 Robert "ai" Kuroto
 
@@ -144,6 +144,7 @@ set_killer
 
 *Czech
 shogun assassin/woky
+Tomáš "CZHeron" Volavka
 
 *Dutch
 Alexander "freefang" van Dam
@@ -192,6 +193,7 @@ XCostaX
 
 *Polish
 4m
+Alex "tiprogrammierer.alex" Progger
 Amadeusz "amade/proraide" Sławiński
 
 *Portuguese
@@ -201,6 +203,7 @@ xXxCHAOTICxXx
 *Romanian
 BusterDBK
 Mircea "Taoki" Kitsune
+Tudor "TropiKo" Ionel
 
 *Russian
 Alex "alextalker7" Talker