]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote branch 'origin/master' into samual/balance
authorSamual <samual@xonotic.org>
Wed, 26 Oct 2011 03:10:21 +0000 (23:10 -0400)
committerSamual <samual@xonotic.org>
Wed, 26 Oct 2011 03:10:21 +0000 (23:10 -0400)
40 files changed:
defaultXonotic.cfg
effects-high.cfg
effects-low.cfg
effects-med.cfg
effects-normal.cfg
effects-omg.cfg
effects-ultimate.cfg
effects-ultra.cfg
models/keys/key.md3 [new file with mode: 0644]
models/keys/key.tga [new file with mode: 0644]
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/hud_config.qc
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/menu/gamecommand.qc
qcsrc/menu/xonotic/dialog_settings_effects.c
qcsrc/menu/xonotic/dialog_settings_video.c
qcsrc/server/antilag.qc
qcsrc/server/antilag.qh
qcsrc/server/cl_client.qc
qcsrc/server/clientcommands.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_subs.qc
qcsrc/server/g_world.qc
qcsrc/server/gamecommand.qc
qcsrc/server/item_key.qc [new file with mode: 0644]
qcsrc/server/item_key.qh [new file with mode: 0644]
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/base.qh
qcsrc/server/mutators/gamemode_keepaway.qc
qcsrc/server/progs.src
qcsrc/server/sv_main.qc
qcsrc/server/t_plats.qc
qcsrc/server/tturrets/units/unit_tessla.qc
qcsrc/server/w_common.qc
qcsrc/server/w_tuba.qc
qcsrc/warpzonelib/common.qc
qcsrc/warpzonelib/common.qh

index 1d90a8cc9ff0aaff484b2efd213238b7431594df..6dc4c33954eb6fc89d27cf59bdcf7d7560faa86d 100644 (file)
@@ -53,8 +53,6 @@ alias asay_drop "say_team (%l) dropped %w ; impulse 17"
 alias +hook +button6
 alias -hook -button6
 alias use "impulse 21"
-alias +use use // always send that impulse AND press the key (+use is engine internal command and executes anyway)
-set cl_newusekeysupported 1 // indicates that we always send the use impulse too, so they do not need to be synthesized
 alias ready "cmd ready"
 alias lockteams "sv_cmd lockteams"
 alias unlockteams "sv_cmd unlockteams"
@@ -1041,7 +1039,7 @@ bind MWHEELDOWN weapprev
 bind r reload
 bind BACKSPACE dropweapon
 bind g dropweapon
-bind f use
+bind f +use
 
 // misc
 bind e +hook
@@ -1713,6 +1711,7 @@ seta hud_width 560
 prvm_leaktest_ignore_classnames "ctf_team dom_team tdm_team"
 
 sv_allowdownloads_inarchive 1 // for csprogs.dat
+sv_allowdownloads 0 // download protocol is evil
 
 set g_jump_grunt 0     "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
 
@@ -1757,6 +1756,8 @@ set cl_handicap 1 "the higher, the more damage you will receive (client setting)
 
 seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice." 
 
+seta cl_autoscreenshot 0 "client option to automatically take a screenshot once the map has ended (see also sv_autoscreenshot)"
+
 // must be at the bottom of this file:
 // alias for switching the teamselect menu
 alias menu_showteamselect "menu_cmd directmenu TeamSelect"
index 48d0d43b87e409e030ca2ea3783fe1e7fd57bfd4..b385001d5eb235147e34d186fc87fe2704153513 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 2000
 r_glsl_deluxemapping 1
 r_glsl_offsetmapping 1
 r_glsl_offsetmapping_reliefmapping 0
-r_hdr 0
 r_motionblur 0.5
 r_shadow_gloss 1
 r_shadow_realtime_dlight 1
index 9609a5780234582d3945e02c316c9a77d188174e..17f88444c6d238ba316eb238238ce257ead41562 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 500
 r_glsl_deluxemapping 0
 r_glsl_offsetmapping 0
 r_glsl_offsetmapping_reliefmapping 0
-r_hdr 0
 r_motionblur 0
 r_shadow_gloss 0
 r_shadow_realtime_dlight 0
index 94a85e5091a2146c326077707410d87142075e2f..ab4356da768e182e3ddab34d6125cabfa0e9c265 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 1000
 r_glsl_deluxemapping 0
 r_glsl_offsetmapping 0
 r_glsl_offsetmapping_reliefmapping 0
-r_hdr 0
 r_motionblur 0
 r_shadow_gloss 0
 r_shadow_realtime_dlight 1
index 7822102ba9c11e9a0a4088eecdf5550cbf108a14..8d558fc5a7ea9157c6f0f44351ea00c2c43143da 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 1000
 r_glsl_deluxemapping 1
 r_glsl_offsetmapping 0
 r_glsl_offsetmapping_reliefmapping 0
-r_hdr 0
 r_motionblur 0
 r_shadow_gloss 1
 r_shadow_realtime_dlight 1
index a68a15787ded9bb5b8a10003b278054e7e29c3c3..eede2b12fae570e19efab4cd1e855b37cc39dbd5 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 250
 r_glsl_deluxemapping 0
 r_glsl_offsetmapping 0
 r_glsl_offsetmapping_reliefmapping 0
-r_hdr 0
 r_motionblur 0
 r_shadow_gloss 0
 r_shadow_realtime_dlight 0
index 20cd2e563870d40b2678874e6802250a2ffbe02a..268101e31839f9e31c20b7267d840d6a2edaa1cd 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 2000
 r_glsl_deluxemapping 1
 r_glsl_offsetmapping 1
 r_glsl_offsetmapping_reliefmapping 1
-r_hdr 2
 r_motionblur 0.5
 r_shadow_gloss 1
 r_shadow_realtime_dlight 1
index 94d47fab2e7cfcf4a600c625ecf6b8b401d99760..0ec7293fc78954102135ae6933b0e17f648f0b9b 100644 (file)
@@ -17,7 +17,6 @@ r_drawparticles_drawdistance 2000
 r_glsl_deluxemapping 1
 r_glsl_offsetmapping 1
 r_glsl_offsetmapping_reliefmapping 0
-r_hdr 0
 r_motionblur 0.5
 r_shadow_gloss 1
 r_shadow_realtime_dlight 1
diff --git a/models/keys/key.md3 b/models/keys/key.md3
new file mode 100644 (file)
index 0000000..097c90c
Binary files /dev/null and b/models/keys/key.md3 differ
diff --git a/models/keys/key.tga b/models/keys/key.tga
new file mode 100644 (file)
index 0000000..5e70fa3
Binary files /dev/null and b/models/keys/key.tga differ
index c9593f344866ab0e5fa468f222a8bdd5dea8fb32..4fdb5078ff961a4f9b1c7f6eafc410efc068c37c 100644 (file)
@@ -347,7 +347,6 @@ float CSQC_ConsoleCommand(string strMessage)
 {
        float argc;
        // Tokenize String
-       //argc = tokenize(strMessage);
        argc = tokenize_console(strMessage);
 
        // Acquire Command
@@ -958,13 +957,23 @@ void CSQC_Ent_Update(float bIsNewEntity)
 
 #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
        if(self.enttype)
-               if(t != self.enttype)
+       {
+               if(t != self.enttype || bIsNewEntity)
                {
                        //print(_("A CSQC entity changed its type!\n"));
-                       print(sprintf(_("A CSQC entity changed its type! (edict: %d, classname: %s)\n"), num_for_edict(self), self.classname));
+                       print(sprintf(_("A CSQC entity changed its type! (edict: %d, type: %d -> %d)\n"), num_for_edict(self), self.enttype, t));
                        Ent_Remove();
                        bIsNewEntity = 1;
                }
+       }
+       else
+       {
+               if(!bIsNewEntity)
+               {
+                       print(sprintf(_("A CSQC entity appeared out of nowhere! (edict: %d, type: %d)\n"), num_for_edict(self), t));
+                       bIsNewEntity = 1;
+               }
+       }
 #endif
        self.enttype = t;
        switch(t)
index 9b9b37fb6b658f0e99c8ca640c9c7e89fc894ea3..54b22d1e69bc8d43821d9aa528312dc3ed12ef88 100644 (file)
@@ -792,7 +792,7 @@ void CSQC_UpdateView(float w, float h)
                }
        }
        
-       if(autocvar_hud_damage && !autocvar_chase_active)
+       if(autocvar_hud_damage)
        {
                splash_size_x = max(vid_conwidth, vid_conheight);
                splash_size_y = max(vid_conwidth, vid_conheight);
@@ -844,24 +844,27 @@ void CSQC_UpdateView(float w, float h)
                // pro: matches model better
                // contra: it's not red because blood is red, but because red is an alarming color, so red should stay
                // maybe different reddish pics?
-               if(autocvar_cl_gentle_damage || autocvar_cl_gentle)
+               if(autocvar_chase_active >= 0) // not while the event chase camera is active
                {
-                       if(autocvar_cl_gentle_damage == 2)
+                       if(autocvar_cl_gentle_damage || autocvar_cl_gentle)
                        {
-                               if(myhealth_flash < pain_threshold) // only randomize when the flash is gone
+                               if(autocvar_cl_gentle_damage == 2)
                                {
-                                       myhealth_gentlergb = eX * random() + eY * random() + eZ * random();
+                                       if(myhealth_flash < pain_threshold) // only randomize when the flash is gone
+                                       {
+                                               myhealth_gentlergb = eX * random() + eY * random() + eZ * random();
+                                       }
                                }
+                               else
+                                       myhealth_gentlergb = stov(autocvar_hud_damage_gentle_color);
+
+                               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
                        }
                        else
-                               myhealth_gentlergb = stov(autocvar_hud_damage_gentle_color);
-
-                       drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
+                               drawpic(splash_pos, "gfx/blood", splash_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
                }
-               else
-                       drawpic(splash_pos, "gfx/blood", splash_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
 
-               if(autocvar_hud_postprocessing)
+               if(autocvar_hud_postprocessing) // we still need to set this anyway even when chase_active is set, this way it doesn't get stuck on.
                {
                        if(autocvar_hud_damage_blur && myhealth_flash_temp)
                        {
@@ -1424,7 +1427,7 @@ void CSQC_common_hud(void)
             if(acc_color_levels)
                 strunzone(acc_color_levels);
             acc_color_levels = strzone(autocvar_accuracy_color_levels);
-            acc_levels = tokenize(acc_color_levels);
+            acc_levels = tokenize_console(acc_color_levels);
             if (acc_levels > MAX_ACCURACY_LEVELS)
                 acc_levels = MAX_ACCURACY_LEVELS;
 
index f26f65ea54b53d3c7a5d8cd564457416d81755d7..488debb11baeb521d6427bfa8bce5fc11d74451d 100644 (file)
@@ -583,7 +583,7 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
        string con_keys;
        float keys;
        con_keys = findkeysforcommand("toggleconsole");
-       keys = tokenize(con_keys);
+       keys = tokenize(con_keys); // findkeysforcommand returns data for this
 
        float hit_con_bind, i;
        for (i = 0; i < keys; ++i)
index c3407757a469c8d3e3dbb56d03bac34d2dd85816..d97ec0918be53a64e3d55e00e296b6f5c0b31032 100644 (file)
@@ -2085,3 +2085,13 @@ float xdecode(string s)
                return -1;
        return ((a * 22 + b) * 22 + c) * 22 + d;
 }
+
+float lowestbit(float f)
+{
+       f &~= f * 2;
+       f &~= f * 4;
+       f &~= f * 16;
+       f &~= f * 256;
+       f &~= f * 65536;
+       return f;
+}
index 2eee6d74ef1a4d369286c1fcc01a71588ccd130d..b2e77484e398695ea3b2febb290bd217cdf83af5 100644 (file)
@@ -22,7 +22,7 @@ void wordwrap_cb(string s, float l, void(string) callback)
 
 float GameCommand_Generic(string cmd);
 // returns TRUE if handled, FALSE otherwise
-// uses tokenize on its argument!
+// tokenizes its input!
 
 // iterative depth-first search, with fields that go "up", "down left" and "right" in a tree
 // for each element, funcPre is called first, then funcPre and funcPost for all its children, and funcPost last
index 83ef53762c914ab5f5ca4cbd255547d14163f7a8..e637bf5aa87a3f71bd43bf99c94f55f1fc5960a7 100644 (file)
@@ -184,44 +184,5 @@ void GameCommand(string theCommand)
                return;
        }
 
-#if 0
-       if(argv(0) == "tokentest")
-       {
-               string s;
-               float i, n;
-
-               print("SANE tokenizer:\n");
-               s = cvar_string("tokentest");
-               n = tokenize_console_force_builtin(s);
-               for(i = -n; i < n; ++i)
-               {
-                       print("token ", ftos(i), ": '", argv(i), "' = ");
-                       print(ftos(argv_start_index(i)), " to ", ftos(argv_end_index(i)), "\n");
-               }
-               print(".\n");
-
-               print("INSANE tokenizer:\n");
-               s = cvar_string("tokentest");
-               n = tokenize(s);
-               for(i = -n; i < n; ++i)
-               {
-                       print("token ", ftos(i), ": '", argv(i), "' = ");
-                       print(ftos(argv_start_index(i)), " to ", ftos(argv_end_index(i)), "\n");
-               }
-               print(".\n");
-
-               print("EMULATED tokenizer:\n");
-               s = cvar_string("tokentest");
-               n = tokenize_console_force_emulation(s);
-               for(i = -n; i < n; ++i)
-               {
-                       print("token ", ftos(i), ": '", argv(i), "' = ");
-                       print(ftos(argv_start_index(i)), " to ", ftos(argv_end_index(i)), "\n");
-               }
-               print(".\n");
-               return;
-       }
-#endif
-
        print(_("Invalid command. For a list of supported commands, try menu_cmd help.\n"));
 }
index 585b2079683ba10c50434d7073d3e7b29dfacd12..fc8756b4b7a9ca314adbe12bbce645136dd84b41 100644 (file)
@@ -175,9 +175,7 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_coronas", _("Coronas")));
                me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "r_coronas_occlusionquery", _("Use Occlusion Queries")));
        me.TR(me);
-               me.TD(me, 1, 1.2, e = makeXonoticCheckBox(0, "r_bloom", _("Bloom")));
-                       setDependent(e, "r_hdr", 0, 0);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBoxEx(2, 0, "r_hdr", _("High Dynamic Range (HDR)")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_bloom", _("High Dynamic Range (HDR)")));
        
        me.TR(me);
                s = makeXonoticSlider(0.1, 1, 0.1, "r_motionblur");
index 770811ec1e8424a5c92d6ad8798d5676983e6ab4..e5f5da237bc73be61dc3e2ab264bece41d243758 100644 (file)
@@ -44,14 +44,12 @@ void XonoticVideoSettingsTab_fill(entity me)
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "vid_fullscreen", _("Full screen")));
                me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "vid_vsync", _("Vertical Synchronization")));
-       me.TR(me);
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_gl20", _("Use OpenGL 2.0 shaders (GLSL)")));
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "v_glslgamma", _("Use GLSL to handle color control")));
                        setDependent(e, "vid_gl20", 1, 1);
-       me.TR(me);
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Vertex Buffer Objects (VBOs)")));
        me.TR(me);
@@ -62,6 +60,16 @@ void XonoticVideoSettingsTab_fill(entity me)
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "gl_vbo", "2", _("Vertices")));
                me.TD(me, 1, 1.9, e = makeXonoticRadioButton(1, "gl_vbo", "1", _("Vertices and Triangles")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Frame Buffer Objects (FBOs)")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "r_viewfbo", "0", _("None")));
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "r_viewfbo", "1", _("8bit")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "r_viewfbo", "2", _("16bit HDR")));
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "r_viewfbo", "3", _("32bit HDR")));
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Depth first:")));
@@ -70,9 +78,6 @@ void XonoticVideoSettingsTab_fill(entity me)
                        e.addValue(e, ZCTX(_("DF^World")), "1");
                        e.addValue(e, ZCTX(_("DF^All")), "2");
                        e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               if(cvar_type("apple_multithreadedgl") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "apple_multithreadedgl", _("Disable multithreaded OpenGL")));
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "gl_finish", _("Wait for GPU to finish each frame")));
 
index 8a628a1bea91e1c5f9e5d5158b176b3eeedfad91..69d291a4ed69018848e0ebccb7c897b250b922d1 100644 (file)
@@ -14,6 +14,9 @@ void antilag_dummy()
 
 void antilag_record(entity e, float t)
 {
+    if(e.vehicle)
+        antilag_record(e.vehicle, t);
+
        if(time < e.(antilag_times[e.antilag_index]))
                return;
        e.antilag_index = e.antilag_index + 1;
@@ -24,6 +27,7 @@ void antilag_record(entity e, float t)
 
        if(e.antilag_debug)
                te_spark(antilag_takebackorigin(e, t - e.antilag_debug), '0 0 0', 32);
+
 }
 
 // finds the index BEFORE t
@@ -75,6 +79,7 @@ vector antilag_takebackorigin(entity e, float t)
 vector antilag_takebackavgvelocity(entity e, float t0, float t1)
 {
        vector o0, o1;
+
        if(t0 >= t1)
                return '0 0 0';
        o0 = antilag_takebackorigin(e, t0);
@@ -84,11 +89,17 @@ vector antilag_takebackavgvelocity(entity e, float t0, float t1)
 
 void antilag_takeback(entity e, float t)
 {
+    if(e.vehicle)
+        antilag_takeback(e.vehicle, t);
+
        e.antilag_saved_origin = e.origin;
        setorigin(e, antilag_takebackorigin(e, t));
 }
 
 void antilag_restore(entity e)
 {
+    if(e.vehicle)
+        antilag_restore(e.vehicle);
+
        setorigin(e, e.antilag_saved_origin);
 }
index 2a7343243dd6e4dc7cfd80d2cd2bd6394928197e..08e33e2e58c07c9ed8f18f703342826f0ddd7949 100644 (file)
@@ -1,5 +1,4 @@
 void antilag_record(entity e, float t);
-float antilag_find(entity e, float t);
 vector antilag_takebackorigin(entity e, float t);
 vector antilag_takebackavgvelocity(entity e, float t0, float t1);
 void antilag_takeback(entity e, float t);
index f41503ab09c790131d48727a08a8af085aeca642..de4c7431d5aafad3db68fe68f1da5e7ad5208070 100644 (file)
@@ -861,6 +861,9 @@ void PutClientInServer (void)
                WriteByte(MSG_ONE, SVC_SETVIEW);
                WriteEntity(MSG_ONE, self);
        }
+       
+       // reset player keys
+       self.itemkeys = 0;
 
        // player is dead and becomes observer
        // FIXME fix LMS scoring for new system
@@ -2777,7 +2780,7 @@ void PlayerPreThink (void)
 
        MUTATOR_CALLHOOK(PlayerPreThink);
 
-       if(!self.cvar_cl_newusekeysupported)
+       if(!self.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
        {
                if(self.BUTTON_USE && !self.usekeypressed)
                        PlayerUseKey();
index 2ffa4afd9007578ba97f864e7f41621d02f328db..cfbc5ff18427f68e033e26bb70e5fc53afa447ad 100644 (file)
@@ -145,33 +145,34 @@ float cmd_floodcheck()
 
 .float checkfail;
 void SV_ParseClientCommand(string s) {
-       string cmd;
-       float tokens;
        float i;
        entity e;
 
-       tokens = tokenize_console(s);
-
-       cmd = strtolower(argv(0));
-       if(cmd != "reportcvar")
-       if(cmd != "sentcvar")
-       if(cmd != "pause")
-       if(cmd != "prespawn")
-       if(cmd != "spawn")
-       if(cmd != "begin")
+       cmd_argc = tokenize_console(s);
+       cmd_string = s;
+       cmd_name = strtolower(argv(0));
+       if(cmd_name != "reportcvar")
+       if(cmd_name != "sentcvar")
+       if(cmd_name != "pause")
+       if(cmd_name != "prespawn")
+       if(cmd_name != "spawn")
+       if(cmd_name != "begin")
        {
                if(cmd_floodcheck())
                        return;
        }
 
+       if(MUTATOR_CALLHOOK(SV_ParseClientCommand))
+               return; // already handled
+       
        if(GameCommand_Vote(s, self)) {
                return;
        } else if(GameCommand_MapVote(argv(0))) {
                return;
-       } else if(cmd == "checkfail") {
+       } else if(cmd_name == "checkfail") {
                print(sprintf("CHECKFAIL: %s (%s) epically failed check %s\n", self.netname, self.netaddress, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1))));
                self.checkfail = 1;
-       } else if(cmd == "autoswitch") {
+       } else if(cmd_name == "autoswitch") {
                // be backwards compatible with older clients (enabled)
                self.autoswitch = ("0" != argv(1));
                string autoswitchmsg;
@@ -181,7 +182,7 @@ void SV_ParseClientCommand(string s) {
                        autoswitchmsg = "off";
                }
                sprint(self, strcat("^1autoswitch turned ", autoswitchmsg, "\n"));
-       } else if(cmd == "clientversion") {
+       } else if(cmd_name == "clientversion") {
                if not(self.flags & FL_CLIENT)
                        return;
                if (argv(1) == "$gameversion") {
@@ -201,21 +202,21 @@ void SV_ParseClientCommand(string s) {
                        self.classname = "observer";
                        stuffcmd(self,"menu_showteamselect\n");
                }
-       } else if(cmd == "reportcvar") { // old system
+       } else if(cmd_name == "reportcvar") { // old system
                if(substring(argv(2), 0, 1) == "$") // undefined cvar: use the default value on the server then
                {
                        s = strcat(substring(s, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
-                       tokens = tokenize_console(s);
+                       cmd_argc = tokenize_console(s);
                }
                GetCvars(1);
-       } else if(cmd == "sentcvar") { // new system
-               if(tokens == 2) // undefined cvar: use the default value on the server then
+       } else if(cmd_name == "sentcvar") { // new system
+               if(cmd_argc == 2) // undefined cvar: use the default value on the server then
                {
                        s = strcat(substring(s, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
-                       tokens = tokenize_console(s);
+                       cmd_argc = tokenize_console(s);
                }
                GetCvars(1);
-       } else if(cmd == "spectate") {
+       } else if(cmd_name == "spectate") {
                if(cmd_floodcheck())
                        return;
                if not(self.flags & FL_CLIENT)
@@ -244,7 +245,7 @@ void SV_ParseClientCommand(string s) {
                        sprint(self, "WARNING: you will spectate in the next round.\n");
                        self.caplayer = 0;
                }
-       } else if(cmd == "join") {
+       } else if(cmd_name == "join") {
                if not(self.flags & FL_CLIENT)
                        return;
                if(!g_arena)
@@ -265,7 +266,7 @@ void SV_ParseClientCommand(string s) {
                                centerprint(self, PREVENT_JOIN_TEXT);
                        }
                }
-       } else if( cmd == "selectteam" ) {
+       } else if( cmd_name == "selectteam" ) {
                if not(self.flags & FL_CLIENT)
                        return;
                if( !teamplay ) {
@@ -301,7 +302,7 @@ void SV_ParseClientCommand(string s) {
                } else {
                        sprint( self, strcat( "selectteam none/red/blue/yellow/pink/auto - \"", argv(1), "\" not recognised\n" ) );
                }
-       } else if(cmd == "ready") {
+       } else if(cmd_name == "ready") {
                if not(self.flags & FL_CLIENT)
                        return;
 
@@ -328,54 +329,54 @@ void SV_ParseClientCommand(string s) {
                                sprint(self, "^1Game has already been restarted\n");
                        }
                }
-       } else if(cmd == "maplist") {
+       } else if(cmd_name == "maplist") {
                sprint(self, maplist_reply);
-       } else if(cmd == "lsmaps") {
+       } else if(cmd_name == "lsmaps") {
                sprint(self, lsmaps_reply);
-       } else if(cmd == "lsnewmaps") {
+       } else if(cmd_name == "lsnewmaps") {
                sprint(self, lsnewmaps_reply);
-       } else if(cmd == "records") {
+       } else if(cmd_name == "records") {
                for(i = 0; i < 10; ++i)
                        sprint(self, records_reply[i]);
-       } else if(cmd == "ladder") {
+       } else if(cmd_name == "ladder") {
                sprint(self, ladder_reply);
-       } else if(cmd == "rankings") {
+       } else if(cmd_name == "rankings") {
                sprint(self, rankings_reply);
-       } else if(cmd == "voice") {
-               if(tokens >= 3)
+       } else if(cmd_name == "voice") {
+               if(cmd_argc >= 3)
                        VoiceMessage(argv(1), substring(s, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
                else
                        VoiceMessage(argv(1), "");
-       } else if(cmd == "say") {
-               if(tokens >= 2)
+       } else if(cmd_name == "say") {
+               if(cmd_argc >= 2)
                        Say(self, FALSE, world, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
                //clientcommand(self, formatmessage(s));
-       } else if(cmd == "say_team") {
-               if(tokens >= 2)
+       } else if(cmd_name == "say_team") {
+               if(cmd_argc >= 2)
                        Say(self, TRUE, world, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
                //clientcommand(self, formatmessage(s));
-       } else if(cmd == "tell") {
-               e = GetCommandPlayerSlotTargetFromTokenizedCommand(tokens, 1);
-               if(e && tokens > ParseCommandPlayerSlotTarget_firsttoken)
+       } else if(cmd_name == "tell") {
+               e = GetCommandPlayerSlotTargetFromTokenizedCommand(cmd_argc, 1);
+               if(e && cmd_argc > ParseCommandPlayerSlotTarget_firsttoken)
                {
                        Say(self, FALSE, e, substring(s, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)), TRUE);
                }
                else
                {
-                       if(tokens > ParseCommandPlayerSlotTarget_firsttoken)
+                       if(cmd_argc > ParseCommandPlayerSlotTarget_firsttoken)
                                trigger_magicear_processmessage_forallears(self, -1, world, substring(s, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)));
                        sprint(self, "ERROR: usage: tell # playerid text...\n");
                }
                //clientcommand(self, formatmessage(s));
-       } else if(cmd == "info") {
-               cmd = cvar_string_builtin(strcat("sv_info_", argv(1))); // This needed fixed for the cvar check
-               if(cmd == "")
+       } else if(cmd_name == "info") {
+               cmd_name = cvar_string_builtin(strcat("sv_info_", argv(1))); // This needed fixed for the cvar check
+               if(cmd_name == "")
                        sprint(self, "ERROR: unsupported info command\n");
                else
-                       wordwrap_sprint(cmd, 1111);
-       } else if(cmd == "suggestmap") {
+                       wordwrap_sprint(cmd_name, 1111);
+       } else if(cmd_name == "suggestmap") {
                sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
-       } else if(cmd == "timeout") {
+       } else if(cmd_name == "timeout") {
                if not(self.flags & FL_CLIENT)
                        return;
                if(autocvar_sv_timeout) {
@@ -388,42 +389,42 @@ void SV_ParseClientCommand(string s) {
                        else
                                sprint(self, "^7Error: only players can call a timeout!\n");
                }
-       } else if(cmd == "timein") {
+       } else if(cmd_name == "timein") {
                if not(self.flags & FL_CLIENT)
                        return;
                if(autocvar_sv_timeout) {
                        evaluateTimein();
                }
-       } else if(cmd == "teamstatus") {
+       } else if(cmd_name == "teamstatus") {
                Score_NicePrint(self);
-       } else if(cmd == "cvar_changes") {
+       } else if(cmd_name == "cvar_changes") {
                sprint(self, cvar_changes);
-       } else if(cmd == "cvar_purechanges") {
+       } else if(cmd_name == "cvar_purechanges") {
                sprint(self, cvar_purechanges);
-       } else if(CheatCommand(tokens)) {
+       } else if(CheatCommand(cmd_argc)) {
        } else {
 #if 0
                //if(ctf_clientcommand())
                //      return;
                // grep for Cmd_AddCommand_WithClientCommand to find them all
-               if(cmd != "status")
-               //if(cmd != "say") // handled above
-               //if(cmd != "say_team") // handled above
-               if(cmd != "kill")
-               if(cmd != "pause")
-               if(cmd != "ping")
-               if(cmd != "name")
-               if(cmd != "color")
-               if(cmd != "rate")
-               if(cmd != "pmodel")
-               if(cmd != "playermodel")
-               if(cmd != "playerskin")
-               if(cmd != "prespawn")
-               if(cmd != "spawn")
-               if(cmd != "begin")
-               if(cmd != "pings")
-               if(cmd != "sv_startdownload")
-               if(cmd != "download")
+               if(cmd_name != "status")
+               //if(cmd_name != "say") // handled above
+               //if(cmd_name != "say_team") // handled above
+               if(cmd_name != "kill")
+               if(cmd_name != "pause")
+               if(cmd_name != "ping")
+               if(cmd_name != "name")
+               if(cmd_name != "color")
+               if(cmd_name != "rate")
+               if(cmd_name != "pmodel")
+               if(cmd_name != "playermodel")
+               if(cmd_name != "playerskin")
+               if(cmd_name != "prespawn")
+               if(cmd_name != "spawn")
+               if(cmd_name != "begin")
+               if(cmd_name != "pings")
+               if(cmd_name != "sv_startdownload")
+               if(cmd_name != "download")
                {
                        print("WARNING: Invalid clientcommand by ", self.netname, ": ", s, "\n");
                        return;
@@ -431,7 +432,7 @@ void SV_ParseClientCommand(string s) {
 #endif
 
                if(self.jointime > 0 && time > self.jointime + 10 && time > self.nickspamtime) // allow any changes in the first 10 seconds since joining
-               if(cmd == "name" || cmd == "playermodel") // TODO also playerskin and color?
+               if(cmd_name == "name" || cmd_name == "playermodel") // TODO also playerskin and color?
                {
                        if(self.nickspamtime == 0 || time > self.nickspamtime + autocvar_g_nick_flood_timeout)
                                // good, no serious flood
index 6c37ac92d8b3f1f83436a1264731716c50908dd5..b84d03164d312d8c2b3b410bb8c86a602bb1fca0 100644 (file)
@@ -246,6 +246,12 @@ float alreadychangedlevel;
 
 .float runes;
 
+// Keys player is holding
+.float itemkeys;
+// message delay for func_door locked by keys and key locks
+// this field is used on player entities
+.float key_door_messagetime;
+
 
 .float version;
 
@@ -315,6 +321,7 @@ float default_weapon_alpha;
 .float cvar_cl_handicap;
 .float cvar_cl_playerdetailreduction;
 .float cvar_cl_clippedspectating;
+.float cvar_cl_autoscreenshot;
 .float cvar_cl_movement_track_canjump;
 .float cvar_cl_newusekeysupported;
 
@@ -662,3 +669,4 @@ float serverflags;
 .float misc_bulletcounter;     // replaces uzi & hlac bullet counter.
 
 void PlayerUseKey();
+
index 5a583fc15ad101f07180877866f28641c5247c07..d7d2287ed6b093a23b63092caccfb496258af825 100644 (file)
@@ -329,7 +329,7 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
                }
                else if (attacker.classname == "player")
                {
-                       if(teamplay && attacker.team == targ.team)
+                       if(!IsDifferentTeam(attacker, targ))
                        {
                                if(attacker.team == COLOR_TEAM1)
                                        type = KILL_TEAM_RED;
@@ -561,7 +561,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float
                                damage = 0;
                                force = '0 0 0';
                        }
-                       else if(teamplay && attacker.team == targ.team)
+                       else if(!IsDifferentTeam(attacker, targ))
                        {
                                if(autocvar_teamplay_mode == 1)
                                        damage = 0;
index e9f9b3454e18ef0151812464e7ce7aabecabf6b9..6a62d61b5d423e43debf69ab9461e031c427142c 100644 (file)
@@ -389,12 +389,9 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
        if (lag)
        {
                // take players back into the past
-               player = player_list;
-               while (player)
-               {
-                       antilag_takeback(player, time - lag);
-                       player = player.nextplayer;
-               }
+               FOR_EACH_PLAYER(player)
+                       if(player != forent)
+                               antilag_takeback(player, time - lag);
        }
 
        // do the trace
@@ -406,12 +403,9 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
        // restore players to current positions
        if (lag)
        {
-               player = player_list;
-               while (player)
-               {
-                       antilag_restore(player);
-                       player = player.nextplayer;
-               }
+               FOR_EACH_PLAYER(player)
+                       if(player != forent)
+                               antilag_restore(player);
        }
 
        // restore shooter solid type
index b134886d4f6fcfc54281c1af591fb028650650c8..6f318e27e623ab88338d7017f228dbe65e3b89a2 100644 (file)
@@ -961,7 +961,7 @@ string GetMapname()
 float Map_Count, Map_Current;
 string Map_Current_Name;
 
-// NOTE: this now expects the map list to be already tokenize()d and the count in Map_Count
+// NOTE: this now expects the map list to be already tokenized and the count in Map_Count
 float GetMaplistPosition()
 {
        float pos, idx;
@@ -1345,9 +1345,8 @@ void IntermissionThink()
 {
        FixIntermissionClient(self);
 
-       if(autocvar_sv_autoscreenshot)
-       if(self.autoscreenshot > 0)
-       if(time > self.autoscreenshot)
+       if( (autocvar_sv_autoscreenshot || self.cvar_cl_autoscreenshot)
+               && ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
        {
                self.autoscreenshot = -1;
                if(clienttype(self) == CLIENTTYPE_REAL)
index f5b662be35e51a5e6a80a72a6ca70ac800cdaaa7..986f2dd84536c7b7141dbe3065a340a817df7d5b 100644 (file)
@@ -596,7 +596,7 @@ void EffectIndexDump()
        fh = fopen("effectinfo.txt", FILE_READ);
        while((s = fgets(fh)))
        {
-               tokenize(s); // tokenize_console would hit the loop counter :(
+               tokenize_console(s);
                if(argv(0) == "effect")
                {
                        if(db_get(d, argv(1)) != "1")
diff --git a/qcsrc/server/item_key.qc b/qcsrc/server/item_key.qc
new file mode 100644 (file)
index 0000000..e39f281
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+TODO:
+- add an unlock sound (here to trigger_keylock and to func_door)
+- display available keys on the HUD
+- make more tests
+- think about adding NOT_EASY/NOT_NORMAL/NOT_HARD for Q1 compatibility
+- should keys have a trigger?
+*/
+
+float item_keys_usekey(entity l, entity p) {
+       float valid = l.itemkeys & p.itemkeys;
+       
+       if not(valid) {
+               // other has none of the needed keys
+               return FALSE;
+       } else if (l.itemkeys == valid) {
+               // ALL needed keys were given
+               l.itemkeys = 0;
+               return TRUE;
+       } else {
+               // only some of the needed keys were given
+               l.itemkeys &~= valid;
+               return TRUE;
+       }
+}
+
+string item_keys_keylist(float keylist) {
+       float base, l;
+       string n;
+       
+       // no keys
+       if not(keylist)
+               return "";
+       
+       // one key
+       if ((keylist & (keylist-1)) != 0)
+               return strcat("the ", item_keys_names[lowestbit(keylist)]);
+       
+       while (keylist) {
+               l = lowestbit(keylist);
+               if (n)
+                       n = strcat(n, ", the ", item_keys_names[base + l]);
+               else
+                       n = strcat("the ", item_keys_names[base + l]);
+               
+               keylist = bitshift(keylist,  -(l + 1));
+               base+= l + 1;
+       }
+       
+       return n;
+}
+
+
+/*
+================================
+item_key
+================================
+*/
+
+/**
+ * Key touch handler.
+ */
+void item_key_touch(void) {
+       if (other.classname != "player")
+               return;
+               
+       // player already picked up this key
+       if (other.itemkeys & self.itemkeys)
+               return;
+       
+       other.itemkeys |= self.itemkeys;
+       play2(other, self.noise);
+       
+       centerprint(other, self.message);
+};
+
+/**
+ * Spawn a key with given model, key code and color.
+ */
+void spawn_item_key() {
+       precache_model(self.model);
+       
+       if (self.spawnflags & 1) // FLOATING
+               self.noalign = 1;
+       
+       if (self.noalign)
+               self.movetype = MOVETYPE_NONE;
+       else
+               self.movetype = MOVETYPE_TOSS;
+               
+       precache_sound(self.noise);
+               
+       self.mdl = self.model;
+       self.effects = EF_LOWPRECISION;
+       setmodel(self, self.model);
+       //setsize(self, '-16 -16 -24', '16 16 32');
+       setorigin(self, self.origin + '0 0 32');
+       setsize(self, '-16 -16 -56', '16 16 0');
+       self.modelflags |= MF_ROTATE;
+       self.solid = SOLID_TRIGGER;
+       
+       if (!self.noalign)
+       {
+               // first nudge it off the floor a little bit to avoid math errors
+               setorigin(self, self.origin + '0 0 1');
+               // note droptofloor returns FALSE if stuck/or would fall too far
+               droptofloor();
+       }
+
+       self.touch = item_key_touch;
+};
+
+
+/*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
+A key entity.
+The itemkeys should contain one of the following key IDs:
+1 - GOLD key - 
+2 - SILVER key
+4 - BRONZE key
+8 - RED keycard
+16 - BLUE keycard
+32 - GREEN keycard
+Custom keys:
+... - last key is 1<<23
+Keys with bigger Id than 32 don't have a default netname and model, if you use one of them, you MUST provide those.
+-----------KEYS------------
+colormod: color of the key (default: '.9 .9 .9').
+itemkeys: a key Id.
+message: message to print when player picks up this key.
+model: custom key model to use.
+netname: the display name of the key.
+noise: custom sound to play when player picks up the key.
+-------- SPAWNFLAGS --------
+FLOATING: the item will float in air, instead of aligning to the floor by falling
+---------NOTES----------
+This is the only correct way to put keys on the map!
+
+itemkeys MUST always have exactly one bit set.
+*/
+void spawnfunc_item_key() {
+       local string _model, _netname;
+       local vector _colormod;
+       
+       // reject this entity if more than one key was set!
+       if (self.itemkeys>0 && (self.itemkeys & (self.itemkeys-1)) != 0) {
+               objerror("item_key.itemkeys must contain only 1 bit set specifying the key it represents!");
+               remove(self);
+               return;
+       }
+
+       // find default netname and colormod
+       switch(self.itemkeys) {
+       case 1:
+               _netname = "GOLD key";
+               _colormod = '1 .9 0';
+               break;
+               
+       case 2:
+               _netname = "SILVER key";
+               _colormod = '.9 .9 .9';
+               break;
+               
+       case 4:
+               _netname = "BRONZE key";
+               _colormod = '.6 .25 0';
+               break;
+               
+       case 8:
+               _netname = "RED keycard";
+               _colormod = '.9 0 0';
+               break;
+               
+       case 16:
+               _netname = "BLUE keycard";
+               _colormod = '0 0 .9';
+               break;
+               
+       case 32:
+               _netname = "GREEN keycard";
+               _colormod = '0 .9 0';
+               break;
+       
+       default:
+               if (!self.netname) {
+                       objerror("item_key doesn't have a default name for this key and a custom one was not specified!");
+                       remove(self);
+                       return;
+               } else if (!self.colormod) {
+                       _colormod = '1 1 1';
+               }
+               break;
+               
+       }
+       
+       // find default model
+       if (self.itemkeys <= ITEM_KEY_BIT(2)) {
+               _model = "models/keys/key.md3";
+       } else if (self.itemkeys >= ITEM_KEY_BIT(3) && self.itemkeys <= ITEM_KEY_BIT(5)) {
+               _model = "models/keys/key.md3"; // FIXME: replace it by a keycard model!
+       } else if (!self.model) {
+               objerror("item_key doesn't have a default model for this key and a custom one was not specified!");
+               remove(self);
+               return;
+       }
+       
+       // set defailt netname
+       if (!self.netname)
+               self.netname = _netname;
+       
+       // set default colormod
+       if (!self.colormod)
+               self.colormod = _colormod;
+       
+       // set default model
+       if (!self.model)
+               self.model = _model;
+       
+       // set default pickup message
+       if (!self.message)
+               self.message = strzone(strcat("You've picked up the ", self.netname, "!"));
+
+       if (!self.noise)
+               self.noise = "misc/itempickup.wav";
+       
+       // save the name for later
+       item_keys_names[lowestbit(self.itemkeys)] = self.netname;
+
+       // put the key on the map       
+       spawn_item_key();
+}
+
+/*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
+SILVER key.
+-----------KEYS------------
+colormod: color of the key (default: '.9 .9 .9').
+message: message to print when player picks up this key.
+model: custom model to use.
+noise: custom sound to play when player picks up the key.
+-------- SPAWNFLAGS --------
+FLOATING: the item will float in air, instead of aligning to the floor by falling
+---------NOTES----------
+Don't use this entity on new maps! Use item_key instead.
+*/
+void spawnfunc_item_key1(void) {
+       self.classname = "item_key";
+       self.itemkeys = ITEM_KEY_BIT(1);
+       spawnfunc_item_key();
+};
+
+/*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
+GOLD key.
+-----------KEYS------------
+colormod: color of the key (default: '1 .9 0').
+message: message to print when player picks up this key.
+model: custom model to use.
+noise: custom sound to play when player picks up the key.
+-------- SPAWNFLAGS --------
+FLOATING: the item will float in air, instead of aligning to the floor by falling
+---------NOTES----------
+Don't use this entity on new maps! Use item_key instead.
+*/
+void spawnfunc_item_key2(void) {
+       self.classname = "item_key";
+       self.itemkeys = ITEM_KEY_BIT(0);
+       spawnfunc_item_key();
+};
+
+
+/*
+================================
+trigger_keylock
+================================
+*/
+
+/**
+ * trigger givent targets
+ */
+void trigger_keylock_trigger(string s) {
+       local entity t, stemp, otemp, atemp;
+       
+       stemp = self;
+       otemp = other;
+       atemp = activator;
+       
+       
+       for(t = world; (t = find(t, targetname, s)); )
+               if (t.use) {
+                       self = t;
+                       other = stemp;
+                       activator = atemp;
+                       self.use();
+               }
+       
+       self = stemp;
+       other = otemp;
+       activator = atemp;
+};
+
+/**
+ * kill killtarget of trigger keylock.
+ */
+void trigger_keylock_kill(string s) {
+       local entity t;
+       for(t = world; (t = find(t, targetname, s)); )
+               remove(t);
+};
+
+void trigger_keylock_touch(void) {
+       local float key_used, started_delay;
+       
+       key_used = FALSE;
+       started_delay = FALSE;
+       
+       // only player may trigger the lock
+       if (other.classname != "player")
+               return;
+       
+       
+       // check silver key
+       if (self.itemkeys)
+               key_used = item_keys_usekey(self, other);
+       
+       activator = other;
+       
+       if (self.itemkeys) {
+               // at least one of the keys is missing
+               if (key_used) {
+                       // one or more keys were given, but others are still missing!
+                       play2(other, self.noise1);
+                       centerprint(other, strcat("You also need ", item_keys_keylist(self.itemkeys), "!"));
+                       other.key_door_messagetime = time + 2;
+               } else if (other.key_door_messagetime <= time) {
+                       // no keys were given
+                       play2(other, self.noise2);
+                       centerprint(other, strcat("You need ", item_keys_keylist(self.itemkeys), "!"));
+                       other.key_door_messagetime = time + 2;
+               }
+               
+               // trigger target2
+               if (self.delay <= time || started_delay == TRUE)
+               if (self.target2) {
+                       trigger_keylock_trigger(self.target2);
+                       started_delay = TRUE;
+                       self.delay = time + self.wait;
+               }
+       } else {
+               // all keys were given!
+               play2(other, self.noise);
+               centerprint(other, self.message);
+               
+               if (self.target)
+                       trigger_keylock_trigger(self.target);
+                       
+               if (self.killtarget)
+                       trigger_keylock_kill(self.killtarget);
+               
+               remove(self);
+       }
+       
+};
+
+/*QUAKED trigger_keylock (.0 .5 .8) ?
+Keylock trigger.  Must target other entities.
+This trigger will trigger target entities when all required keys are provided.
+-------- KEYS --------
+itemkeys: A bit field with key IDs that are needed to open this lock.
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (3 is default)
+target: trigger all entities with this targetname when triggered and all keys have been given to it, then remove this trigger
+target2: trigger all entities with this targetname when triggered without giving it all the required keys.
+killtarget: remove all entities with this targetname when triggered with all the needed keys.
+message: print this message to the player who activated the trigger when all needed keys have been given.
+message2: print this message to the player who activated the trigger when not all of the needed keys have been given.
+noise: sound to play when lock gets unlocked (default: see sounds)
+noise1: sound to play when only some of the needed key were used but not all (default: misc/decreasevalue.wav)
+noise2: sound to play when a key is missing (default: misc/talk.wav)
+wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4.
+---------NOTES----------
+If spawned without any key specified in itemkeys, this trigger will display an error and remove itself.
+message2 and noise2 will be resent to the player every 2 seconds while he is in the trigger zone.
+*/
+void spawnfunc_trigger_keylock(void) {
+       if (!self.itemkeys) {
+               remove(self);
+               return;
+       }
+
+       // set unlocked message 
+       if (!self.message)
+               self.message = "Unlocked!";
+       
+       // set default unlock noise
+       if (!self.noise) {
+               if (self.sounds == 1)
+                       self.noise = "misc/secret.wav";
+               else if (self.sounds == 2)
+                       self.noise = "misc/talk.wav";
+               else //if (self.sounds == 3) {
+                       self.noise = "misc/trigger1.wav";
+       }
+       
+       // set default use key sound
+       if (!self.noise1)
+               self.noise1 = "misc/decreasevalue.wav";
+       
+       // set closed sourd
+       if (!self.noise2)
+               self.noise2 = "misc/talk.wav";
+       
+       // delay between triggering message2 and trigger2
+       if (!self.wait)
+               self.wait = 5;
+       
+       // precache sounds
+       precache_sound(self.noise);
+       precache_sound(self.noise1);
+       precache_sound(self.noise2);
+       
+       EXACTTRIGGER_INIT;
+       
+       self.touch = trigger_keylock_touch;
+};
+
+
diff --git a/qcsrc/server/item_key.qh b/qcsrc/server/item_key.qh
new file mode 100644 (file)
index 0000000..24ef1e9
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Returns the bit ID of a key
+ */
+#define ITEM_KEY_BIT(n)        ( bitshift(1, n) )
+
+#define ITEM_KEY_MAX   24
+
+/**
+ * list of key names.
+ */
+string item_keys_names[ITEM_KEY_MAX];
+
+/**
+ * Use keys from p on l.
+ * Returns TRUE if any new keys were given, FALSE otherwise.
+ */
+float item_keys_usekey(entity l, entity p);
+
+/**
+ * Returns a string with a comma separated list of key names, as specified in keylist.
+ */
+string item_keys_keylist(float keylist);
+
index 27c04f8a4d02499a2549a81c9aedec74ec53958e..7e675922833eb1107ffacfdcfedeb3c4269be048 100644 (file)
@@ -583,6 +583,7 @@ void GetCvars(float f)
        get_cvars_s = s;
        MUTATOR_CALLHOOK(GetCvars);
        GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
+       GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
        GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
index e26280e61a695cf0fedcff92ff3fd487c803a830..73b23bbd3f224201ecffa53725fe544a3b225573 100644 (file)
@@ -159,3 +159,32 @@ MUTATOR_HOOKABLE(PlayerUseKey);
        // called when the use key is pressed
        // if MUTATOR_RETURNVALUE is 1, don't do anything
        // return 1 if the use key actually did something
+
+MUTATOR_HOOKABLE(SV_ParseClientCommand);
+       // called when a client command is parsed
+       // NOTE: hooks MUST start with if(MUTATOR_RETURNVALUE) return 0;
+       // NOTE: return 1 if you handled the command, return 0 to continue handling
+       // NOTE: THESE HOOKS MUST NEVER EVER CALL tokenize()
+       // INPUT
+       string cmd_name; // command name
+       float cmd_argc; // also, argv() can be used
+       string cmd_string; // whole command, use only if you really have to
+       /*
+               // example:
+               MUTATOR_HOOKFUNCTION(foo_SV_ParseClientCommand)
+               {
+                       if(MUTATOR_RETURNVALUE) // command was already handled?
+                               return 0;
+                       if(cmd_name == "echocvar" && cmd_argc >= 2)
+                       {
+                               print(cvar_string(argv(1)), "\n");
+                               return 1;
+                       }
+                       if(cmd_name == "echostring" && cmd_argc >= 2)
+                       {
+                               print(substring(cmd_string, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), "\n");
+                               return 1;
+                       }
+                       return 0;
+               }
+       */
index 8d3511eceda0750e74266d5649133b69f9c15e84..9134353e015574860dc4478938633ba80e3a56ec 100644 (file)
@@ -3,6 +3,7 @@ void ka_TouchEvent(void);
 void ka_RespawnBall(void);
 void ka_DropEvent(entity);
 void ka_TimeScoring(void);
+void ka_EventLog(string, entity);
 
 entity ka_ball;
 
@@ -125,6 +126,7 @@ void ka_TouchEvent() // runs any time that the ball comes in contact with someth
        other.effects |= autocvar_g_keepaway_ballcarrier_effects;
        
        // messages and sounds
+       ka_EventLog("pickup", other);
        Send_KillNotification(other.netname, "", "", KA_PICKUPBALL, MSG_KA);
        WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
        WriteString(MSG_BROADCAST, strcat(other.netname, "^7 has picked up the ball!"));
@@ -167,6 +169,7 @@ void ka_DropEvent(entity plyr) // runs any time that a player is supposed to los
        plyr.effects &~= autocvar_g_keepaway_ballcarrier_effects;
 
        // messages and sounds
+       ka_EventLog("dropped", plyr);
        Send_KillNotification(plyr.netname, "", "", KA_DROPBALL, MSG_KA);
        WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
        WriteString(MSG_BROADCAST, strcat(plyr.netname, "^7 has dropped the ball!"));
@@ -205,6 +208,12 @@ void ka_TimeScoring()
        }
 }
 
+void ka_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
+{
+       if(autocvar_sv_eventlog)
+               GameLogEcho(strcat(":ka:", mode, ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
 MUTATOR_HOOKFUNCTION(ka_Scoring)
 {
        if((frag_attacker != frag_target) && (frag_attacker.classname == "player"))
index 3d1e3970a1f34a31fdafda89a5367a8d803c832c..b5307d42893dda6cbb1a8715ac92c6209a20c50e 100644 (file)
@@ -64,6 +64,8 @@ vote.qh
 
 playerdemo.qh
 
+item_key.qh
+
 scores_rules.qc
 
 miscfunctions.qc
@@ -110,6 +112,7 @@ w_all.qc
 t_items.qc
 cl_weapons.qc
 cl_impulse.qc
+item_key.qc
 
 ent_cs.qc
 
index ce5828affc0194d1c051cf26b3412b6ff2688c61..eb386005d16f16201ba064b01d32e799b1a85bee 100644 (file)
@@ -275,7 +275,7 @@ void SV_OnEntityPreSpawnFunction()
                        s = substring(s, 1, -1);
                }
 
-               n = tokenize(s);
+               n = tokenize_console(s);
                for(i = 0; i < n; ++i)
                {
                        s = argv(i);
index 9ac9df289243bd36ba3028cec515d4f5394117cb..f44dcb7b9476be220390010163dd175108282428 100644 (file)
@@ -885,6 +885,7 @@ void door_go_up()
 }
 
 
+
 /*
 =============================================================================
 
@@ -893,6 +894,50 @@ ACTIVATION FUNCTIONS
 =============================================================================
 */
 
+float door_check_keys(void) {
+       local entity door;
+       
+       
+       if (self.owner)
+               door = self.owner;
+       else
+               door = self;
+       
+       // no key needed
+       if not(door.itemkeys)
+               return TRUE;
+
+       // this door require a key
+       // only a player can have a key
+       if (other.classname != "player")
+               return FALSE;
+       
+       if (item_keys_usekey(door, other)) {
+               // some keys were used
+               if (other.key_door_messagetime <= time) {
+                       play2(other, "misc/talk.wav");
+                       centerprint(other, strcat("You also need ", item_keys_keylist(door.itemkeys), "!"));
+                       other.key_door_messagetime = time + 2;
+               }
+       } else {
+               // no keys were used
+               if (other.key_door_messagetime <= time) {
+                       play2(other, "misc/talk.wav");
+                       centerprint(other, strcat("You need ", item_keys_keylist(door.itemkeys), "!"));
+                       other.key_door_messagetime = time + 2;
+               }
+       }
+
+       if (door.itemkeys) {
+               // door is now unlocked
+               play2(other, "misc/talk.wav");
+               centerprint(other, "Door unlocked!");
+               return TRUE;
+       } else
+               return FALSE;
+}
+
+
 void door_fire()
 {
        entity  oself;
@@ -958,6 +1003,7 @@ void door_use()
        entity oself;
 
        //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
+       
        if (self.owner)
        {
                oself = self;
@@ -971,11 +1017,16 @@ void door_use()
 void door_trigger_touch()
 {
        if (other.health < 1)
-       if not(other.iscreature && other.deadflag == DEAD_NO)
-               return;
+               if not(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;
@@ -992,6 +1043,12 @@ void door_damage(entity inflictor, entity attacker, float damage, float deathtyp
                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;
@@ -1271,13 +1328,17 @@ void LinkDoors()
 }
 
 
-/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK x x TOGGLE
+/*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.
@@ -1311,8 +1372,17 @@ void door_reset()
        self.think = SUB_Null;
 }
 
+// spawnflags require key (for now only func_door)
+#define SPAWNFLAGS_GOLD_KEY 8
+#define 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 ();
@@ -1326,8 +1396,9 @@ void spawnfunc_func_door()
        self.blocked = door_blocked;
        self.use = door_use;
 
-    if(self.spawnflags & 8)
-        self.dmg = 10000;
+       // FIXME: undocumented flag 8, originally (Q1) GOLD_KEY
+       // if(self.spawnflags & 8)
+       //      self.dmg = 10000;
 
     if(self.dmg && (!self.message))
                self.message = "was squished";
index 454557010d11f8b3328aa8a5381e5ad11cdc634b..6c2cce6a73341ad4d3b80fcd25a19233b269b688 100644 (file)
@@ -46,24 +46,45 @@ entity toast(entity from, float range, float damage)
 
 float turret_tesla_firecheck()
 {
-    if not (turret_stdproc_firecheck())
-        return 0;
+    // g_turrets_targetscan_maxdelay forces a target re-scan at least this often
+    float do_target_scan;
+    
+    if((self.target_select_time + autocvar_g_turrets_targetscan_maxdelay) < time)
+        do_target_scan = 1;
+
+    // Old target (if any) invalid?
+    if(self.target_validate_time < time)
+    if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0)
+    {
+        self.enemy = world;
+        self.target_validate_time = time + 0.5;
+        do_target_scan = 1;
+    }
 
-    self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;
+    // But never more often then g_turrets_targetscan_mindelay!
+    if (self.target_select_time + autocvar_g_turrets_targetscan_mindelay > time)
+        do_target_scan = 0;
 
-    self.enemy = turret_select_target();
+    if(do_target_scan)
+    {
+        self.enemy = turret_select_target();
+        self.target_select_time = time;
+    }
+
+    if not (turret_stdproc_firecheck())
+        return 0;
 
     if(self.enemy)
         return 1;
 
     return 0;
-
 }
 
+
 void turret_tesla_fire()
 {
-    entity e,t;
-    float d,r,i;
+    entity e, t;
+    float d, r, i;
 
     //w_deathtypestring = "discoverd how a tesla coil works";
 
index 08c56121b5c6a110661fe6c6977bc90edee2d992..1a995191c2f81025e9c9235d145649f0b9f82c42 100644 (file)
@@ -353,6 +353,8 @@ void fireBallisticBullet_trace_callback(vector start, vector hit, vector end)
 {
        if(vlen(trace_endpos - fireBallisticBullet_trace_callback_ent.origin) > 16)
                zcurveparticles_from_tracetoss(fireBallisticBullet_trace_callback_eff, fireBallisticBullet_trace_callback_ent.origin, trace_endpos, fireBallisticBullet_trace_callback_ent.velocity);
+       WarpZone_trace_forent = world;
+       self.owner = world;
 }
 
 void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float headshotbonus, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant)
@@ -416,7 +418,8 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
 
                if(lag)
                        FOR_EACH_PLAYER(pl)
-                               antilag_takeback(pl, time - lag);
+                               if(pl != self)
+                                       antilag_takeback(pl, time - lag);
 
                oldself = self;
                self = proj;
@@ -438,15 +441,6 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                        trace_fraction = 0;
                        fireBallisticBullet_trace_callback_ent = self;
                        fireBallisticBullet_trace_callback_eff = eff;
-                       // FIXME can we somehow do this with just ONE trace?
-                       WarpZone_TraceToss(self, self.owner);
-                       if(self.owner && WarpZone_trace_firstzone)
-                       {
-                               self.owner = world;
-                               self.velocity = v0;
-                               self.gravity = g0;
-                               continue;
-                       }
                        WarpZone_TraceToss_ThroughZone(self, self.owner, world, fireBallisticBullet_trace_callback);
                        self.velocity = v0;
                        self.gravity = g0;
@@ -503,7 +497,8 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
 
                if(lag)
                        FOR_EACH_PLAYER(pl)
-                               antilag_restore(pl);
+                               if(pl != self)
+                                       antilag_restore(pl);
 
                remove(proj);
 
index c10d1f544a2d01e67fdef7e2c3b8b396fe53b515..2e4aa4957df67e7d201fa2b11f216f300888d85e 100644 (file)
@@ -240,6 +240,9 @@ float w_tuba(float req)
                precache_model ("models/weapons/g_tuba.md3");
                precache_model ("models/weapons/v_tuba.md3");
                precache_model ("models/weapons/h_tuba.iqm");
+               precache_model ("models/weapons/g_akordeon.md3");
+               precache_model ("models/weapons/v_akordeon.md3");
+               precache_model ("models/weapons/h_akordeon.iqm");
 
                //float i;
                //for(i = -18; i <= +27; ++i)
index 0f1337d18fb614c447e8efbac9be7d5fc6645040..f09f25bdcd13d320e5b9277da55795865d5c3e88 100644 (file)
@@ -191,6 +191,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
        entity wz;
        vector vf, vr, vu;
 
+       WarpZone_trace_forent = forent;
        WarpZone_trace_firstzone = world;
        WarpZone_trace_lastzone = world;
        WarpZone_Trace_InitTransform();
@@ -206,7 +207,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                }
                else
                {
-                       tracebox(org, mi, ma, end, nomonsters, forent);
+                       tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
                        if(cb)
                                cb(org, trace_endpos, end);
                        return;
@@ -229,8 +230,8 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                        nomonsters_adjusted = nomonsters;
                        break;
        }
-       if((contentshack = (forent.dphitcontentsmask && !(forent.dphitcontentsmask & DPCONTENTS_SOLID))))
-               BITSET_ASSIGN(forent.dphitcontentsmask, DPCONTENTS_SOLID);
+       if((contentshack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID))))
+               BITSET_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
 
        // if starting in warpzone, first transform
        wz = WarpZone_Find(org + mi, org + ma);
@@ -262,7 +263,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                        trace_ent = world;
                        break;
                }
-               tracebox(org, mi, ma, end, nomonsters_adjusted, forent);
+               tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
                if(cb)
                        cb(org, trace_endpos, end);
                if(sol < 0)
@@ -273,7 +274,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                        break;
                if(trace_ent.classname != "trigger_warpzone")
                {
-                       if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & forent.dphitcontentsmask) == DPCONTENTS_SOLID))
+                       if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
                        {
                                // continue the trace, ignoring this hit (we only care for warpzones)
                                org = trace_endpos + normalize(end - org);
@@ -302,13 +303,13 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                end = WarpZone_TransformOrigin(wz, end);
 
                // we got warped, so let's step back a bit
-               tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, forent);
+               tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
                org = trace_endpos;
        }
        WarpZone_MakeAllOther();
 :fail
        if(contentshack)
-               BITCLR_ASSIGN(forent.dphitcontentsmask, DPCONTENTS_SOLID);
+               BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
        trace_startsolid = sol;
        v_forward = vf;
        v_right = vr;
@@ -334,13 +335,14 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
        o0 = e.origin;
        v0 = e.velocity;
 
+       WarpZone_trace_forent = forent;
        WarpZone_trace_firstzone = world;
        WarpZone_trace_lastzone = world;
        WarpZone_Trace_InitTransform();
        WarpZone_tracetoss_time = 0;
        if(!warpzone_warpzones_exist)
        {
-               tracetoss(e, forent);
+               tracetoss(e, WarpZone_trace_forent);
                if(cb)
                        cb(e.origin, trace_endpos, trace_endpos);
                dt = vlen(e.origin - o0) / vlen(e.velocity);
@@ -384,7 +386,7 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
                        trace_ent = world;
                        break;
                }
-               tracetoss(e, forent);
+               tracetoss(e, WarpZone_trace_forent);
                if(cb)
                        cb(e.origin, trace_endpos, trace_endpos);
                dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
@@ -415,7 +417,7 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
 
                // we got warped, so let's step back a bit
                e.velocity = -e.velocity;
-               tracetoss(e, forent);
+               tracetoss(e, WarpZone_trace_forent);
                dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
                WarpZone_tracetoss_time -= dt;
                e.origin = trace_endpos;
index 1dc12b8cfe97f60bc75d5139bb653a04b1eacf3e..c2f36bea868d8baf7ad06c37294b3b7bb2316a24 100644 (file)
@@ -25,6 +25,7 @@ void WarpZone_MakeAllSolid();
 void WarpZone_MakeAllOther();
 
 #define MOVE_NOTHING -1
+entity WarpZone_trace_forent; // temp, callback is allowed to change it
 typedef void(vector start, vector hit, vector end) WarpZone_trace_callback_t; // called on every elementary trace
 const var WarpZone_trace_callback_t WarpZone_trace_callback_t_null;
 entity WarpZone_trace_transform; // transform accumulator during a trace