From: Mario Date: Thu, 31 Jan 2013 10:44:31 +0000 (+1100) Subject: Merge branch 'master' into mario/mutator_minstagib X-Git-Tag: xonotic-v0.7.0~55^2~3^2~25 X-Git-Url: http://git.xonotic.org/?a=commitdiff_plain;h=8ca366ebd48869569fbc18c9cd854b705e04e540;hp=4e6c8c5fcb1b874a8c90f5f571471ff2993ce7dc;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into mario/mutator_minstagib --- diff --git a/_hud_common.cfg b/_hud_common.cfg index 5179bb2ab..ba88a2a4f 100644 --- a/_hud_common.cfg +++ b/_hud_common.cfg @@ -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 index 000000000..6445def55 --- /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 "+ + + + + + + + + + [ > + + + + + + + > + + + + + + + + + + > + + + > + < < < < - ] > + + . > + . + + + + + + + . . + + + . > + + . < < + + + + + + + + + + + + + + + . > . + + + . - - - - - - . - - - - - - - - . > + . > ." diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 1ad85c8bd..c51cc0c71 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -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\"" diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index b75fc166e..3e5deb104 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -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; } } diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index 940f81057..d1c104058 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -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 diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index cb06932e4..94cd1a5c0 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -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; diff --git a/qcsrc/menu/xonotic/dialog_settings_input.c b/qcsrc/menu/xonotic/dialog_settings_input.c index 96bf5e5c6..daa8f3ff1 100644 --- a/qcsrc/menu/xonotic/dialog_settings_input.c +++ b/qcsrc/menu/xonotic/dialog_settings_input.c @@ -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"))); diff --git a/qcsrc/menu/xonotic/keybinder.c b/qcsrc/menu/xonotic/keybinder.c index 1107e60ab..739be1b05 100644 --- a/qcsrc/menu/xonotic/keybinder.c +++ b/qcsrc/menu/xonotic/keybinder.c @@ -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) { diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 433261d45..c8db3db8a 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -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; diff --git a/qcsrc/server/cl_physics.qc b/qcsrc/server/cl_physics.qc index ae1647305..5d0e040d2 100644 --- a/qcsrc/server/cl_physics.qc +++ b/qcsrc/server/cl_physics.qc @@ -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); diff --git a/qcsrc/server/cl_weapons.qc b/qcsrc/server/cl_weapons.qc index 236c0923f..4df59a09a 100644 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@ -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; } } diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index 0710ddfa8..8f3ea869d 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -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: diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 974618340..c303c14da 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -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")) diff --git a/qcsrc/server/mutators/base.qc b/qcsrc/server/mutators/base.qc index 368ab5898..f4761b884 100644 --- a/qcsrc/server/mutators/base.qc +++ b/qcsrc/server/mutators/base.qc @@ -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) diff --git a/qcsrc/server/mutators/base.qh b/qcsrc/server/mutators/base.qh index 882fceb80..6feccf3c5 100644 --- a/qcsrc/server/mutators/base.qh +++ b/qcsrc/server/mutators/base.qh @@ -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 diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc index 908d81cf3..134e979d1 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@ -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; diff --git a/qcsrc/server/mutators/gamemode_freezetag.qc b/qcsrc/server/mutators/gamemode_freezetag.qc index aedfd6364..116eecbbf 100644 --- a/qcsrc/server/mutators/gamemode_freezetag.qc +++ b/qcsrc/server/mutators/gamemode_freezetag.qc @@ -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; diff --git a/qcsrc/server/mutators/gamemode_keepaway.qc b/qcsrc/server/mutators/gamemode_keepaway.qc index 9f8647d9d..3be0b0352 100644 --- a/qcsrc/server/mutators/gamemode_keepaway.qc +++ b/qcsrc/server/mutators/gamemode_keepaway.qc @@ -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; diff --git a/qcsrc/server/mutators/gamemode_keyhunt.qc b/qcsrc/server/mutators/gamemode_keyhunt.qc index 58d732d7f..592fa327c 100644 --- a/qcsrc/server/mutators/gamemode_keyhunt.qc +++ b/qcsrc/server/mutators/gamemode_keyhunt.qc @@ -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; diff --git a/qcsrc/server/mutators/gamemode_nexball.qc b/qcsrc/server/mutators/gamemode_nexball.qc index 5f27b60a5..62cfd01ad 100644 --- a/qcsrc/server/mutators/gamemode_nexball.qc +++ b/qcsrc/server/mutators/gamemode_nexball.qc @@ -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; } diff --git a/qcsrc/server/mutators/gamemode_onslaught.qc b/qcsrc/server/mutators/gamemode_onslaught.qc index 8137cc304..dd0152ed0 100644 --- a/qcsrc/server/mutators/gamemode_onslaught.qc +++ b/qcsrc/server/mutators/gamemode_onslaught.qc @@ -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; diff --git a/qcsrc/server/mutators/mutator_dodging.qc b/qcsrc/server/mutators/mutator_dodging.qc index bdd39b128..5cb328c2e 100644 --- a/qcsrc/server/mutators/mutator_dodging.qc +++ b/qcsrc/server/mutators/mutator_dodging.qc @@ -27,21 +27,6 @@ // 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; } diff --git a/qcsrc/server/mutators/mutator_new_toys.qc b/qcsrc/server/mutators/mutator_new_toys.qc index cc4f94324..6ee3e87b3 100644 --- a/qcsrc/server/mutators/mutator_new_toys.qc +++ b/qcsrc/server/mutators/mutator_new_toys.qc @@ -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; diff --git a/qcsrc/server/mutators/mutator_nix.qc b/qcsrc/server/mutators/mutator_nix.qc index dad19e4a3..b492ee60e 100644 --- a/qcsrc/server/mutators/mutator_nix.qc +++ b/qcsrc/server/mutators/mutator_nix.qc @@ -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 index 000000000..74b7db2f0 --- /dev/null +++ b/qcsrc/server/mutators/mutator_physical_items.qc @@ -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; +} diff --git a/qcsrc/server/mutators/mutator_superspec.qc b/qcsrc/server/mutators/mutator_superspec.qc index 87915f9af..0645b4805 100644 --- a/qcsrc/server/mutators/mutator_superspec.qc +++ b/qcsrc/server/mutators/mutator_superspec.qc @@ -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; } diff --git a/qcsrc/server/mutators/mutators.qh b/qcsrc/server/mutators/mutators.qh index c306c4d39..83c8e0143 100644 --- a/qcsrc/server/mutators/mutators.qh +++ b/qcsrc/server/mutators/mutators.qh @@ -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); diff --git a/qcsrc/server/mutators/sandbox.qc b/qcsrc/server/mutators/sandbox.qc index 4d97b8eec..391e31742 100644 --- a/qcsrc/server/mutators/sandbox.qc +++ b/qcsrc/server/mutators/sandbox.qc @@ -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; } diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index ea05945b9..67100fbea 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -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 diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc index cecca909a..3a0c0d12e 100644 --- a/qcsrc/server/t_items.qc +++ b/qcsrc/server/t_items.qc @@ -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;