]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into mirceakitsune/sandbox
authorMircea Kitsune <sonichedgehog_hyperblast00@yahoo.com>
Fri, 28 Oct 2011 12:22:43 +0000 (15:22 +0300)
committerMircea Kitsune <sonichedgehog_hyperblast00@yahoo.com>
Fri, 28 Oct 2011 12:22:43 +0000 (15:22 +0300)
40 files changed:
defaultXonotic.cfg
effectinfo.txt
gfx/menu/luminos/skinvalues.txt
gfx/menu/wickedx/skinvalues.txt
gfx/menu/xaw/skinvalues.txt
keybinds.txt
qcsrc/menu/classes.c
qcsrc/menu/skin-customizables.inc
qcsrc/menu/xonotic/dialog_sandboxtools.c [new file with mode: 0644]
qcsrc/menu/xonotic/mainwindow.c
qcsrc/server/autocvars.qh
qcsrc/server/cheats.qc
qcsrc/server/cheats.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/base.qh
qcsrc/server/mutators/mutators.qh
qcsrc/server/mutators/sandbox.qc [new file with mode: 0644]
qcsrc/server/progs.src
qcsrc/server/sv_main.qc
sound/object/impact_flesh_1.ogg [new file with mode: 0644]
sound/object/impact_flesh_2.ogg [new file with mode: 0644]
sound/object/impact_flesh_3.ogg [new file with mode: 0644]
sound/object/impact_flesh_4.ogg [new file with mode: 0644]
sound/object/impact_flesh_5.ogg [new file with mode: 0644]
sound/object/impact_metal_1.ogg [new file with mode: 0644]
sound/object/impact_metal_2.ogg [new file with mode: 0644]
sound/object/impact_metal_3.ogg [new file with mode: 0644]
sound/object/impact_metal_4.ogg [new file with mode: 0644]
sound/object/impact_metal_5.ogg [new file with mode: 0644]
sound/object/impact_stone_1.ogg [new file with mode: 0644]
sound/object/impact_stone_2.ogg [new file with mode: 0644]
sound/object/impact_stone_3.ogg [new file with mode: 0644]
sound/object/impact_stone_4.ogg [new file with mode: 0644]
sound/object/impact_stone_5.ogg [new file with mode: 0644]
sound/object/impact_wood_1.ogg [new file with mode: 0644]
sound/object/impact_wood_2.ogg [new file with mode: 0644]
sound/object/impact_wood_3.ogg [new file with mode: 0644]
sound/object/impact_wood_4.ogg [new file with mode: 0644]
sound/object/impact_wood_5.ogg [new file with mode: 0644]
xonotic-credits.txt

index c96b0b13418b678bca4602fdfcb4174acdd19dd5..ff90731aad59c24614c6179fd5721b265fda1c0d 100644 (file)
@@ -544,6 +544,33 @@ set g_player_alpha 1
 set g_player_brightness 0      "set to 2 for brighter players"
 seta g_balance_cloaked_alpha 0.25
 
+set g_sandbox 0 "allow players to spawn and edit objects around the map"
+set g_sandbox_info 1 "print object information to the server. 1 prints info about spawned / removed objects, 2 also prints info about edited objects"
+set g_sandbox_storage_autosave 10 "storage is automatically saved every specified number of seconds"
+set g_sandbox_editor_maxobjects 1000 "maximum number of objects that may exist at a time"
+set g_sandbox_editor_free 0 "when enabled, players can edit any object on the map, not just the objects they've spawned"
+set g_sandbox_editor_distance_spawn 200 "distance at which objects spawn in front of the player"
+set g_sandbox_editor_distance_edit 350 "distance at which players can edit or remove objects they are looking at"
+set g_sandbox_object_scale_min 0.1 "minimum scale that objects can be set to"
+set g_sandbox_object_scale_max 2 "maximum scale that objects can be set to"
+set g_sandbox_object_material_velocity_min 100 "velocity objects must have while colliding for material effects to be applied"
+set g_sandbox_object_material_velocity_factor 0.002 "velocity range which decides the intensity of material effects"
+
+seta menu_sandbox_spawn_model ""
+seta menu_sandbox_attach_bone ""
+seta menu_sandbox_edit_skin 0
+seta menu_sandbox_edit_alpha 1
+seta menu_sandbox_edit_color_main "1 1 1"
+seta menu_sandbox_edit_color_glow "1 1 1"
+seta menu_sandbox_edit_frame 0
+seta menu_sandbox_edit_scale 1
+seta menu_sandbox_edit_physics 1
+seta menu_sandbox_edit_force 1
+seta menu_sandbox_edit_material ""
+
+alias menu_showsandboxtools "menu_cmd directmenu SandboxTools"
+bind f7 menu_showsandboxtools
+
 set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
 set g_botclip_collisions 1 "0 = disable collision testing against botclips, might be useful on some defrag maps"
 
@@ -996,6 +1023,8 @@ alias togglezoom "${_togglezoom}zoom"
 
 alias reload "impulse 20"
 
+alias sandbox "cmd g_sandbox $*"
+
 // movement
 bind w +forward
 bind a +moveleft
@@ -1042,6 +1071,7 @@ bind r reload
 bind BACKSPACE dropweapon
 bind g dropweapon
 bind f +use
+bind v +button8 // drag object
 
 // misc
 bind e +hook
index 70f5fbb4c6f8fd7f03468ae16cc2e9e7bd80399d..06e153bf8973a526982e937994b836b323e46b09 100644 (file)
@@ -6407,3 +6407,109 @@ velocityoffset 0 0 200
 airfriction 4
 color 0x4F4B46 0x000000
 rotate -180 180 -20 20
+
+// metal impact effect
+// used in qcsrc/server/mutators/sandbox.qc:   pointparticles(particleeffectnum("impact_metal"), self.origin, '0 0 0', 1);
+effect impact_metal
+count 1
+type alphastatic
+tex 0 8
+size 3 6
+sizeincrease 10
+alpha 25 64 50
+gravity -0.01
+color 0x000000 0x886666
+originjitter 20 20 5
+// sparks
+effect impact_metal
+count 2
+type spark
+tex 41 41
+color 0xFFCC22 0xFF4422
+size 2 2
+alpha 255 255 112
+bounce 1.8
+stretchfactor 0.5
+velocityjitter 200 200 300
+velocitymultiplier 2
+airfriction 2
+gravity 1
+
+// stone impact effect
+// used in qcsrc/server/mutators/sandbox.qc:   pointparticles(particleeffectnum("impact_stone"), self.origin, '0 0 0', 1);
+effect impact_stone
+count 1
+type alphastatic
+tex 0 8
+size 3 6
+sizeincrease 15
+alpha 50 128 75
+gravity -0.01
+color 0x000000 0xcc9966
+originjitter 20 20 5
+// debris
+effect impact_stone
+notunderwater
+count 1
+type alphastatic
+tex 66 68
+color 0x000000 0x886644
+size 1 2
+alpha 450 750 300
+gravity 1.3
+airfriction 0.5
+bounce 1.2
+velocityjitter 124 124 324
+rotate -180 180 -1000 1000
+
+// wood impact effect
+// used in qcsrc/server/mutators/sandbox.qc:   pointparticles(particleeffectnum("impact_wood"), self.origin, '0 0 0', 1);
+effect impact_wood
+count 1
+type alphastatic
+tex 0 8
+size 3 6
+sizeincrease 10
+alpha 50 128 75
+gravity -0.01
+color 0x000000 0xcc9966
+originjitter 20 20 5
+// sparks
+effect impact_wood
+count 2
+type spark
+tex 41 41
+color 0x221100 0x221100
+size 1 8
+alpha 255 255 75
+bounce 1.5
+velocityjitter 180 180 260
+velocitymultiplier 2
+airfriction 2
+gravity 1
+
+// flesh impact effect
+// used in qcsrc/server/mutators/sandbox.qc:   pointparticles(particleeffectnum("impact_flesh"), self.origin, '0 0 0', 1);
+effect impact_flesh
+count 0.5
+type alphastatic
+tex 0 8
+size 8 12
+alpha 100 256 400
+color 0x000000 0x420000
+originjitter 11 11 11
+// blood splash
+effect impact_flesh
+count 0.3
+type blood
+tex 24 32
+size 2 6
+alpha 256 256 64
+color 0xA8FFFF 0xA8FFFFF
+bounce -1
+airfriction 1
+liquidfriction 4
+velocityjitter 96 96 96
+velocitymultiplier 5
+staincolor 0x808080 0x808080
+staintex 16 24
index bf147b4f4821636d4a4d7ed1136fe81ed1fdc363..b4102234acd4e8bc06eef8253bfcc90d83538333 100755 (executable)
@@ -166,6 +166,7 @@ COLOR_CHECKBOX_D                '1 1 1'
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
 COLOR_DIALOG_SETTINGS           '1 1 1'
 COLOR_DIALOG_TEAMSELECT         '1 1 1'
+COLOR_DIALOG_SANDBOXTOOLS       '1 1 1'
 COLOR_DIALOG_QUIT               '1 1 1'
 COLOR_DIALOG_ADVANCED           '1 1 1'
 COLOR_DIALOG_MUTATORS           '1 1 1'
index 2b09e5624ccf0ad14e2f77e387911543e36bb3ec..d6b7197a1d32c099a1ffbff4fdee06210e066455 100755 (executable)
@@ -166,6 +166,7 @@ COLOR_CHECKBOX_D                '1 1 1'
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
 COLOR_DIALOG_SETTINGS           '1 1 1'
 COLOR_DIALOG_TEAMSELECT         '1 1 1'
+COLOR_DIALOG_SANDBOXTOOLS       '1 1 1'
 COLOR_DIALOG_QUIT               '1 1 1'
 COLOR_DIALOG_ADVANCED           '1 1 1'
 COLOR_DIALOG_MUTATORS           '1 1 1'
index 376f1596c918ccf64790748f4e71626857ce53da..5afcb09cfe3751cd5efedde9758be73cd512e864 100644 (file)
@@ -21,6 +21,7 @@ AVOID_TOOLTIP                   '8 8 0'
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
 COLOR_DIALOG_SETTINGS           '1 1 1'
 COLOR_DIALOG_TEAMSELECT         '1 1 1'
+COLOR_DIALOG_SANDBOXTOOLS       '1 1 1'
 COLOR_DIALOG_QUIT               '1 0 0'
 COLOR_DIALOG_ADVANCED           '1 1 1'
 COLOR_DIALOG_MUTATORS           '1 1 1'
index 2df89afae0e9f0ecf8b5dd4cdc6a737071a65a80..d7ec276f57f9d541057d42ebaccc63776a177069 100644 (file)
 "messagemode2"                          "team chat"
 "team_auto"                             "auto-join team"
 "menu_showteamselect"                   "team menu"
+"menu_showsandboxtools"                 "sandbox menu"
 "spec"                                  "enter spectator mode"
 "dropweapon"                            "drop weapon"
 "+use"                                  "drop key / drop flag"
+"+button8"                              "drag object"
 ""                                      ""
 ""                                      "User defined"
 "+userbind 1"                           "$userbind1"
index 5b7331e3752be37be4231150c89627e38c5baa5e..c0a9780471e3689ca0f1490c51459d9ce05c84ed 100644 (file)
@@ -29,6 +29,7 @@
 #include "xonotic/bigcommandbutton.c"
 #include "xonotic/dialog_firstrun.c"
 #include "xonotic/dialog_teamselect.c"
+#include "xonotic/dialog_sandboxtools.c"
 #include "xonotic/dialog_settings.c"
 #include "xonotic/dialog_settings_video.c"
 #include "xonotic/dialog_settings_effects.c"
index ca8f4cf8e959ee7d2a5755e74e82def02d543c0b..e8cfba3689a7bcca7ed0fe1fa1eaffa4549dd904 100644 (file)
@@ -55,6 +55,7 @@ SKINBEGIN
        SKINVECTOR(COLOR_DIALOG_MULTIPLAYER, '0.7 0.7 1');
        SKINVECTOR(COLOR_DIALOG_SETTINGS, '0.7 0.7 1');
        SKINVECTOR(COLOR_DIALOG_TEAMSELECT, '1 1 1');
+       SKINVECTOR(COLOR_DIALOG_SANDBOXTOOLS, '1 1 1');
        SKINVECTOR(COLOR_DIALOG_QUIT, '1 0 0');
        SKINVECTOR(COLOR_DIALOG_ADVANCED, '0.7 0.7 1');
        SKINVECTOR(COLOR_DIALOG_MUTATORS, '0.7 0.7 1');
diff --git a/qcsrc/menu/xonotic/dialog_sandboxtools.c b/qcsrc/menu/xonotic/dialog_sandboxtools.c
new file mode 100644 (file)
index 0000000..e0cb430
--- /dev/null
@@ -0,0 +1,86 @@
+#ifdef INTERFACE
+CLASS(XonoticSandboxToolsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticSandboxToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+       ATTRIB(XonoticSandboxToolsDialog, title, string, _("Sandbox Tools")) // ;)
+       ATTRIB(XonoticSandboxToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
+       ATTRIB(XonoticSandboxToolsDialog, intendedWidth, float, 0.8)
+       ATTRIB(XonoticSandboxToolsDialog, rows, float, 15)
+       ATTRIB(XonoticSandboxToolsDialog, columns, float, 4)
+       ATTRIB(XonoticSandboxToolsDialog, name, string, "SandboxTools")
+ENDCLASS(XonoticSandboxToolsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticSandboxToolsDialog_fill(entity me)
+{
+       entity e, box;
+
+       me.TR(me);
+               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Model:")));
+               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_spawn_model"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Spawn"), '0 0 0', "sandbox object_spawn $menu_sandbox_spawn_model", 0));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Remove *"), '0 0 0', "sandbox object_remove", 0));
+       me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Copy *"), '0 0 0', "sandbox object_duplicate copy", 0));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Paste"), '0 0 0', "sandbox object_duplicate paste", 0));
+       me.TR(me);
+               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Bone:")));
+               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_attach_bone"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set * as child"), '0 0 0', "sandbox object_attach get", 0));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Attach to *"), '0 0 0', "sandbox object_attach set $menu_sandbox_edit_skin", 0));
+       me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Detach from *"), '0 0 0', "sandbox object_attach remove", 0));
+       me.TR(me);
+       me.TR(me);
+       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Visual object properties for *:")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set skin:"), '0 0 0', "sandbox object_edit skin $menu_sandbox_edit_skin", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_sandbox_edit_skin"));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set alpha:"), '0 0 0', "sandbox object_edit alpha $menu_sandbox_edit_alpha", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0.1, 1, 0.05, "menu_sandbox_edit_alpha"));
+       me.TR(me);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set color main:"), '0 0 0', "sandbox object_edit color_main \"$menu_sandbox_edit_color_main\"", 0));
+               me.TD(me, 2, 1.5, e = makeXonoticColorpickerString("menu_sandbox_edit_color_main", "menu_sandbox_edit_color_main"));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set color glow:"), '0 0 0', "sandbox object_edit color_glow \"$menu_sandbox_edit_color_glow\"", 0));
+               me.TD(me, 2, 1.5, e = makeXonoticColorpickerString("menu_sandbox_edit_color_glow", "menu_sandbox_edit_color_glow"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set frame:"), '0 0 0', "sandbox object_edit frame $menu_sandbox_edit_frame", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_sandbox_edit_frame"));
+       me.TR(me);
+       me.TR(me);
+       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Physical object properties for *:")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set material:"), '0 0 0', "sandbox object_edit material $menu_sandbox_edit_material", 0));
+               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_edit_material"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set physics:"), '0 0 0', "sandbox object_edit physics $menu_sandbox_edit_physics", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(1, "menu_sandbox_edit_physics", "0", _("Static")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(1, "menu_sandbox_edit_physics", "1", _("Movable")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(1, "menu_sandbox_edit_physics", "2", _("Physical")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set scale:"), '0 0 0', "sandbox object_edit scale $menu_sandbox_edit_scale", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0.5, 2, 0.05, "menu_sandbox_edit_scale"));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Set force:"), '0 0 0', "sandbox object_edit force $menu_sandbox_edit_force", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 10, 0.5, "menu_sandbox_edit_force"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("* is the object you are facing")));
+               me.TD(me, 1, 0.5, makeXonoticCommandButton(_("Show help"), '1 0 0', "sandbox help; toggleconsole", 0));
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
+
+/* Click. The c-word is here so you can grep for it :-) */
index 55d496047138cf23ec68b55251db14e8658d17d9..20627c7a579d25adee8be4192d7e00c8264640e5 100644 (file)
@@ -49,6 +49,10 @@ void MainWindow_configureMainWindow(entity me)
        i = spawnXonoticTeamSelectDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticSandboxToolsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
        
        i = spawnXonoticHUDExitDialog();
        i.configureDialog(i);
index 3f8d6caf0d6d9e486988e30dcbe1b7b3325398cc..3641d07b59e65cae992d465a095e6acbd13bcd1a 100644 (file)
@@ -1199,3 +1199,13 @@ float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
 float autocvar_g_trueaim_minrange;
 float autocvar_g_debug_defaultsounds;
 float autocvar_g_loituma;
+float autocvar_g_sandbox_info;
+float autocvar_g_sandbox_storage_autosave;
+float autocvar_g_sandbox_editor_maxobjects;
+float autocvar_g_sandbox_editor_free;
+float autocvar_g_sandbox_editor_distance_spawn;
+float autocvar_g_sandbox_editor_distance_edit;
+float autocvar_g_sandbox_object_scale_min;
+float autocvar_g_sandbox_object_scale_max;
+float autocvar_g_sandbox_object_material_velocity_min;
+float autocvar_g_sandbox_object_material_velocity_factor;
index 0d95c453a1e6685b1d7032dd06dd520670ae628b..d5c145f26cc144a282de1038811046c7bb0ffa49 100644 (file)
@@ -664,7 +664,7 @@ float CheatCommand(float argc)
        END_CHEAT_FUNCTION();
 }
 
-void crosshair_trace_plusvisibletriggers(entity pl);
+float Drag(entity e, float grab);
 void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
 void Drag_Finish(entity dragger);
 float Drag_IsDraggable(entity draggee);
@@ -682,6 +682,46 @@ float CheatFrame()
 {
        BEGIN_CHEAT_FUNCTION();
 
+       // Dragging can be used as either a cheat, or a tool for g_sandbox. If sv_cheats is active,
+       // the cheat dragging is used (unlimited pickup range and any entity can be carried), even if
+       // g_sandbox is enabled. Is sv_cheats is disabled but g_sandbox is not, then sandbox dragging
+       // is used (limited pickup range and only sandbox objects can be carried), grabbing itself
+       // no longer being accounted as cheating. If both sv_cheats and g_sandbox are disabled, players
+       // attempting to grab objects are reported as trying to cheat.
+
+       switch(0)
+       {
+               default:
+                       if(self.BUTTON_DRAG && !cvar("g_sandbox"))
+                       {
+                               // consider dragging a cheat only if sandbox mode is disabled
+                               IS_CHEAT(0, 0, CHRAME_DRAG);
+                       }
+                       if(autocvar_sv_cheats)
+                       {
+                               // only use cheat dragging if cheats are enabled
+                               crosshair_trace_plusvisibletriggers(self);
+                               if(Drag(trace_ent, TRUE) && !cvar("g_sandbox"))
+                                       DID_CHEAT();
+                       }
+                       break;
+       }
+
+       END_CHEAT_FUNCTION();
+}
+
+
+
+
+
+// ENTITY DRAGGING
+
+float Drag(entity e, float grab)
+{
+       // returns TRUE when an entity has been picked up
+       // If grab is TRUE, the object can also be picked up if it's not being held already
+       // If grab is FALSE, only keep dragging the object if it's already being held
+
        if(Drag_IsDragging(self))
        {
                if(self.BUTTON_DRAG)
@@ -716,49 +756,21 @@ float CheatFrame()
        else
        {
                if(Drag_CanDrag(self))
-                       if(self.BUTTON_DRAG)
+                       if(self.BUTTON_DRAG && grab)
                        {
-                               crosshair_trace_plusvisibletriggers(self);
-                               if(trace_ent)
-                                       if(Drag_IsDraggable(trace_ent))
-                                               switch(0)
-                                               {
-                                                       default:
-                                                               IS_CHEAT(0, 0, CHRAME_DRAG);
-                                                               if(trace_ent.draggedby)
-                                                                       Drag_Finish(trace_ent.draggedby);
-                                                               if(trace_ent.tag_entity)
-                                                                       detach_sameorigin(trace_ent);
-                                                               Drag_Begin(self, trace_ent, trace_endpos);
-                                                               DID_CHEAT();
-                                                               break;
-                                               }
+                               if(e)
+                                       if(Drag_IsDraggable(e))
+                                       {
+                                                       if(e.draggedby)
+                                                               Drag_Finish(e.draggedby);
+                                                       if(e.tag_entity)
+                                                               detach_sameorigin(e);
+                                                       Drag_Begin(self, e, trace_endpos);
+                                                       return TRUE;
+                                       }
                        }
        }
-
-       END_CHEAT_FUNCTION();
-}
-
-
-
-
-
-// ENTITY DRAGGING
-
-void crosshair_trace_plusvisibletriggers(entity pl)
-{
-       entity first;
-       entity e;
-       first = findchainfloat(solid, SOLID_TRIGGER);
-
-       for (e = first; e; e = e.chain)
-               if (e.model != "")
-                       e.solid = SOLID_BSP;
-
-       crosshair_trace(pl);
-
-       for (e = first; e; e = e.chain)
-               e.solid = SOLID_TRIGGER;
+       return FALSE;
 }
 
 // on dragger:
@@ -937,11 +949,6 @@ void Drag_MoveDrag(entity from, entity to)
        }
 }
 
-
-
-
-
-
 void DragBox_Think()
 {
        if(self.aiment && self.enemy)
index 8c276919c51082206169b6050dd44335d7d1fc84..46152692e969e64dd9dfff6cd85f6e8b781747e1 100644 (file)
@@ -11,3 +11,5 @@ float CheatCommand(float argc);
 float CheatFrame();
 
 void Drag_MoveDrag(entity from, entity to); // call this from CopyBody
+
+float Drag(entity e, float grab); // used by sandbox code
\ No newline at end of file
index 8b9cfec127f529c968982e103878561476487f6e..8b60d942bf7304c914c71bb993fd9bcf49bc52bb 100644 (file)
@@ -8,6 +8,21 @@ void crosshair_trace(entity pl)
 {
        traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
 }
+void crosshair_trace_plusvisibletriggers(entity pl)
+{
+       entity first;
+       entity e;
+       first = findchainfloat(solid, SOLID_TRIGGER);
+
+       for (e = first; e; e = e.chain)
+               if (e.model != "")
+                       e.solid = SOLID_BSP;
+
+       crosshair_trace(pl);
+
+       for (e = first; e; e = e.chain)
+               e.solid = SOLID_TRIGGER;
+}
 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
 void WarpZone_crosshair_trace(entity pl)
 {
@@ -1086,6 +1101,8 @@ void readlevelcvars(void)
                MUTATOR_ADD(mutator_rocketflying);
        if(cvar("g_vampire"))
                MUTATOR_ADD(mutator_vampire);
+       if(cvar("g_sandbox"))
+               MUTATOR_ADD(sandbox);
 
        if(cvar("sv_allow_fullbright"))
                serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
index 73b23bbd3f224201ecffa53725fe544a3b225573..621e4db6cb9baa5b1409b7a38da33e8d44cdb7bb 100644 (file)
@@ -188,3 +188,6 @@ MUTATOR_HOOKABLE(SV_ParseClientCommand);
                        return 0;
                }
        */
+
+MUTATOR_HOOKABLE(SV_StartFrame);
+       // runs globally each server frame
index 1ae28abe54ff961700c030d9e305119aa51bd5ec..349d945dfa87e6aac7b0ea6818e1864ac227e6ac 100644 (file)
@@ -7,3 +7,5 @@ MUTATOR_DECLARATION(mutator_nix);
 MUTATOR_DECLARATION(mutator_dodging);
 MUTATOR_DECLARATION(mutator_rocketflying);
 MUTATOR_DECLARATION(mutator_vampire);
+
+MUTATOR_DECLARATION(sandbox);
diff --git a/qcsrc/server/mutators/sandbox.qc b/qcsrc/server/mutators/sandbox.qc
new file mode 100644 (file)
index 0000000..4e8756f
--- /dev/null
@@ -0,0 +1,513 @@
+float object_count;
+.string object_clipboard;
+.entity object_attach;
+.string material;
+
+.float touch_timer;
+void sandbox_Object_Touch()
+{
+       // apply material impact effects
+
+       if(!self.material)
+               return;
+       if(self.touch_timer > time)
+               return; // don't execute each frame
+       self.touch_timer = time + 0.1;
+
+       // make particle count and sound volume depend on impact speed
+       float intensity;
+       intensity = vlen(self.velocity) + vlen(other.velocity);
+       if(intensity) // avoid divisions by 0
+               intensity /= 2; // average the two velocities
+       if not(intensity >= autocvar_g_sandbox_object_material_velocity_min)
+               return; // impact not strong enough to do anything
+       // now offset intensity and apply it to the effects
+       intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
+       intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
+
+       sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".ogg"), VOL_BASE * intensity, ATTN_NORM);
+       pointparticles(particleeffectnum(strcat("impact_", self.material)), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
+}
+
+entity sandbox_EditObject_Get()
+{
+       // returns the traced entity if the player can edit it, and world if not
+       // attached objects are SOLID_NOT and don't risk getting traced
+
+       makevectors(self.v_angle);
+       WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_edit, MOVE_NORMAL, self);
+
+       if(trace_ent.classname != "object")
+               return world; // entity is not an object
+       if(!trace_ent.crypto_idfp)
+               return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
+       else if not(trace_ent.crypto_idfp != self.crypto_idfp && !autocvar_g_sandbox_editor_free)
+               return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
+       return world;
+}
+
+void sandbox_EditObject_Scale(entity e, float f)
+{
+       e.scale = f;
+       if(e.scale)
+       {
+               e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
+               setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
+       }
+}
+
+.float old_movetype;
+void sandbox_AttachObject_Set(entity e, entity parent, string s)
+{
+       // attaches e to parent on string s
+
+       e.old_movetype = e.movetype; // persist this
+
+       e.movetype = MOVETYPE_FOLLOW;
+       e.solid = SOLID_NOT;
+       e.takedamage = DAMAGE_NO;
+
+       setattachment(e, parent, s);
+       e.owner = parent;
+}
+
+void sandbox_AttachObject_Remove(entity e)
+{
+       // detaches any object attached to e
+
+       entity head;
+       for(head = world; (head = find(head, classname, "object")); )
+       {
+               if(head.owner == e)
+               {
+                       head.movetype = head.old_movetype; // revert to previous physics
+                       head.solid = SOLID_BBOX;
+                       head.takedamage = DAMAGE_AIM;
+
+                       setattachment(head, world, "");
+                       head.owner = world;
+
+                       // objects reset origin and angles when detached, so apply the parent's to prevent teleporting
+                       setorigin(head, e.origin);
+                       head.angles = e.angles;
+               }
+       }
+}
+
+entity sandbox_SpawnObject()
+{
+       // spawn a new object with default properties
+
+       entity e;
+       e = spawn();
+       e.classname = "object";
+       e.takedamage = DAMAGE_AIM;
+       e.damageforcescale = 1;
+       e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
+       e.movetype = MOVETYPE_TOSS;
+       e.frame = 0;
+       e.skin = 0;
+       e.material = string_null;
+       e.touch = sandbox_Object_Touch;
+
+       // set the object's owner via player UID
+       // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
+       if(self.crypto_idfp != "")
+               e.crypto_idfp = strzone(self.crypto_idfp);
+       else
+               print_to(self, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
+
+       // set origin and direction based on player position and view angle
+       makevectors(self.v_angle);
+       WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, self);
+       setorigin(e, trace_endpos);
+       e.angles_y = self.v_angle_y;
+
+       object_count += 1;
+       return e;
+}
+
+void sandbox_RemoveObject(entity e)
+{
+       sandbox_AttachObject_Remove(e); // detach child objects
+       if(e.material)
+       {
+               strunzone(e.material);
+               e.material = string_null;
+       }
+       if(e.crypto_idfp)
+       {
+               strunzone(e.crypto_idfp);
+               e.crypto_idfp = string_null;
+       }
+       remove(e);
+       e = world;
+
+       object_count -= 1;
+}
+
+string sandbox_Storage_Save(entity e)
+{
+       // save object properties
+       string s;
+
+       s = strcat(e.model, " ");
+       s = strcat(s, ftos(e.skin), " ");
+       s = strcat(s, ftos(e.alpha), " ");
+       s = strcat(s, sprintf("\"%.9v\"", e.colormod), " ");
+       s = strcat(s, sprintf("\"%.9v\"", e.glowmod), " ");
+       s = strcat(s, ftos(e.frame), " ");
+       s = strcat(s, ftos(e.scale), " ");
+       s = strcat(s, ftos(e.movetype), " ");
+       s = strcat(s, ftos(e.damageforcescale), " ");
+       s = strcat(s, e.material, " ");
+
+       return s;
+}
+
+void sandbox_Storage_Load(entity e, string s)
+{
+       // load object properties
+       tokenize_console(s);
+
+       setmodel(e, argv(0));
+       e.skin = stof(argv(1));
+       e.alpha = stof(argv(2));
+       e.colormod = stov(argv(3));
+       e.glowmod = stov(argv(4));
+       e.frame = stof(argv(5));
+       sandbox_EditObject_Scale(e, stof(argv(6)));
+       e.movetype = stof(argv(7));
+       e.damageforcescale = stof(argv(8));
+       if(e.material)  strunzone(e.material);  if(argv(9))     e.material = strzone(argv(9));  else    e.material = string_null;
+}
+
+MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
+{
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return FALSE;
+       if(cmd_name == "g_sandbox")
+       {
+               if(cmd_argc < 2)
+               {
+                       print_to(self, "Sandbox mode is active. For usage information, type 'sandbox help'");
+                       return TRUE;
+               }
+
+               switch(argv(1))
+               {
+                       entity e;
+                       float i;
+
+                       // ---------------- COMMAND: HELP ----------------
+                       case "help":
+                               print_to(self, "You can use the following sandbox commands:");
+                               print_to(self, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
+                               print_to(self, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
+                               print_to(self, "^7\"^2object_duplicate ^3value^7\" duplicates the object. 'copy' copies the object, 'paste' puts it in front of the player");
+                               print_to(self, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
+                               print_to(self, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
+                               print_to(self, "^7Attachment properties for ^2object_attach^7:");
+                               print_to(self, "^3get ^7- selects the object you are facing as the object to be attached");
+                               print_to(self, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
+                               print_to(self, "^3remove ^7- detaches all objects from the object you are facing");
+                               print_to(self, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
+                               print_to(self, "^7Object properties for ^2object_edit^7:");
+                               print_to(self, "^3skin value ^7- changes the skin of the object");
+                               print_to(self, "^3alpha value ^7- sets object transparency");
+                               print_to(self, "^3colormod \"value_x value_y value_z\" ^7- main object color");
+                               print_to(self, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
+                               print_to(self, "^3frame value ^7- object animation frame, for self-animated models");
+                               print_to(self, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
+                               print_to(self, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
+                               print_to(self, "^3force value ^7- amount of force applied to objects that are shot");
+                               print_to(self, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
+                               print_to(self, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
+                               return TRUE;
+
+                       // ---------------- COMMAND: SPAWN OBJECT ----------------
+                       case "object_spawn":
+                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+                               {
+                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+                                       return TRUE;
+                               }
+                               if(cmd_argc < 3)
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
+                                       return TRUE;
+                               }
+                               else if not(fexists(argv(2)))
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
+                                       return TRUE;
+                               }
+
+                               e = sandbox_SpawnObject();
+                               setmodel(e, argv(2));
+
+                               if(autocvar_g_sandbox_info > 0)
+                                       print(strcat("^3SANDBOX - SERVER: ^7", self.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
+                               return TRUE;
+
+                       // ---------------- COMMAND: REMOVE OBJECT ----------------
+                       case "object_remove":
+                               e = sandbox_EditObject_Get();
+                               if(e != world)
+                               {
+                                       if(autocvar_g_sandbox_info > 0)
+                                               print(strcat("^3SANDBOX - SERVER: ^7", self.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
+                                       sandbox_RemoveObject(e);
+                                       return TRUE;
+                               }
+
+                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
+                               return TRUE;
+
+                       // ---------------- COMMAND: DUPLICATE OBJECT ----------------
+                       case "object_duplicate":
+                               switch(argv(2))
+                               {
+                                       case "copy":
+                                               // copies customizable properties of the selected object to the clipboard
+                                               e = sandbox_EditObject_Get(); // you can only copy objects you can edit, so this works
+                                               if(e != world)
+                                               {
+                                                       if(self.object_clipboard)
+                                                               strunzone(self.object_clipboard);
+                                                       self.object_clipboard = strzone(sandbox_Storage_Save(e));
+
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Object copied to clipboard");
+                                                       return TRUE;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have edit rights over");
+                                               return TRUE;
+
+                                       case "paste":
+                                               // spawns a new object using the properties in the player's clipboard
+                                               if(!self.object_clipboard) // no object in clipboard
+                                               {
+                                                       print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
+                                                       return TRUE;
+                                               }
+                                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+                                               {
+                                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+                                                       return TRUE;
+                                               }
+
+                                               e = sandbox_SpawnObject();
+                                               sandbox_Storage_Load(e, self.object_clipboard);
+
+                                               print_to(self, "^2SANDBOX - INFO: ^7Object pasted successfully");
+                                               if(autocvar_g_sandbox_info > 0)
+                                                       print(strcat("^3SANDBOX - SERVER: ^7", self.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
+                                               return TRUE;
+                               }
+                               return TRUE;
+
+                       // ---------------- COMMAND: CLAIM OBJECT ----------------
+                       case "object_claim":
+                               // if the player can edit an object but is not its owner, this can be used to claim that object
+                               if(self.crypto_idfp == "")
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
+                                       return TRUE;
+                               }
+                               e = sandbox_EditObject_Get();
+                               if(e != world)
+                               {
+                                       if(e.crypto_idfp == self.crypto_idfp)
+                                       {
+                                               print_to(self, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
+                                               return TRUE;
+                                       }
+
+                                       if(e.crypto_idfp)
+                                               strunzone(e.crypto_idfp);
+                                       e.crypto_idfp = self.crypto_idfp;
+                                       print_to(self, "^2SANDBOX - INFO: ^7Object claimed successfully");
+                               }
+                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
+                               return TRUE;
+
+                       // ---------------- COMMAND: ATTACH OBJECT ----------------
+                       case "object_attach":
+                               switch(argv(2))
+                               {
+                                       case "get":
+                                               // select e as the object as meant to be attached
+                                               e = sandbox_EditObject_Get();
+                                               if(e != world)
+                                               {
+                                                       self.object_attach = e;
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Object selected for attachment");
+                                                       return TRUE;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
+                                               return TRUE;
+                                       case "set":
+                                               if(self.object_attach == world)
+                                               {
+                                                       print_to(self, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
+                                                       return TRUE;
+                                               }
+
+                                               // attaches the previously selected object to e
+                                               e = sandbox_EditObject_Get();
+                                               if(e != world)
+                                               {
+                                                       sandbox_AttachObject_Set(self.object_attach, e, argv(3));
+                                                       self.object_attach = world; // object was attached, no longer keep it scheduled for attachment
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Object attached successfully");
+                                                       if(autocvar_g_sandbox_info > 1)
+                                                               print(strcat("^3SANDBOX - SERVER: ^7", self.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
+                                                       return TRUE;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
+                                               return TRUE;
+                                       case "remove":
+                                               // removes e if it was attached
+                                               e = sandbox_EditObject_Get();
+                                               if(e != world)
+                                               {
+                                                       sandbox_AttachObject_Remove(e);
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Child objects detached successfully");
+                                                       if(autocvar_g_sandbox_info > 1)
+                                                               print(strcat("^3SANDBOX - SERVER: ^7", self.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
+                                                       return TRUE;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
+                                               return TRUE;
+                               }
+                               return TRUE;
+
+                       // ---------------- COMMAND: EDIT OBJECT ----------------
+                       case "object_edit":
+                               if(!argv(2))
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
+                                       return TRUE;
+                               }
+
+                               e = sandbox_EditObject_Get();
+                               if(e != world)
+                               {
+                                       switch(argv(2))
+                                       {
+                                               case "skin":
+                                                       e.skin = stof(argv(3));
+                                                       break;
+                                               case "alpha":
+                                                       e.alpha = stof(argv(3));
+                                                       break;
+                                               case "color_main":
+                                                       e.colormod = stov(argv(3));
+                                                       break;
+                                               case "color_glow":
+                                                       e.glowmod = stov(argv(3));
+                                                       break;
+                                               case "frame":
+                                                       e.frame = stof(argv(3));
+                                                       break;
+                                               case "scale":
+                                                       sandbox_EditObject_Scale(e, stof(argv(3)));
+                                                       break;
+                                               case "physics":
+                                                       switch(argv(3))
+                                                       {
+                                                               case "0": // static
+                                                                       e.movetype = MOVETYPE_NONE;
+                                                                       break;
+                                                               case "1": // movable
+                                                                       e.movetype = MOVETYPE_TOSS;
+                                                                       break;
+                                                               case "2": // physical
+                                                                       e.movetype = MOVETYPE_PHYSICS;
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                       }
+                                                       break;
+                                               case "force":
+                                                       e.damageforcescale = stof(argv(3));
+                                                       break;
+                                               case "material":
+                                                       if(e.material)
+                                                               strunzone(e.material);
+                                                       if(argv(3))
+                                                       {
+                                                               for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
+                                                                       precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".ogg"));
+                                                               e.material = strzone(argv(3));
+                                                       }
+                                                       else
+                                                               e.material = string_null; // no material
+                                                       break;
+                                               default:
+                                                       print_to(self, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
+                                                       break;
+                                       }
+                                       if(autocvar_g_sandbox_info > 1)
+                                               print(strcat("^3SANDBOX - SERVER: ^7", self.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
+                                       return TRUE;
+                               }
+
+                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
+                               return TRUE;
+
+                       // ---------------- COMMAND: DEFAULT ----------------
+                       default:
+                               print_to(self, "Invalid command. For usage information, type 'sandbox help'");
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(sandbox_PlayerPreThink)
+{
+       // if the player is close enough to their object, they can drag it
+
+       if(autocvar_sv_cheats)
+               return FALSE; // cheat dragging is used instead
+
+       // grab is TRUE if the object can be picked up. While an object is being carried, the Drag() function
+       // must execute for it either way, otherwise it would cause bugs if it went out of the player's trace.
+       // This also makes sure that an object can only pe picked up if in range, but does not get dropped if
+       // it goes out of range while slinging it around.
+
+       entity e;
+       float grab;
+
+       e = sandbox_EditObject_Get();
+       if(e != world && vlen(e.origin - self.origin) <= autocvar_g_sandbox_editor_distance_edit)
+               grab = TRUE;
+
+       if(Drag(e, grab)) // execute dragging
+               return TRUE;
+
+       return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(sandbox_ClientDisconnect)
+{
+       // unzone the player's clipboard if it's not empty
+       if(self.object_clipboard)
+       {
+               strunzone(self.object_clipboard);
+               self.object_clipboard = string_null;
+       }
+
+       return FALSE;
+}
+
+MUTATOR_DEFINITION(sandbox)
+{
+       MUTATOR_HOOK(SV_ParseClientCommand, sandbox_PlayerCommand, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerPreThink, sandbox_PlayerPreThink, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ClientDisconnect, sandbox_ClientDisconnect, CBC_ORDER_ANY);
+
+       return FALSE;
+}
+
index c29ac5ff965380bd8dde021b95856a8eef9a385d..8ba264665d93c74a002f72027e21c1287e88f9b9 100644 (file)
@@ -197,6 +197,7 @@ mutators/mutator_nix.qc
 mutators/mutator_dodging.qc
 mutators/mutator_rocketflying.qc
 mutators/mutator_vampire.qc
+mutators/sandbox.qc
 
 ../warpzonelib/anglestransform.qc
 ../warpzonelib/mathlib.qc
index eb386005d16f16201ba064b01d32e799b1a85bee..d11f235224056a9c9526cbaa5944e2b514a5bc89 100644 (file)
@@ -242,6 +242,8 @@ void StartFrame (void)
 
        FOR_EACH_PLAYER(self)
                self.porto_forbidden = max(0, self.porto_forbidden - 1);
+
+       MUTATOR_CALLHOOK(SV_StartFrame);
 }
 
 .vector originjitter;
diff --git a/sound/object/impact_flesh_1.ogg b/sound/object/impact_flesh_1.ogg
new file mode 100644 (file)
index 0000000..2d7d423
Binary files /dev/null and b/sound/object/impact_flesh_1.ogg differ
diff --git a/sound/object/impact_flesh_2.ogg b/sound/object/impact_flesh_2.ogg
new file mode 100644 (file)
index 0000000..c490c75
Binary files /dev/null and b/sound/object/impact_flesh_2.ogg differ
diff --git a/sound/object/impact_flesh_3.ogg b/sound/object/impact_flesh_3.ogg
new file mode 100644 (file)
index 0000000..12af028
Binary files /dev/null and b/sound/object/impact_flesh_3.ogg differ
diff --git a/sound/object/impact_flesh_4.ogg b/sound/object/impact_flesh_4.ogg
new file mode 100644 (file)
index 0000000..18bf012
Binary files /dev/null and b/sound/object/impact_flesh_4.ogg differ
diff --git a/sound/object/impact_flesh_5.ogg b/sound/object/impact_flesh_5.ogg
new file mode 100644 (file)
index 0000000..2c83777
Binary files /dev/null and b/sound/object/impact_flesh_5.ogg differ
diff --git a/sound/object/impact_metal_1.ogg b/sound/object/impact_metal_1.ogg
new file mode 100644 (file)
index 0000000..331728a
Binary files /dev/null and b/sound/object/impact_metal_1.ogg differ
diff --git a/sound/object/impact_metal_2.ogg b/sound/object/impact_metal_2.ogg
new file mode 100644 (file)
index 0000000..645dc20
Binary files /dev/null and b/sound/object/impact_metal_2.ogg differ
diff --git a/sound/object/impact_metal_3.ogg b/sound/object/impact_metal_3.ogg
new file mode 100644 (file)
index 0000000..d1128fd
Binary files /dev/null and b/sound/object/impact_metal_3.ogg differ
diff --git a/sound/object/impact_metal_4.ogg b/sound/object/impact_metal_4.ogg
new file mode 100644 (file)
index 0000000..cbb99f8
Binary files /dev/null and b/sound/object/impact_metal_4.ogg differ
diff --git a/sound/object/impact_metal_5.ogg b/sound/object/impact_metal_5.ogg
new file mode 100644 (file)
index 0000000..60d4d43
Binary files /dev/null and b/sound/object/impact_metal_5.ogg differ
diff --git a/sound/object/impact_stone_1.ogg b/sound/object/impact_stone_1.ogg
new file mode 100644 (file)
index 0000000..429b1c5
Binary files /dev/null and b/sound/object/impact_stone_1.ogg differ
diff --git a/sound/object/impact_stone_2.ogg b/sound/object/impact_stone_2.ogg
new file mode 100644 (file)
index 0000000..0a4feb7
Binary files /dev/null and b/sound/object/impact_stone_2.ogg differ
diff --git a/sound/object/impact_stone_3.ogg b/sound/object/impact_stone_3.ogg
new file mode 100644 (file)
index 0000000..f33b43c
Binary files /dev/null and b/sound/object/impact_stone_3.ogg differ
diff --git a/sound/object/impact_stone_4.ogg b/sound/object/impact_stone_4.ogg
new file mode 100644 (file)
index 0000000..507e4a6
Binary files /dev/null and b/sound/object/impact_stone_4.ogg differ
diff --git a/sound/object/impact_stone_5.ogg b/sound/object/impact_stone_5.ogg
new file mode 100644 (file)
index 0000000..89c9df7
Binary files /dev/null and b/sound/object/impact_stone_5.ogg differ
diff --git a/sound/object/impact_wood_1.ogg b/sound/object/impact_wood_1.ogg
new file mode 100644 (file)
index 0000000..cb665e0
Binary files /dev/null and b/sound/object/impact_wood_1.ogg differ
diff --git a/sound/object/impact_wood_2.ogg b/sound/object/impact_wood_2.ogg
new file mode 100644 (file)
index 0000000..ab826a0
Binary files /dev/null and b/sound/object/impact_wood_2.ogg differ
diff --git a/sound/object/impact_wood_3.ogg b/sound/object/impact_wood_3.ogg
new file mode 100644 (file)
index 0000000..1d383c2
Binary files /dev/null and b/sound/object/impact_wood_3.ogg differ
diff --git a/sound/object/impact_wood_4.ogg b/sound/object/impact_wood_4.ogg
new file mode 100644 (file)
index 0000000..314917d
Binary files /dev/null and b/sound/object/impact_wood_4.ogg differ
diff --git a/sound/object/impact_wood_5.ogg b/sound/object/impact_wood_5.ogg
new file mode 100644 (file)
index 0000000..9d8c929
Binary files /dev/null and b/sound/object/impact_wood_5.ogg differ
index 8f2ddab6c9ad842b1d5578a6b1d4c9b48abadb1e..fba2a0ab2c0670513ae2566cb3018a4278a77607 100644 (file)
@@ -38,6 +38,7 @@ mand1nga
 Merlijn Hofstra
 remaxim
 Stephan
+Independent.nu
 
 *Engine Code Additions & QA
 Rudolf "divVerent" Polzer