]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into mario/mutator_minstagib
authorMario <mario.mario@y7mail.com>
Thu, 31 Jan 2013 10:44:31 +0000 (21:44 +1100)
committerMario <mario.mario@y7mail.com>
Thu, 31 Jan 2013 10:44:31 +0000 (21:44 +1100)
30 files changed:
_hud_common.cfg
bf.cfg [new file with mode: 0644]
defaultXonotic.cfg
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/autocvars.qh
qcsrc/menu/xonotic/dialog_settings_input.c
qcsrc/menu/xonotic/keybinder.c
qcsrc/server/autocvars.qh
qcsrc/server/cl_physics.qc
qcsrc/server/cl_weapons.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/base.qc
qcsrc/server/mutators/base.qh
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/gamemode_freezetag.qc
qcsrc/server/mutators/gamemode_keepaway.qc
qcsrc/server/mutators/gamemode_keyhunt.qc
qcsrc/server/mutators/gamemode_nexball.qc
qcsrc/server/mutators/gamemode_onslaught.qc
qcsrc/server/mutators/mutator_dodging.qc
qcsrc/server/mutators/mutator_new_toys.qc
qcsrc/server/mutators/mutator_nix.qc
qcsrc/server/mutators/mutator_physical_items.qc [new file with mode: 0644]
qcsrc/server/mutators/mutator_superspec.qc
qcsrc/server/mutators/mutators.qh
qcsrc/server/mutators/sandbox.qc
qcsrc/server/progs.src
qcsrc/server/t_items.qc

index 5179bb2abfcddf226f547c457d0877e39d78f5b7..ba88a2a4fa6fedcd4f2343caeb2e8b1445b1893e 100644 (file)
@@ -35,6 +35,7 @@ alias hud_panel_radar_maximized "cl_cmd hud radar"
 // other hud cvars
 seta hud_showbinds 1   "what to show in the HUD to indicate certain keys to press: 0 display commands, 1 bound keys, 2 both"
 seta hud_showbinds_limit 2     "maximum number of bound keys to show for a command. 0 for unlimited"
+set _hud_showbinds_reload 0    "set it to 1 to reload binds if you changed any. It is reset to 0 automatically"
 
 seta hud_colorflash_alpha 0.5 "starting alpha of the color flash"
 
diff --git a/bf.cfg b/bf.cfg
new file mode 100644 (file)
index 0000000..6445def
--- /dev/null
+++ b/bf.cfg
@@ -0,0 +1,98 @@
+// DP console is TURING COMPLETE!
+
+alias _bf_vcall "${$1} ${2- ?}"
+
+// number system
+// Xon RPN: set $_bf_zero 0
+// Xon RPN: alias _bf_inc "rpn /$1 $2 1 add def"
+// Xon RPN: alias _bf_dec "rpn /$1 $2 1 sub def"
+
+// unary
+// decimal | unary
+//       0 | 0
+//       1 | +
+//       2 | ++
+//      -1 | -
+//      -2 | --
+alias _bf_zero "set $1 0"
+alias _bf_one "set $1 +"
+alias _bf_minus_one "set $1 -"
+alias _bf_return_3 "set $1 $3"
+alias _bf_return_4 "set $1 $4"
+set _bf_zero "0"
+alias _bf_inc_loop1 "set _bf_tmp_$3 _bf_inc_loop2; set _bf_tmp_+$2 _bf_return_3; _bf_vcall _bf_tmp_$3 $*"
+alias _bf_inc_loop2 "set _bf_tmp_$2 _bf_inc_loop3; set _bf_tmp_-$4 _bf_return_4; _bf_vcall _bf_tmp_$2 $*"
+alias _bf_inc_loop3 "_bf_inc_loop1 $1 $2 +$3 -$4"
+alias _bf_inc "set _bf_tmp_$2 _bf_inc_loop1; set _bf_tmp_0 _bf_one; set _bf_tmp_- _bf_zero; _bf_vcall _bf_tmp_$2 $1 $2 + -"
+alias _bf_dec_loop1 "set _bf_tmp_$3 _bf_dec_loop2; set _bf_tmp_-$2 _bf_return_3; _bf_vcall _bf_tmp_$3 $*"
+alias _bf_dec_loop2 "set _bf_tmp_$2 _bf_dec_loop3; set _bf_tmp_+$4 _bf_return_4; _bf_vcall _bf_tmp_$2 $*"
+alias _bf_dec_loop3 "_bf_dec_loop1 $1 $2 -$3 +$4"
+alias _bf_dec "set _bf_tmp_$2 _bf_dec_loop1; set _bf_tmp_0 _bf_minus_one; set _bf_tmp_+ _bf_zero; _bf_vcall _bf_tmp_$2 $1 $2 - +"
+// end of unary
+
+// interpreter state
+set bf_input ""
+alias _bf_clearstate "set _bf_left \"\"; set _bf_right \"\"; set _bf_register $_bf_zero; set _bf_execstack \"\""
+alias _bf_dumpstate "echo rev($_bf_left) < $_bf_register > $_bf_right"
+
+// a STACK!
+alias _bf_pop_get "set $2 \"${3 ?}\"; set $1 \"${4- ?}\""
+alias _bf_pop_dispatch "_bf_pop_get $1 $2 $_bf_popstack_"
+// usage: _bf_pop stackvar outvar defaultvalue
+alias _bf_pop "set _bf_popstack_ \"${$1 ?}\"; set \"_bf_popstack_${$1 ?}\" \"${3 ?}\"; _bf_pop_dispatch $*"
+// usage: _bf_push stackvar value
+alias _bf_push "set $1 \"$2 ${$1 ?}\""
+
+// skip mode: skip until matching ] (1 on _bf_execstack), then continue executing
+alias _bf_skip_ "echo PROGRAMM FELL OFF THE EDGE"
+alias _bf_skip_+ "_bf_skip_${* ?}"
+alias _bf_skip_- "_bf_skip_${* ?}"
+alias _bf_skip_< "_bf_skip_${* ?}"
+alias _bf_skip_> "_bf_skip_${* ?}"
+alias _bf_skip_. "_bf_skip_${* ?}"
+alias _bf_skip_, "_bf_skip_${* ?}"
+alias _bf_skip_endloop_0 "_bf_skip_${* ?}" // continue skipping
+alias _bf_skip_endloop_1 "bf_${* ?}" // back to execution
+alias _bf_skip_endloop_dispatch "_bf_skip_endloop_$_bf_stackval ${* ?}"
+alias _bf_skip_] "_bf_pop _bf_execstack _bf_stackval; _bf_skip_endloop_dispatch ${* ?}"
+alias _bf_skip_[ "_bf_push _bf_execstack 0; _bf_skip_${* ?}"
+// enter
+alias _bf_skiploop "_bf_push _bf_execstack 1; _bf_skip_${* ?}"
+
+// run mode: execute until matching ] (1 on _bf_execstack), then exit
+alias bf_ "echo PROGRAMM FELL OFF THE EDGE"
+alias bf_+ "_bf_inc _bf_register $_bf_register; bf_${* ?}"
+alias bf_- "_bf_dec _bf_register $_bf_register; bf_${* ?}"
+alias bf_< "_bf_push _bf_left $_bf_register; _bf_pop _bf_right _bf_register $_bf_zero; bf_${* ?}"
+alias bf_> "_bf_push _bf_right $_bf_register; _bf_pop _bf_left _bf_register $_bf_zero; bf_${* ?}"
+alias bf_. "echo $_bf_register; bf_${* ?}"
+// note: on EOF, we don't change the register value!
+alias _bf_input_get "set _bf_register $_bf_inputval; bf_${* ?}" // read input
+alias _bf_input_eof "bf_${* ?}" // at EOF, just continue
+alias _bf_input_dispatch "set _bf_inputval_ _bf_input_get; set _bf_inputval_$_bf_inputval _bf_input_eof; _bf_vcall _bf_inputval_ ${* ?}"
+alias bf_, "_bf_pop bf_input _bf_inputval; _bf_input_dispatch ${* ?}"
+alias _bf_endloop_0 "echo IN SKIP MODE, EXCEPT NOT"
+alias _bf_endloop_1 "" // back to caller
+alias _bf_endloop_ "echo PROGRAMM FELL OFF THE EDGE"
+alias _bf_endloop_dispatch "_bf_endloop_$_bf_stackval ${* ?}"
+alias bf_] "_bf_pop _bf_execstack _bf_stackval; _bf_endloop_dispatch ${* ?}"
+// enter
+alias _bf_runloop "_bf_push _bf_execstack 1; bf_$*; bf_[ ${* ?}"
+// loop dispatcher
+alias bf_[ "set _bf_runloop_$_bf_zero _bf_runloop; set _bf_runloop_$_bf_register _bf_skiploop; _bf_vcall _bf_runloop_$_bf_zero ${* ?}"
+
+// start it
+alias bf_exec "_bf_clearstate; _bf_push _bf_execstack 1; bf_$1 ]"
+
+// "cat"
+// Xon RPN: bf_input "1 2 3 4 5"
+bf_input "+ ++ +++ ++++ +++++"
+bf_exec "[ - ] - , + [ - . + [ - ] - , + ]"
+
+// output 42
+// Xon RPN: bf_input "12 6 9"
+bf_input "++++++++++++ ++++++ +++++++++"
+bf_exec ", > , > , < [ > [ - > + > + < < ] > > [ - < < + > > ] < < < - ] < [ - > > > - < < < ] > > > ."
+
+// hello world
+bf_exec "+ + + + + + + + + + [ > + + + + + + + > + + + + + + + + + + > + + + > + < < < < - ] > + + . > + . + + + + + + + . . + + + . > + + . < < + + + + + + + + + + + + + + + . > . + + + . - - - - - - . - - - - - - - - . > + . > ."
index 1ad85c8bd01da28797e5aaa8cf42a8a97fd3b321..c51cc0c717cd3765e5e741627f3824759e2b793b 100644 (file)
@@ -1067,6 +1067,10 @@ alias sethostname "set menu_use_default_hostname 0; hostname $*"
 
 set sv_foginterval 1 "force enable fog in regular intervals"
 
+set g_physical_items 0 "1 uses ODE physics for dropped weapons, 2 for all items, requires physics_ode to be enabled"
+set g_physical_items_damageforcescale 3 "how affected physical weapons are by damage"
+set g_physical_items_reset 1 "return map items to their original lotation after being picked up"
+
 // Audio track names (for old-style "cd loop NUMBER" usage)
 set _cdtrack_first "1"
 alias _cdtrack_0 "g_cdtracks_remaplist \"$g_cdtracks_remaplist $1\""
index b75fc166e585359c982d319e8bf1de0c168e60d7..3e5deb104d6674735d53bae5e40b618cb6dcbcf6 100644 (file)
@@ -1255,7 +1255,8 @@ string getcommandkey(string text, string command)
                                        keys = strcat(keys, ", ", keynumtostring(k));
 
                                ++l;
-                               if (autocvar_hud_showbinds_limit > 0 && autocvar_hud_showbinds_limit >= l) break;
+                               if (autocvar_hud_showbinds_limit > 0 && autocvar_hud_showbinds_limit <= l)
+                                       break;
                        }
 
                }
index 940f810573f3283f007b310855df39813e939c8f..d1c10405805f93f4135b3abba6bde4391ee968c2 100644 (file)
@@ -392,6 +392,13 @@ void CSQC_UpdateView(float w, float h)
 
        hud = getstati(STAT_HUD);
 
+       if(autocvar__hud_showbinds_reload) // menu can set this one
+       {
+               db_close(binddb);
+               binddb = db_create();
+               cvar_set("_hud_showbinds_reload", "0");
+       }
+
        if(checkextension("DP_CSQC_MINFPS_QUALITY"))
                view_quality = getproperty(VF_MINFPS_QUALITY);
        else
index cb06932e45e00eefaa25e29dd3abf2e25df753c4..94cd1a5c03bb4b03450aa61a3facea5e0e874145 100644 (file)
@@ -326,6 +326,7 @@ var float autocvar_hud_panel_weapons_timeout_speed_out = 0.75;
 float autocvar_hud_progressbar_alpha;
 float autocvar_hud_showbinds;
 float autocvar_hud_showbinds_limit;
+float autocvar__hud_showbinds_reload;
 float autocvar_hud_shownames;
 float autocvar_hud_shownames_enemies;
 float autocvar_hud_shownames_crosshairdistance;
index 96bf5e5c67d207f3b8b864535eca34c2a6628a85..daa8f3ff104fe3bcfc659fd32f7762c2ebd1fc50 100644 (file)
@@ -40,6 +40,7 @@ void XonoticInputSettingsTab_fill(entity me)
                me.TD(me, 1, 1, e = makeXonoticButton(_("Clear"), '0 0 0'));
                        e.onClick = KeyBinder_Bind_Clear;
                        e.onClickEntity = kb;
+                       kb.clearButton = e;
 
        me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "con_closeontoggleconsole", _("Pressing \"enter console\" key also closes it")));
index 1107e60abc6b3296e77dd9582bbe6613a267ef32..739be1b056aa908da09d5ab1bfded18f3ef30708 100644 (file)
@@ -22,6 +22,7 @@ CLASS(XonoticKeyBinder) EXTENDS(XonoticListBox)
        ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0)
        ATTRIB(XonoticKeyBinder, userbindEditButton, entity, NULL)
        ATTRIB(XonoticKeyBinder, keyGrabButton, entity, NULL)
+       ATTRIB(XonoticKeyBinder, clearButton, entity, NULL)
        ATTRIB(XonoticKeyBinder, userbindEditDialog, entity, NULL)
        METHOD(XonoticKeyBinder, editUserbind, void(entity, string, string, string))
 ENDCLASS(XonoticKeyBinder)
@@ -80,6 +81,8 @@ void replace_bind(string from, string to)
                if(k != -1)
                        localcmd("\nbind \"", keynumtostring(k), "\" \"", to, "\"\n");
        }
+       if(n)
+               cvar_set("_hud_showbinds_reload", "1");
 }
 void XonoticKeyBinder_configureXonoticKeyBinder(entity me)
 {
@@ -126,6 +129,7 @@ void KeyBinder_Bind_Change(entity btn, entity me)
                return;
 
        me.keyGrabButton.forcePressed = 1;
+       me.clearButton.disabled = 1;
        keyGrabber = me;
 }
 void XonoticKeyBinder_keyGrabbed(entity me, float key, float ascii)
@@ -134,6 +138,8 @@ void XonoticKeyBinder_keyGrabbed(entity me, float key, float ascii)
        string func;
 
        me.keyGrabButton.forcePressed = 0;
+       me.clearButton.disabled = 0;
+
        if(key == K_ESCAPE)
                return;
 
@@ -161,6 +167,7 @@ void XonoticKeyBinder_keyGrabbed(entity me, float key, float ascii)
        }
        localcmd("\nbind \"", keynumtostring(key), "\" \"", func, "\"\n");
        localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
+       cvar_set("_hud_showbinds_reload", "1");
 }
 void XonoticKeyBinder_editUserbind(entity me, string theName, string theCommandPress, string theCommandRelease)
 {
@@ -168,11 +175,11 @@ void XonoticKeyBinder_editUserbind(entity me, string theName, string theCommandP
 
        if(!me.userbindEditDialog)
                return;
-       
+
        func = Xonotic_KeyBinds_Functions[me.selectedItem];
        if(func == "")
                return;
-       
+
        descr = Xonotic_KeyBinds_Descriptions[me.selectedItem];
        if(substring(descr, 0, 1) != "$")
                return;
@@ -189,11 +196,11 @@ void KeyBinder_Bind_Edit(entity btn, entity me)
 
        if(!me.userbindEditDialog)
                return;
-       
+
        func = Xonotic_KeyBinds_Functions[me.selectedItem];
        if(func == "")
                return;
-       
+
        descr = Xonotic_KeyBinds_Descriptions[me.selectedItem];
        if(substring(descr, 0, 1) != "$")
                return;
@@ -222,6 +229,7 @@ void KeyBinder_Bind_Clear(entity btn, entity me)
                        localcmd("\nbind \"", keynumtostring(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
        }
        localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
+       cvar_set("_hud_showbinds_reload", "1");
 }
 void XonoticKeyBinder_clickListBoxItem(entity me, float i, vector where)
 {
index 433261d45a94b464e25e1e5d4b2b3d6a53aefecd..c8db3db8a409c5749a6b1c4fef7e086cdb5d22dd 100644 (file)
@@ -1275,3 +1275,6 @@ float autocvar_g_sandbox_object_material_velocity_min;
 float autocvar_g_sandbox_object_material_velocity_factor;
 float autocvar_g_max_info_autoscreenshot;
 float autocvar_physics_ode;
+float autocvar_g_physical_items;
+float autocvar_g_physical_items_damageforcescale;
+float autocvar_g_physical_items_reset;
index ae1647305765c36a684d0ceb5ba67281263d7c61..5d0e040d2bc7a73276862a435a09f8daa2d9686c 100644 (file)
@@ -895,15 +895,15 @@ void SV_PlayerPhysics()
                maxspd_mod = autocvar_sv_spectator_speed_multiplier;
                if(!self.spectatorspeed)
                        self.spectatorspeed = maxspd_mod;
-               if(self.impulse && self.impulse <= 19)
+               if(self.impulse && self.impulse <= 19 || self.impulse >= 200 && self.impulse <= 209 || self.impulse >= 220 && self.impulse <= 229)
                {
                        if(self.lastclassname != "player")
                        {
-                               if(self.impulse == 10 || self.impulse == 15 || self.impulse == 18)
+                               if(self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || self.impulse >= 200 && self.impulse <= 209)
                                        self.spectatorspeed = bound(1, self.spectatorspeed + 0.5, 5);
                                else if(self.impulse == 11)
                                        self.spectatorspeed = maxspd_mod;
-                               else if(self.impulse == 12 || self.impulse == 16  || self.impulse == 19)
+                               else if(self.impulse == 12 || self.impulse == 16  || self.impulse == 19 || self.impulse >= 220 && self.impulse <= 229)
                                        self.spectatorspeed = bound(1, self.spectatorspeed - 0.5, 5);
                                else if(self.impulse >= 1 && self.impulse <= 9)
                                        self.spectatorspeed = 1 + 0.5 * (self.impulse - 1);
index 236c0923fdc330834469234bc9eb2285a1f6bb26..4df59a09afde775e7e73cca9fb0be6e248ad1205 100644 (file)
@@ -298,6 +298,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                wep.savenextthink = wep.nextthink;
                wep.nextthink = min(wep.nextthink, time + 0.5);
                wep.pickup_anyway = TRUE; // these are ALWAYS pickable
+
                return s;
        }
 }
index 0710ddfa8474874cca23787d9ed6221e44660ebd..8f3ea869d49e24bcdf0febd74dc5564c1002f7b6 100644 (file)
@@ -1415,6 +1415,7 @@ void GameCommand_stuffto(float request, float argc)
        // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
        
        #ifdef STUFFTO_ENABLED
+       #message "stuffto command enabled"
        switch(request)
        {
                case CMD_REQUEST_COMMAND:
index 9746183407254d68b66e7fcf49ed9d5d1ff56b47..c303c14da8caf6a1973e7b924c66a5bd072c2b49 100644 (file)
@@ -1102,9 +1102,11 @@ void readlevelcvars(void)
                MUTATOR_ADD(mutator_dodging);
        if(cvar("g_spawn_near_teammate"))
                MUTATOR_ADD(mutator_spawn_near_teammate);
+       if(cvar("g_physical_items"))
+               MUTATOR_ADD(mutator_physical_items);
        if(cvar("g_minstagib"))
-               MUTATOR_ADD(mutator_minstagib);
-               
+               MUTATOR_ADD(mutator_minstagib); 
+
        if(!g_minstagib)
        {
                if(cvar("g_invincible_projectiles"))
index 368ab589824ef5a66464d99283c7d223184cdf3f..f4761b884dca28175d58da08589a777c589722c2 100644 (file)
@@ -116,8 +116,14 @@ float Mutator_Add(mutatorfunc_t func, string name)
                // good
                return 1;
        }
-       backtrace("WARNING: when adding mutator: adding failed\n");
-       Mutator_Remove(func, name);
+
+       backtrace("WARNING: when adding mutator: adding failed, rolling back\n");
+
+       if(func(MUTATOR_ROLLING_BACK) != 0)
+       {
+               // baaaaad
+               error("WARNING: when adding mutator: rolling back failed");
+       }
        return 0;
 }
 void Mutator_Remove(float(float) func, string name)
index 882fceb808682204647cd1bf45fe870da65fab2f..6feccf3c582d0006697940193a1b69d22eaba6a1 100644 (file)
@@ -18,6 +18,7 @@ float CallbackChain_Call(entity cb);
 
 #define MUTATOR_REMOVING 0
 #define MUTATOR_ADDING 1
+#define MUTATOR_ROLLING_BACK 2
 typedef float(float) mutatorfunc_t;
 float Mutator_Add(mutatorfunc_t func, string name);
 void Mutator_Remove(mutatorfunc_t func, string name); // calls error() on fail
@@ -27,9 +28,10 @@ void Mutator_Remove(mutatorfunc_t func, string name); // calls error() on fail
 #define MUTATOR_DEFINITION(name) float MUTATOR_##name(float mode)
 #define MUTATOR_DECLARATION(name) float MUTATOR_##name(float mode)
 #define MUTATOR_HOOKFUNCTION(name) float HOOKFUNCTION_##name()
-#define MUTATOR_HOOK(cb,func,order) do { if(mode == MUTATOR_ADDING) { if(!HOOK_##cb) HOOK_##cb = CallbackChain_New(#cb); if(!CallbackChain_Add(HOOK_##cb,HOOKFUNCTION_##func,order)) { print("HOOK FAILED: ", #func, "\n"); return 1; } } else if(mode == MUTATOR_REMOVING) { if(HOOK_##cb) CallbackChain_Remove(HOOK_##cb,HOOKFUNCTION_##func); } } while(0)
+#define MUTATOR_HOOK(cb,func,order) do { if(mode == MUTATOR_ADDING) { if(!HOOK_##cb) HOOK_##cb = CallbackChain_New(#cb); if(!CallbackChain_Add(HOOK_##cb,HOOKFUNCTION_##func,order)) { print("HOOK FAILED: ", #func, "\n"); return 1; } } else if(mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK) { if(HOOK_##cb) CallbackChain_Remove(HOOK_##cb,HOOKFUNCTION_##func); } } while(0)
 #define MUTATOR_ONADD if(mode == MUTATOR_ADDING)
 #define MUTATOR_ONREMOVE if(mode == MUTATOR_REMOVING)
+#define MUTATOR_ONROLLBACK_OR_REMOVE if(mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK)
 
 #define MUTATOR_HOOKABLE(cb) entity HOOK_##cb
 #define MUTATOR_CALLHOOK(cb) CallbackChain_Call(HOOK_##cb)
@@ -209,6 +211,12 @@ MUTATOR_HOOKABLE(SV_StartFrame);
 MUTATOR_HOOKABLE(SetModname);
        // OUT
        string modname; // name of the mutator/mod if it warrants showing as such in the server browser
+       
+MUTATOR_HOOKABLE(Item_Spawn);
+       // called for each item being spawned on a map, including dropped weapons
+       // return 1 to remove an item
+       // INPUT
+       entity self; // the item
 
 MUTATOR_HOOKABLE(SetWeaponreplace);
        // IN
index 908d81cf3fe0a9d96b13a1c529a8db568f5008a9..134e979d1c17d0b09da3b1658b0fd724a791b55e 100644 (file)
@@ -2200,9 +2200,17 @@ MUTATOR_DEFINITION(gamemode_ctf)
                ctf_Initialize();
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back ctf_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
        MUTATOR_ONREMOVE
        {
-               error("This is a game type and it cannot be removed at runtime.");
+               print("This is a game type and it cannot be removed at runtime.");
+               return -1;
        }
 
        return 0;
index aedfd6364c942ef5f1d967b38d0dac04fa8d202f..116eecbbf6b773613f7b299568df3ee31a5817d6 100644 (file)
@@ -476,9 +476,17 @@ MUTATOR_DEFINITION(gamemode_freezetag)
                freezetag_Initialize();
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back freezetag_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
        MUTATOR_ONREMOVE
        {
-               error("This is a game type and it cannot be removed at runtime.");
+               print("This is a game type and it cannot be removed at runtime.");
+               return -1;
        }
 
        return 0;
index 9f8647d9dfa5cab3a61a1a37735360bcaf4602ec..3be0b035272b013598402f91188aed6c003069b6 100644 (file)
@@ -426,9 +426,17 @@ MUTATOR_DEFINITION(gamemode_keepaway)
                ka_Initialize();
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back ka_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
        MUTATOR_ONREMOVE
        {
-               error("This is a game type and it cannot be removed at runtime.");
+               print("This is a game type and it cannot be removed at runtime.");
+               return -1;
        }
 
        return 0;
index 58d732d7f70b926c6cb13c6f93aa0f9a5807f48e..592fa327cfb7af6ae6b413369dcc6759573523a2 100644 (file)
@@ -1111,9 +1111,17 @@ MUTATOR_DEFINITION(gamemode_keyhunt)
                kh_Initialize();
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back kh_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
        MUTATOR_ONREMOVE
        {
-               error("This is a game type and it cannot be removed at runtime.");
+               print("This is a game type and it cannot be removed at runtime.");
+               return -1;
        }
 
        return 0;
index 5f27b60a55f882e851cc99fe5bc876fec16e5601..62cfd01ad867250673f406bfc68ab7ea99841671 100644 (file)
@@ -979,5 +979,18 @@ MUTATOR_DEFINITION(gamemode_nexball)
                InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back nb_delayedinit here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               print("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
        return 0;
 }
index 8137cc3047d35ed2822d17a9841415e83c991ff5..dd0152ed084311be37509b34e5471531386afdcc 100644 (file)
@@ -1696,7 +1696,14 @@ MUTATOR_DEFINITION(gamemode_onslaught)
        
        MUTATOR_ONADD
        {
-               //InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
+               if(time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               print("This is a game type and it cannot be removed at runtime.");
+               return -1;
        }
 
        return 0;
index bdd39b1283f487fe0e74ab42135b6d66f4b180c7..5cb328c2ea593f6ac43a08d3fba5ac54df4a9059 100644 (file)
 // the jump part of the dodge cannot be ramped
 .float dodging_single_action;
 
-void dodging_Initialize() {
-       // print("dodging_Initialize\n");
-
-       self.last_FORWARD_KEY_time = 0;
-       self.last_BACKWARD_KEY_time = 0;
-       self.last_RIGHT_KEY_time = 0;
-       self.last_LEFT_KEY_time = 0;
-       self.last_dodging_time = 0;
-       self.dodging_action = 0;
-       self.dodging_velocity_gain = 0;
-       self.dodging_single_action = 0;
-       self.dodging_direction_x = 0;
-       self.dodging_direction_y = 0;
-}
-
 MUTATOR_HOOKFUNCTION(dodging_GetCvars) {
        GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
        return 0;
@@ -283,14 +268,17 @@ MUTATOR_DEFINITION(mutator_dodging)
        MUTATOR_ONADD
        {
                g_dodging = 1;
-               dodging_Initialize();
        }
 
        // this just turns off the cvar.
-       MUTATOR_ONREMOVE
-       {        
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
                g_dodging = 0;
        }
 
+       MUTATOR_ONREMOVE
+       {
+       }
+
        return 0;
 }
index cc4f94324b8273fadf9fbc113c4dc286c6b8066b..6ee3e87b3c193e52354dd4e9e40301a8b6a756fc 100644 (file)
@@ -208,9 +208,19 @@ MUTATOR_DEFINITION(mutator_new_toys)
                        if(nt_IsNewToy(i))
                                get_weaponinfo(i).spawnflags &~= WEP_FLAG_MUTATORBLOCKED;
        }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               float i;
+               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       if(nt_IsNewToy(i))
+                               get_weaponinfo(i).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+
        MUTATOR_ONREMOVE
        {
-               error("This cannot be removed at runtime\n");
+               print("This cannot be removed at runtime\n");
+               return -1;
        }
 
        return 0;
index dad19e4a3748f468c93db674b6b2e9c7e7e43a2c..b492ee60eb48add1046b6278fb171783bc85dea8 100644 (file)
@@ -247,6 +247,11 @@ MUTATOR_DEFINITION(mutator_nix)
                NIX_precache();
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
        MUTATOR_ONREMOVE
        {
                // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
diff --git a/qcsrc/server/mutators/mutator_physical_items.qc b/qcsrc/server/mutators/mutator_physical_items.qc
new file mode 100644 (file)
index 0000000..74b7db2
--- /dev/null
@@ -0,0 +1,127 @@
+.vector spawn_origin, spawn_angles;
+
+void physical_item_think()
+{
+       self.nextthink = time;
+
+       self.alpha = self.owner.alpha; // apply fading and ghosting
+
+       if(!self.cnt) // map item, not dropped
+       {
+               // copy ghost item properties
+               self.colormap = self.owner.colormap;
+               self.colormod = self.owner.colormod;
+               self.glowmod = self.owner.glowmod;
+
+               // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
+               if(autocvar_g_physical_items_reset)
+               {
+                       if(self.owner.nextthink > time) // awaiting respawn
+                       {
+                               setorigin(self, self.spawn_origin);
+                               self.angles = self.spawn_angles;
+                               self.solid = SOLID_NOT;
+                               self.movetype = MOVETYPE_NONE;
+                       }
+                       else
+                       {
+                               self.solid = SOLID_CORPSE;
+                               self.movetype = MOVETYPE_PHYSICS;
+                       }
+               }
+       }
+
+       if(!self.owner.modelindex)
+               remove(self); // the real item is gone, remove this
+}
+
+void physical_item_touch()
+{
+       if(!self.cnt) // not for dropped items
+       if (ITEM_TOUCH_NEEDKILL())
+       {
+               setorigin(self, self.spawn_origin);
+               self.angles = self.spawn_angles;
+       }
+}
+
+void physical_item_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       if(!self.cnt) // not for dropped items
+       if(ITEM_DAMAGE_NEEDKILL(deathtype))
+       {
+               setorigin(self, self.spawn_origin);
+               self.angles = self.spawn_angles;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(item_spawning)
+{
+       if(self.owner == world && autocvar_g_physical_items <= 1)
+               return FALSE;
+       if (self.spawnflags & 1) // floating item
+               return FALSE;
+
+       // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
+       // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
+       entity wep;
+       wep = spawn();
+       setmodel(wep, self.model);
+       setsize(wep, self.mins, self.maxs);
+       setorigin(wep, self.origin);
+       wep.angles = self.angles;
+       wep.velocity = self.velocity;
+
+       wep.owner = self;
+       wep.solid = SOLID_CORPSE;
+       wep.movetype = MOVETYPE_PHYSICS;
+       wep.takedamage = DAMAGE_AIM;
+       wep.effects |= EF_NOMODELFLAGS; // disable the spinning
+       wep.colormap = self.owner.colormap;
+       wep.glowmod = self.owner.glowmod;
+       wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
+       wep.dphitcontentsmask = self.dphitcontentsmask;
+       wep.cnt = (self.owner != world);
+
+       wep.think = physical_item_think;
+       wep.nextthink = time;
+       wep.touch = physical_item_touch;
+       wep.event_damage = physical_item_damage;
+
+       wep.spawn_origin = self.origin;
+       wep.spawn_angles = self.angles;
+
+       self.effects |= EF_NODRAW; // hide the original weapon
+       self.movetype = MOVETYPE_FOLLOW;
+       self.aiment = wep; // attach the original weapon
+
+       return FALSE;
+}
+
+MUTATOR_DEFINITION(mutator_physical_items)
+{
+       MUTATOR_HOOK(Item_Spawn, item_spawning, CBC_ORDER_ANY);
+
+       // check if we have a physics engine
+       MUTATOR_ONADD
+       {
+               if not(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE"))
+               {
+                       dprint("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
+                       return -1;
+               }
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               print("This cannot be removed at runtime\n");
+               return -1;
+       }
+
+       return 0;
+}
index 87915f9af49b7cc1d175986ae26fe3df7613444a..0645b4805446b17cd1baafe035225d4b4793fceb 100644 (file)
@@ -518,13 +518,5 @@ MUTATOR_DEFINITION(mutator_superspec)
        //MUTATOR_HOOK(MakePlayerObserver, superspec_MakePlayerObserver, CBC_ORDER_ANY);
        MUTATOR_HOOK(ClientDisconnect, superspec_ClientDisconnect, CBC_ORDER_ANY);
 
-       MUTATOR_ONADD
-       {
-       }
-
-       MUTATOR_ONREMOVE
-       {
-       }
-
        return 0;
 }
index c306c4d3946b3d3f5ea19ae405aaf822e93d4a5e..83c8e0143e0a6a7490b484f74c60e454bf84da6b 100644 (file)
@@ -11,6 +11,7 @@ MUTATOR_DECLARATION(mutator_new_toys);
 MUTATOR_DECLARATION(mutator_nix);
 MUTATOR_DECLARATION(mutator_rocketflying);
 MUTATOR_DECLARATION(mutator_spawn_near_teammate);
+MUTATOR_DECLARATION(mutator_physical_items);
 MUTATOR_DECLARATION(mutator_vampire);
 MUTATOR_DECLARATION(mutator_superspec);
 MUTATOR_DECLARATION(mutator_minstagib);
index 4d97b8eece8e8fc585377a84d5167ea9dc3fea1a..391e317423dffd4dd37e628effe9a988b452267f 100644 (file)
@@ -817,6 +817,16 @@ MUTATOR_DEFINITION(sandbox)
                        sandbox_Database_Load();
        }
 
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               // nothing to remove
+       }
+
        return FALSE;
 }
 
index ea05945b9bfea8c0327ac85ef02127527a1ba071..67100fbea222f24cce4d502a3e9e028da835f32f 100644 (file)
@@ -220,6 +220,7 @@ mutators/mutator_dodging.qc
 mutators/mutator_rocketflying.qc
 mutators/mutator_vampire.qc
 mutators/mutator_spawn_near_teammate.qc
+mutators/mutator_physical_items.qc
 mutators/sandbox.qc
 mutators/mutator_superspec.qc
 mutators/mutator_minstagib.qc
index cecca909afed3874d70f7e6226877d48dc252c1c..3a0c0d12e3a4920938d1c3c495715fa7c6293bfb 100644 (file)
@@ -1143,6 +1143,14 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                Item_Reset();
         
     Net_LinkEntity(self, FALSE, 0, ItemSend);
+
+       // call this hook after everything else has been done
+       if(MUTATOR_CALLHOOK(Item_Spawn))
+       {
+               startitem_failed = TRUE;
+               remove(self);
+               return;
+       }
 }
 
 float weaponswapping;