About
@@ -24,7 +24,6 @@ but no CD-ROM support.
-
-
Hints
Visit the for a full run-down of the engine's commands and variables.
@@ -64,13 +63,17 @@ If your controller doesn't work you can try placing to joystick defaults and behaviour. See the "Controller support / Cvars" section above.
+- Fix for a mouse grabbing issue on macOS.
+
- Add missing support for -ip command line option on unix / macOS.
+
- Backport angled sprites code from FTEQW (spriteframetype: 2, must have 8 frames per group.)
+
- Bump the progs execution runaway loop limit to 16M.
+
- Add signon buffer fragmentation to fix SZ_GetSpace errors on certain maps when using protocol 999.
+
- Increased MAX_DATAGRAM to 64000 to overcome packet overflows.
+
- Bump the MAXALIASFRAMES limit to 1024.
+
- Fix arrays to have proper sizes in gl mesh code, reflecting MAXALIASTRIS and MAXALIASVERTS correctly. (fixes SIGSEGV in mj4m4/mj4m5.)
+
- Increased default value of gl_farclip to 65536.
+
- Increase chase cam target trace distance to allow for chasecam to function in large open maps (useful e.g. for the func_vehicle mod.)
+
- Raised default maximum number of particles to 16384 (can be set up to 32768 with -particles on the command line.)
+
- Fix on-screen keyboard showing up suddenly on Steam Deck when starting a map.
+
- Fix viewmodel interpolation with >10Hz animations.
+
- Fix a memory leak when exiting game in SDL2 builds.
+
- Fix a possible crash when handling clipboard data on macOS.
+
- Fix a potential crash after loading of saved game.
+
- Fix possible out-of-bound reads when handling progs type sizes.
+
- Fix Dutch angle VP_PARALLEL_UPRIGHT sprites.
+
- Fix an issue with lights blending by using 10 bit color depth for lightmaps. (For GLSL mode only.) Disable with "-nopackedpixels", if necessary.
+
- No relative motions when the window is not focused.
+
- Status bar and intermission screen tweaks.
+
- Properly display monster counts > 3 digits.
+
- Fix console animation with scr_conspeed <= 0.
+
- Fix mouselook not working upon game quickload during a demo play.
+
- Haiku operating system support.
+
- Fix console when server is run noninteractively with stdin redirected from /dev/null.
+
- Updated Visual Studio project files.
+
- Minor code cleanups. Updated third party code, e.g. SDL, music codecs, etc.
+
- Thanks to Andrei Drexler, Alexey Lysiuk, Andrey Budko, Boris I. Bendovsky, Chris Cowan, Maciej Olędzki, Simon McVittie, OscarL, Eric Wasylishen, Jaycie Ewald and Spike for patches.
+
+
+
Changes in 0.95.1
- Allow mixing lit and unlit textures in the same map.
diff --git a/Misc/quake_retexturing_project.patch b/Misc/fix_externaltex.patch
similarity index 84%
rename from Misc/quake_retexturing_project.patch
rename to Misc/fix_externaltex.patch
index 907a5ca4b..4da5489f7 100644
--- a/Misc/quake_retexturing_project.patch
+++ b/Misc/fix_externaltex.patch
@@ -1,5 +1,7 @@
+-- from quake retexturing project
+
diff --git a/Quake/gl_model.c b/Quake/gl_model.c
-index d193051..783dc4d 100644
+index 239d361..80948f1 100644
--- a/Quake/gl_model.c
+++ b/Quake/gl_model.c
@@ -39,6 +39,8 @@ static void Mod_Print (void);
@@ -11,7 +13,7 @@ index d193051..783dc4d 100644
static byte *mod_novis;
static int mod_novis_capacity;
-@@ -542,6 +544,13 @@ static void Mod_LoadTextures (lump_t *l)
+@@ -549,6 +551,13 @@ static void Mod_LoadTextures (lump_t *l)
{
if (!q_strncasecmp(tx->name,"sky",3)) //sky texture //also note -- was Q_strncmp, changed to match qbsp
{
@@ -25,7 +27,7 @@ index d193051..783dc4d 100644
if (loadmodel->bspversion == BSPVERSION_QUAKE64)
Sky_LoadTextureQ64 (loadmodel, tx);
else
-@@ -596,6 +605,50 @@ static void Mod_LoadTextures (lump_t *l)
+@@ -606,6 +615,50 @@ static void Mod_LoadTextures (lump_t *l)
//external textures -- first look in "textures/mapname/" then look in "textures/"
mark = Hunk_LowMark ();
COM_StripExtension (loadmodel->name + 5, mapname, sizeof(mapname));
@@ -77,10 +79,10 @@ index d193051..783dc4d 100644
data = Image_LoadImage (filename, &fwidth, &fheight);
if (!data)
diff --git a/Quake/gl_rmain.c b/Quake/gl_rmain.c
-index 332ab1e..783a9d6 100644
+index 6883161..4a8a745 100644
--- a/Quake/gl_rmain.c
+++ b/Quake/gl_rmain.c
-@@ -99,6 +99,8 @@ cvar_t r_noshadow_list = {"r_noshadow_list", "progs/flame2.mdl,progs/flame.mdl,p
+@@ -100,6 +100,8 @@ cvar_t r_noshadow_list = {"r_noshadow_list", "progs/flame2.mdl,progs/flame.mdl,p
extern cvar_t r_vfog;
//johnfitz
@@ -90,7 +92,7 @@ index 332ab1e..783a9d6 100644
cvar_t r_lavaalpha = {"r_lavaalpha","0",CVAR_NONE};
diff --git a/Quake/gl_rmisc.c b/Quake/gl_rmisc.c
-index dc3dff0..dbfe922 100644
+index 93791f6..4006c5d 100644
--- a/Quake/gl_rmisc.c
+++ b/Quake/gl_rmisc.c
@@ -47,6 +47,7 @@ extern cvar_t r_nolerp_list;
@@ -101,11 +103,11 @@ index dc3dff0..dbfe922 100644
extern gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz
-@@ -218,6 +219,7 @@ void R_Init (void)
- Cvar_RegisterVariable (&r_noshadow_list);
- Cvar_SetCallback (&r_noshadow_list, R_Model_ExtraFlags_List_f);
- //johnfitz
-+ Cvar_RegisterVariable (&r_externaltexture_fix); //mk
+@@ -231,6 +232,7 @@ void R_Init (void)
+ Cvar_SetCallback (&r_lavaalpha, R_SetLavaalpha_f);
+ Cvar_SetCallback (&r_telealpha, R_SetTelealpha_f);
+ Cvar_SetCallback (&r_slimealpha, R_SetSlimealpha_f);
++ Cvar_RegisterVariable (&r_externaltexture_fix);//mk
- Cvar_RegisterVariable (&gl_zfix); // QuakeSpasm z-fighting fix
- Cvar_RegisterVariable (&r_lavaalpha);
+ R_InitParticles ();
+ R_SetClearColor_f (&r_clearcolor); //johnfitz
diff --git a/Misc/fs_search_order.patch b/Misc/fs_search_order.patch
index 0fba6a55d..781807937 100644
--- a/Misc/fs_search_order.patch
+++ b/Misc/fs_search_order.patch
@@ -1,10 +1,10 @@
-allow plain files to override files inside a PAK file -- Sander van Dijk.
+allow plain files to override files inside a PAK -- Sander van Dijk.
diff --git a/Quake/common.c b/Quake/common.c
-index eff4c30..1478d77 100644
+index c80450f..6074711 100644
--- a/Quake/common.c
+++ b/Quake/common.c
-@@ -2030,13 +2030,6 @@ static void COM_AddGameDirectory (const char *base, const char *dir)
+@@ -2107,13 +2107,6 @@ static void COM_AddGameDirectory (const char *base, const char *dir)
else path_id = 1U;
_add_path:
@@ -18,7 +18,7 @@ index eff4c30..1478d77 100644
// add any pak files in the format pak0.pak pak1.pak, ...
for (i = 0; ; i++)
{
-@@ -2068,6 +2061,13 @@ _add_path:
+@@ -2145,6 +2138,13 @@ _add_path:
if (!pak) break;
}
@@ -32,4 +32,3 @@ index eff4c30..1478d77 100644
if (!been_here && host_parms->userdir != host_parms->basedir)
{
been_here = true;
-
diff --git a/Misc/pak/default.cfg.diff b/Misc/pak/default.cfg.diff
new file mode 100644
index 000000000..085513ff6
--- /dev/null
+++ b/Misc/pak/default.cfg.diff
@@ -0,0 +1,76 @@
+--- default.cfg~
++++ default.cfg
+@@ -12,24 +12,26 @@
+ bind ALT +strafe
+
+ bind , +moveleft
++bind a +moveleft
+ bind . +moveright
++bind d +moveright
+ bind DEL +lookdown
+ bind PGDN +lookup
+ bind END centerview
+-bind z +lookdown
+-bind a +lookup
+
+-bind d +moveup
++bind e +moveup
+ bind c +movedown
+ bind SHIFT +speed
+ bind CTRL +attack
+ bind UPARROW +forward
++bind w +forward
+ bind DOWNARROW +back
++bind s +back
+ bind LEFTARROW +left
+ bind RIGHTARROW +right
+
+ bind SPACE +jump
+-bind ENTER +jump
++//bind ENTER +jump
+
+ bind TAB +showscores
+
+@@ -45,6 +47,8 @@
+ bind 0 "impulse 0"
+
+ bind / "impulse 10" // change weapon
++bind MWHEELDOWN "impulse 10"
++bind MWHEELUP "impulse 12"
+
+ // zoom
+ alias zoom_in "sensitivity 2;fov 90;wait;fov 70;wait;fov 50;wait;fov 30;wait;fov 10;wait;fov 5;bind F11 zoom_out"
+@@ -85,14 +89,30 @@
+ // mouse buttons
+ //
+ bind MOUSE1 +attack
+-bind MOUSE2 +forward
+-bind MOUSE3 +mlook
++//bind MOUSE2 +forward
++bind MOUSE2 +jump
++//bind MOUSE3 +mlook
++
++//
++// game controller
++//
++bind LSHOULDER "impulse 12"
++bind RSHOULDER "impulse 10"
++bind LTRIGGER +jump
++bind RTRIGGER +attack
+
+ //
+ // default cvars
+ //
+-viewsize 100
+ gamma 1.0
+ volume 0.7
+ sensitivity 3
+
++//viewsize 100
++viewsize 110
++scr_conscale 1.6
++scr_menuscale 1.6
++scr_sbarscale 1.6
++
++// default to mouse-look enabled
+++mlook
diff --git a/Misc/pak/default.cfg.orig b/Misc/pak/default.cfg.orig
deleted file mode 100644
index c4510501f..000000000
--- a/Misc/pak/default.cfg.orig
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// load keybindings
-//
-// commands with a leading + will also be called for key up events with
-// the + changed to a -
-unbindall
-
-//
-// character controls
-//
-
-bind ALT +strafe
-
-bind , +moveleft
-bind . +moveright
-bind DEL +lookdown
-bind PGDN +lookup
-bind END centerview
-bind z +lookdown
-bind a +lookup
-
-bind d +moveup
-bind c +movedown
-bind SHIFT +speed
-bind CTRL +attack
-bind UPARROW +forward
-bind DOWNARROW +back
-bind LEFTARROW +left
-bind RIGHTARROW +right
-
-bind SPACE +jump
-bind ENTER +jump
-
-bind TAB +showscores
-
-bind 1 "impulse 1"
-bind 2 "impulse 2"
-bind 3 "impulse 3"
-bind 4 "impulse 4"
-bind 5 "impulse 5"
-bind 6 "impulse 6"
-bind 7 "impulse 7"
-bind 8 "impulse 8"
-
-bind 0 "impulse 0"
-
-bind / "impulse 10" // change weapon
-
-// zoom
-alias zoom_in "sensitivity 2;fov 90;wait;fov 70;wait;fov 50;wait;fov 30;wait;fov 10;wait;fov 5;bind F11 zoom_out"
-alias zoom_out "sensitivity 4;fov 5;wait;fov 10;wait;fov 30;wait;fov 50;wait;fov 70;wait;fov 90;bind F11 zoom_in; sensitivity 3"
-bind F11 zoom_in
-
-// Function keys
-bind F1 "help"
-bind F2 "menu_save"
-bind F3 "menu_load"
-bind F4 "menu_options"
-bind F5 "menu_multiplayer"
-bind F6 "echo Quicksaving...; wait; save quick"
-bind F9 "echo Quickloading...; wait; load quick"
-bind F10 "quit"
-bind F12 "screenshot"
-
-// mouse options
-bind \ +mlook
-
-//
-// client environment commands
-//
-bind PAUSE "pause"
-bind ESCAPE "togglemenu"
-bind ~ "toggleconsole"
-bind ` "toggleconsole"
-
-bind t "messagemode"
-
-bind + "sizeup"
-bind = "sizeup"
-bind - "sizedown"
-
-bind INS +klook
-
-//
-// mouse buttons
-//
-bind MOUSE1 +attack
-bind MOUSE2 +forward
-bind MOUSE3 +mlook
-
-//
-// default cvars
-//
-viewsize 100
-gamma 1.0
-volume 0.7
-sensitivity 3
-
diff --git a/Misc/pak/maps/e1m1.diff b/Misc/pak/maps/e1m1.diff
new file mode 100644
index 000000000..f834b9cca
--- /dev/null
+++ b/Misc/pak/maps/e1m1.diff
@@ -0,0 +1,18 @@
+--- e1m1.ent
++++ e1m1@c49d.ent
+@@ -715,14 +715,15 @@
+ {
+ "classname" "func_door"
+ "targetname" "t4"
+ "angle" "-2"
+ "spawnflags" "1"
+ "sounds" "2"
+ "model" "*15"
++"lip" "7" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "trigger_multiple"
+ "target" "t4"
+ "health" "1"
+ "model" "*16"
+ }
diff --git a/Misc/pak/maps/e1m1.ent.orig b/Misc/pak/maps/e1m1.ent.orig
deleted file mode 100644
index 7796105e7..000000000
--- a/Misc/pak/maps/e1m1.ent.orig
+++ /dev/null
@@ -1,1969 +0,0 @@
-{
-"worldtype" "2"
-"sounds" "6"
-"classname" "worldspawn"
-"wad" "gfx/base.wad"
-"message" "the Slipgate Complex"
-}
-{
-"classname" "info_player_start"
-"origin" "480 -352 88"
-"angle" "90"
-}
-{
-"classname" "light"
-"origin" "480 96 168"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "480 288 168"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "272 96 80"
-}
-{
-"origin" "272 288 80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "272 192 80"
-}
-{
-"origin" "688 192 80"
-"classname" "light_fluorospark"
-"style" "10"
-}
-{
-"style" "10"
-"classname" "light"
-"origin" "688 288 80"
-}
-{
-"origin" "688 96 80"
-"classname" "light"
-"style" "10"
-}
-{
-"classname" "light"
-"origin" "480 -280 168"
-"light" "200"
-}
-{
-"origin" "480 -144 168"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "480 -376 120"
-"light" "200"
-}
-{
-"light" "160"
-"origin" "480 -40 168"
-"classname" "light"
-}
-{
-"speed" "400"
-"sounds" "2"
-"angle" "270"
-"classname" "func_door"
-"model" "*1"
-}
-{
-"speed" "400"
-"angle" "90"
-"classname" "func_door"
-"model" "*2"
-}
-{
-"light" "250"
-"origin" "592 544 88"
-"classname" "light_fluoro"
-}
-{
-"origin" "456 600 104"
-"classname" "light"
-}
-{
-"light" "180"
-"origin" "688 648 136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "688 520 136"
-"light" "180"
-}
-{
-"origin" "688 480 80"
-"classname" "item_armor1"
-}
-{
-"angle" "180"
-"spawnflags" "768"
-"origin" "616 72 40"
-"classname" "monster_army"
-}
-{
-"light" "250"
-"origin" "0 576 120"
-"classname" "light"
-}
-{
-"light" "180"
-"origin" "160 576 72"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "560 -32 72"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "400 -32 72"
-}
-{
-"light" "200"
-"origin" "0 712 72"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "0 728 -136"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "0 592 -136"
-"classname" "light"
-}
-{
-"wait" "5"
-"angle" "-2"
-"sounds" "2"
-"targetname" "t1"
-"classname" "func_door"
-"dmg" "10"
-"model" "*3"
-}
-{
-"sounds" "1"
-"target" "t1"
-"angle" "180"
-"classname" "func_button"
-"model" "*4"
-}
-{
-"light" "200"
-"origin" "412 780 136"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "328 904 72"
-}
-{
-"light" "200"
-"origin" "168 800 72"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "-72 864 72"
-}
-{
-"origin" "264 888 -136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-8 992 -136"
-"light" "200"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "272 1064 -136"
-}
-{
-"light" "250"
-"origin" "-8 1232 -136"
-"classname" "light"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "256 1272 -136"
-}
-{
-"light" "250"
-"origin" "312 1464 -136"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "128 968 72"
-"classname" "light"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "-48 1168 72"
-}
-{
-"light" "250"
-"origin" "312 1168 72"
-"classname" "light"
-}
-{
-"light" "220"
-"classname" "light"
-"origin" "128 1504 -120"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "-56 1464 -136"
-}
-{
-"sounds" "2"
-"classname" "func_door"
-"angle" "180"
-"speed" "400"
-"model" "*5"
-}
-{
-"classname" "func_door"
-"angle" "0"
-"speed" "400"
-"model" "*6"
-}
-{
-"classname" "light_fluoro"
-"origin" "176 1744 -152"
-}
-{
-"origin" "80 1744 -152"
-"classname" "light_fluoro"
-}
-{
-"light" "250"
-"origin" "-232 1600 -136"
-"classname" "light"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "488 1600 -136"
-}
-{
-"origin" "-56 1448 72"
-"classname" "light"
-"light" "250"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "312 1448 72"
-}
-{
-"light" "260"
-"classname" "light_fluoro"
-"origin" "416 2064 -112"
-}
-{
-"light" "260"
-"origin" "416 1968 -112"
-"classname" "light_fluoro"
-}
-{
-"light" "250"
-"origin" "128 1880 -112"
-"classname" "light"
-}
-{
-"origin" "616 1944 -88"
-"classname" "light"
-}
-{
-"style" "10"
-"classname" "light_fluorospark"
-"origin" "344 2216 -88"
-}
-{
-"light" "180"
-"origin" "352 2016 -112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "128 2056 -112"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "-112 1984 -112"
-"classname" "light"
-}
-{
-"light" "350"
-"origin" "-472 2064 -88"
-"classname" "light_fluoro"
-}
-{
-"classname" "light"
-"origin" "-192 2208 8"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "-424 2208 8"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "-248 2088 -96"
-"classname" "light"
-}
-{
-"origin" "-200 2384 -72"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-424 2384 -72"
-}
-{
-"light" "200"
-"origin" "-448 2408 -128"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-176 2408 -128"
-"light" "200"
-}
-{
-"sounds" "1"
-"classname" "func_plat"
-"model" "*7"
-}
-{
-"light" "350"
-"origin" "-352 2656 184"
-"classname" "light"
-}
-{
-"light" "350"
-"classname" "light"
-"origin" "-352 2464 184"
-}
-{
-"origin" "-576 2800 -40"
-"classname" "light"
-}
-{
-"light" "500"
-"origin" "160 2920 232"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "160 2720 232"
-"light" "500"
-}
-{
-"origin" "-288 2992 8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-168 2776 -40"
-}
-{
-"classname" "light"
-"origin" "160 2824 104"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "-64 2760 136"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "16 2832 -152"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "304 2832 -152"
-"light" "200"
-}
-{
-"origin" "504 2816 16"
-"classname" "light"
-}
-{
-"sounds" "3"
-"wait" "-1"
-"speed" "600"
-"targetname" "t2"
-"spawnflags" "1"
-"angle" "270"
-"classname" "func_door"
-"model" "*8"
-}
-{
-"classname" "light"
-"origin" "160 2840 -152"
-"light" "200"
-}
-{
-"light" "80"
-"origin" "16 2904 -88"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "304 2904 -88"
-"light" "80"
-}
-{
-"classname" "light"
-"origin" "160 2904 -88"
-"light" "80"
-}
-{
-"wait" "-1"
-"sounds" "1"
-"target" "t2"
-"speed" "50"
-"angle" "270"
-"classname" "func_button"
-"model" "*9"
-}
-{
-"light" "100"
-"origin" "0 1800 -32"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "248 1800 -32"
-"light" "100"
-}
-{
-"style" "32"
-"targetname" "t3"
-"origin" "8 2352 200"
-"classname" "light"
-}
-{
-"style" "32"
-"targetname" "t3"
-"classname" "light"
-"origin" "32 2392 200"
-}
-{
-"style" "32"
-"targetname" "t3"
-"origin" "56 2352 200"
-"classname" "light"
-}
-{
-"style" "32"
-"targetname" "t3"
-"classname" "light"
-"origin" "32 2312 200"
-}
-{
-"style" "32"
-"targetname" "t3"
-"light" "200"
-"origin" "32 2352 88"
-"classname" "light"
-}
-{
-"spawnflags" "2048"
-"origin" "112 2352 16"
-"classname" "weapon_nailgun"
-}
-{
-"sounds" "3"
-"targetname" "t3"
-"spawnflags" "3"
-"angle" "270"
-"classname" "func_door_secret"
-"model" "*10"
-}
-{
-"style" "32"
-"sounds" "3"
-"target" "t3"
-"classname" "trigger_once"
-"model" "*11"
-}
-{
-"origin" "304 2368 96"
-"classname" "light"
-}
-{
-"angle" "180"
-"origin" "248 2392 40"
-"classname" "monster_army"
-}
-{
-"origin" "272 2352 64"
-"classname" "item_spikes"
-}
-{
-"style" "32"
-"sounds" "3"
-"target" "t3"
-"classname" "trigger_once"
-"model" "*12"
-}
-{
-"origin" "832 2608 16"
-"classname" "light"
-"light" "220"
-}
-{
-"light" "220"
-"classname" "light"
-"origin" "832 2480 0"
-}
-{
-"light" "240"
-"origin" "800 2816 24"
-"classname" "light"
-}
-{
-"style" "33"
-"targetname" "t11"
-"spawnflags" "1"
-"classname" "light"
-"origin" "752 2000 -88"
-"light" "400"
-}
-{
-"style" "34"
-"spawnflags" "1"
-"targetname" "t12"
-"origin" "1280 2000 -152"
-"classname" "light"
-"light" "400"
-}
-{
-"style" "35"
-"spawnflags" "1"
-"targetname" "t13"
-"classname" "light"
-"origin" "1280 2496 -216"
-"light" "400"
-}
-{
-"style" "36"
-"spawnflags" "1"
-"targetname" "t14"
-"origin" "784 2496 -280"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1368 2584 -488"
-"light" "200"
-}
-{
-"origin" "1368 1944 -488"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "696 2584 -488"
-"light" "150"
-}
-{
-"origin" "1016 2584 -488"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1016 1944 -488"
-"light" "200"
-}
-{
-"origin" "1368 2272 -488"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "696 2272 -488"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "960 2296 -488"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1032 2352 -488"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "888 2352 -488"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "960 2408 -488"
-"classname" "light"
-}
-{
-"light" "100"
-"classname" "light"
-"origin" "984 2448 -304"
-}
-{
-"classname" "light"
-"origin" "832 2360 112"
-"light" "400"
-}
-{
-"classname" "light"
-"origin" "1144 2448 -488"
-}
-{
-"origin" "1232 2360 -488"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1320 2448 -488"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1232 2536 -488"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1232 2136 -488"
-}
-{
-"origin" "1144 2048 -488"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1232 1960 -488"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1320 2048 -488"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "832 2336 -200"
-}
-{
-"classname" "func_door_secret"
-"angle" "90"
-"spawnflags" "2"
-"sounds" "3"
-"model" "*13"
-}
-{
-"classname" "func_door_secret"
-"angle" "180"
-"sounds" "3"
-"model" "*14"
-}
-{
-"classname" "light"
-"origin" "552 2480 -56"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "544 2296 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "664 2480 -56"
-"light" "200"
-}
-{
-"classname" "func_door"
-"targetname" "t4"
-"angle" "-2"
-"spawnflags" "1"
-"sounds" "2"
-"model" "*15"
-}
-{
-"classname" "trigger_multiple"
-"target" "t4"
-"health" "1"
-"model" "*16"
-}
-{
-"spawnflags" "2048"
-"classname" "func_door"
-"angle" "90"
-"targetname" "t5"
-"wait" "-1"
-"sounds" "2"
-"model" "*17"
-}
-{
-"spawnflags" "2048"
-"classname" "trigger_once"
-"target" "t5"
-"model" "*18"
-}
-{
-"classname" "item_artifact_super_damage"
-"origin" "544 2480 -88"
-}
-{
-"classname" "light"
-"origin" "832 2104 -208"
-}
-{
-"classname" "light"
-"origin" "832 2048 -368"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1120 2464 112"
-}
-{
-"origin" "1120 2080 112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "752 2080 112"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1048 2280 -72"
-}
-{
-"classname" "func_button"
-"angle" "270"
-"target" "t1"
-"model" "*19"
-}
-{
-"classname" "light"
-"origin" "1136 1848 -504"
-"light" "220"
-}
-{
-"origin" "1136 1672 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1008 1672 -504"
-"light" "220"
-}
-{
-"origin" "1008 1848 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1288 1848 -504"
-"light" "220"
-}
-{
-"origin" "1400 1584 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1224 1584 -504"
-"light" "220"
-}
-{
-"origin" "1400 1736 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"origin" "880 1672 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "744 1672 -504"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1312 1648 -392"
-"light" "220"
-}
-{
-"light" "170"
-"origin" "1312 1520 -392"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1200 1760 -392"
-"light" "220"
-}
-{
-"light" "170"
-"origin" "1072 1760 -392"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "944 1760 -392"
-"light" "170"
-}
-{
-"origin" "832 1992 -208"
-"classname" "light"
-"light" "220"
-}
-{
-"origin" "744 1832 -504"
-"classname" "light"
-}
-{
-"light" "170"
-"origin" "832 1760 -392"
-"classname" "light"
-}
-{
-"light" "220"
-"origin" "680 1936 -504"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1312 1392 -352"
-"light" "170"
-}
-{
-"light" "170"
-"origin" "1312 1264 -288"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1312 1136 -232"
-}
-{
-"origin" "1224 1456 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1400 1456 -504"
-"light" "220"
-}
-{
-"origin" "1400 1328 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1224 1328 -504"
-"light" "220"
-}
-{
-"origin" "1224 1200 -504"
-"classname" "light"
-"light" "220"
-}
-{
-"classname" "light"
-"origin" "1400 1200 -504"
-"light" "220"
-}
-{
-"origin" "1312 960 -208"
-"classname" "light"
-}
-{
-"classname" "trigger_teleport"
-"target" "t6"
-"model" "*20"
-}
-{
-"classname" "light"
-"origin" "1312 912 -472"
-}
-{
-"classname" "light"
-"origin" "1312 1080 -368"
-}
-{
-"classname" "light"
-"origin" "1128 1064 -504"
-"light" "170"
-}
-{
-"origin" "1128 856 -504"
-"classname" "light"
-"light" "170"
-}
-{
-"classname" "light"
-"origin" "1496 856 -504"
-"light" "170"
-}
-{
-"origin" "1496 1064 -504"
-"classname" "light"
-"light" "170"
-}
-{
-"classname" "light"
-"origin" "1312 776 -504"
-"light" "170"
-}
-{
-"spawnflags" "2"
-"angle" "90"
-"classname" "func_door_secret"
-"model" "*21"
-}
-{
-"origin" "1072 1024 -168"
-"classname" "light"
-}
-{
-"spawnflags" "1"
-"height" "400"
-"angle" "-1"
-"sounds" "1"
-"classname" "func_plat"
-"model" "*22"
-}
-{
-"targetname" "t8"
-"spawnflags" "2"
-"angle" "90"
-"classname" "func_door_secret"
-"model" "*23"
-}
-{
-"target" "t8"
-"classname" "trigger_multiple"
-"model" "*24"
-}
-{
-"light" "220"
-"origin" "792 888 -248"
-"classname" "light"
-}
-{
-"light" "180"
-"classname" "light"
-"origin" "944 608 -248"
-}
-{
-"light" "150"
-"origin" "792 512 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "792 512 -56"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "624 928 -240"
-"light" "220"
-}
-{
-"light" "220"
-"origin" "504 1200 -248"
-"classname" "light"
-}
-{
-"origin" "936 800 -248"
-"classname" "light"
-"light" "180"
-}
-{
-"light" "180"
-"classname" "light"
-"origin" "960 984 -208"
-}
-{
-"classname" "light"
-"origin" "792 512 128"
-"light" "150"
-}
-{
-"spawnflags" "2"
-"origin" "944 1008 -272"
-"classname" "item_health"
-}
-{
-"spawnflags" "1792"
-"origin" "144 2352 16"
-"classname" "weapon_rocketlauncher"
-}
-{
-"spawnflags" "1792"
-"origin" "1216 1040 -432"
-"classname" "weapon_grenadelauncher"
-}
-{
-"spawnflags" "1793"
-"origin" "1392 1024 -432"
-"classname" "item_rockets"
-}
-{
-"targetname" "t6"
-"origin" "-32 1800 -56"
-"classname" "info_teleport_destination"
-}
-{
-"spawnflags" "1792"
-"origin" "832 2448 -368"
-"classname" "weapon_supernailgun"
-}
-{
-"spawnflags" "1792"
-"origin" "128 1216 -208"
-"classname" "weapon_supershotgun"
-}
-{
-"origin" "296 2136 -192"
-"classname" "item_shells"
-}
-{
-"spawnflags" "1"
-"origin" "1424 904 -432"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "1376 808 -432"
-}
-{
-"origin" "1176 936 -432"
-"classname" "item_health"
-}
-{
-"spawnflags" "2048"
-"target" "t9"
-"wait" "-1"
-"angle" "0"
-"classname" "func_button"
-"model" "*25"
-}
-{
-"spawnflags" "2048"
-"target" "t9"
-"wait" "-1"
-"angle" "90"
-"classname" "func_button"
-"model" "*26"
-}
-{
-"spawnflags" "2048"
-"target" "t9"
-"wait" "-1"
-"angle" "270"
-"classname" "func_button"
-"model" "*27"
-}
-{
-"target" "t10"
-"targetname" "t9"
-"count" "3"
-"classname" "trigger_counter"
-"model" "*28"
-}
-{
-"message" "You must press the three buttons..."
-"spawnflags" "2048"
-"sounds" "2"
-"wait" "-1"
-"targetname" "t10"
-"angle" "180"
-"classname" "func_door"
-"model" "*29"
-}
-{
-"light" "150"
-"origin" "832 1928 -384"
-"classname" "light"
-}
-{
-"style" "33"
-"sounds" "3"
-"target" "t11"
-"classname" "trigger_once"
-"model" "*30"
-}
-{
-"style" "34"
-"sounds" "3"
-"target" "t12"
-"classname" "trigger_once"
-"model" "*31"
-}
-{
-"style" "35"
-"sounds" "3"
-"target" "t13"
-"classname" "trigger_once"
-"model" "*32"
-}
-{
-"style" "36"
-"sounds" "3"
-"target" "t14"
-"classname" "trigger_once"
-"model" "*33"
-}
-{
-"sounds" "1"
-"wait" "-1"
-"targetname" "t11"
-"spawnflags" "1"
-"angle" "-2"
-"classname" "func_door"
-"model" "*34"
-}
-{
-"targetname" "t12"
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "1"
-"wait" "-1"
-"sounds" "1"
-"model" "*35"
-}
-{
-"targetname" "t13"
-"sounds" "1"
-"wait" "-1"
-"spawnflags" "1"
-"angle" "-2"
-"classname" "func_door"
-"model" "*36"
-}
-{
-"targetname" "t14"
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "1"
-"wait" "-1"
-"sounds" "1"
-"model" "*37"
-}
-{
-"angle" "90"
-"origin" "1312 880 -248"
-"classname" "info_player_deathmatch"
-}
-{
-"spawnflags" "1"
-"origin" "1376 1024 -272"
-"classname" "item_spikes"
-}
-{
-"origin" "1184 992 -272"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "1376 856 -272"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "1256 1704 -432"
-"classname" "item_health"
-}
-{
-"angle" "90"
-"origin" "480 48 24"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "180"
-"origin" "528 1888 -168"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "0"
-"origin" "-272 2928 -56"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "0"
-"origin" "832 2048 -152"
-"classname" "info_player_deathmatch"
-}
-{
-"speed" "300"
-"message" "This door opens elsewhere..."
-"spawnflags" "2048"
-"targetname" "t15"
-"angle" "270"
-"classname" "func_door"
-"wait" "-1"
-"model" "*38"
-}
-{
-"spawnflags" "2048"
-"target" "t15"
-"classname" "trigger_once"
-"model" "*39"
-}
-{
-"spawnflags" "1792"
-"origin" "480 576 0"
-"classname" "weapon_nailgun"
-}
-{
-"spawnflags" "1793"
-"origin" "464 728 64"
-"classname" "item_spikes"
-}
-{
-"origin" "328 848 -224"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "344 920 -224"
-}
-{
-"spawnflags" "1"
-"origin" "-16 2064 -208"
-"classname" "item_health"
-}
-{
-"spawnflags" "1792"
-"origin" "-480 2240 -160"
-"classname" "item_rockets"
-}
-{
-"spawnflags" "1793"
-"origin" "-96 2456 16"
-"classname" "item_shells"
-}
-{
-"classname" "item_rockets"
-"origin" "-104 2216 16"
-"spawnflags" "1793"
-}
-{
-"classname" "item_artifact_invulnerability"
-"origin" "256 1808 -40"
-"spawnflags" "1792"
-}
-{
-"classname" "monster_army"
-"origin" "0 576 24"
-"angle" "0"
-"spawnflags" "256"
-}
-{
-"classname" "monster_army"
-"origin" "8 1520 -200"
-"angle" "270"
-}
-{
-"classname" "monster_dog"
-"origin" "88 1520 -200"
-"angle" "270"
-}
-{
-"classname" "monster_army"
-"origin" "224 1552 -200"
-"angle" "270"
-"spawnflags" "768"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "-8 936 -200"
-"classname" "monster_army"
-}
-{
-"classname" "monster_army"
-"origin" "648 736 104"
-"spawnflags" "768"
-"angle" "180"
-}
-{
-"classname" "item_artifact_envirosuit"
-"origin" "712 2040 -408"
-"angle" "90"
-}
-{
-"classname" "light"
-"origin" "712 2040 -360"
-"light" "100"
-}
-{
-"classname" "item_rockets"
-"origin" "1328 2536 -528"
-"spawnflags" "1793"
-}
-{
-"classname" "item_health"
-"origin" "916 2416 -136"
-"spawnflags" "2"
-}
-{
-"spawnflags" "1"
-"classname" "monster_army"
-"origin" "1312 936 -248"
-"angle" "90"
-}
-{
-"classname" "monster_dog"
-"origin" "1336 1784 -408"
-"angle" "180"
-"spawnflags" "257"
-}
-{
-"spawnflags" "257"
-"angle" "90"
-"origin" "1392 928 -248"
-"classname" "monster_army"
-}
-{
-"classname" "monster_army"
-"origin" "1384 1008 -248"
-"angle" "90"
-"spawnflags" "768"
-}
-{
-"spawnflags" "768"
-"angle" "90"
-"origin" "1240 1008 -248"
-"classname" "monster_army"
-}
-{
-"classname" "monster_army"
-"origin" "1256 1760 -408"
-"angle" "180"
-"spawnflags" "257"
-}
-{
-"classname" "monster_army"
-"origin" "824 1784 -408"
-"spawnflags" "257"
-"angle" "90"
-}
-{
-"classname" "monster_dog"
-"origin" "1128 1760 -408"
-"angle" "180"
-"spawnflags" "769"
-}
-{
-"classname" "path_corner"
-"origin" "880 2048 -168"
-"target" "t16"
-"targetname" "t17"
-}
-{
-"origin" "1232 2048 -232"
-"classname" "path_corner"
-"targetname" "t16"
-"target" "t17"
-}
-{
-"classname" "monster_army"
-"origin" "1232 2088 -216"
-"target" "t16"
-}
-{
-"classname" "monster_army"
-"origin" "1232 2448 -280"
-"angle" "270"
-"spawnflags" "256"
-}
-{
-"classname" "monster_army"
-"origin" "832 2464 -344"
-"angle" "0"
-"spawnflags" "256"
-}
-{
-"classname" "monster_army"
-"origin" "832 2072 -408"
-"angle" "90"
-}
-{
-"classname" "monster_dog"
-"origin" "840 1960 -408"
-"angle" "90"
-"spawnflags" "768"
-}
-{
-"classname" "trigger_multiple"
-"target" "t18"
-"health" "1"
-"model" "*40"
-}
-{
-"classname" "func_door_secret"
-"angle" "90"
-"spawnflags" "2"
-"targetname" "t18"
-"model" "*41"
-}
-{
-"classname" "weapon_supershotgun"
-"origin" "-360 2912 -80"
-}
-{
-"classname" "trigger_multiple"
-"target" "t18"
-"model" "*42"
-}
-{
-"classname" "light"
-"origin" "-352 2912 -24"
-"light" "120"
-}
-{
-"classname" "light"
-"origin" "160 3024 0"
-"light" "120"
-}
-{
-"classname" "item_shells"
-"origin" "528 720 80"
-}
-{
-"classname" "monster_army"
-"origin" "416 1912 -168"
-"angle" "180"
-"spawnflags" "768"
-}
-{
-"classname" "monster_dog"
-"origin" "432 2120 -168"
-"angle" "180"
-"spawnflags" "256"
-}
-{
-"classname" "path_corner"
-"origin" "248 1992 -200"
-"targetname" "t19"
-"target" "t20"
-}
-{
-"origin" "-200 1992 -200"
-"classname" "path_corner"
-"targetname" "t20"
-"target" "t21"
-}
-{
-"classname" "path_corner"
-"origin" "-136 1912 -200"
-"targetname" "t21"
-"target" "t22"
-}
-{
-"origin" "248 1912 -200"
-"classname" "path_corner"
-"target" "t19"
-"targetname" "t22"
-}
-{
-"classname" "monster_army"
-"origin" "80 2024 -184"
-"target" "t20"
-}
-{
-"classname" "monster_army"
-"origin" "-16 1888 -184"
-"spawnflags" "256"
-"target" "t22"
-}
-{
-"classname" "monster_dog"
-"origin" "-248 2144 -136"
-"spawnflags" "768"
-"angle" "315"
-}
-{
-"classname" "path_corner"
-"origin" "-560 2352 40"
-"targetname" "t23"
-"target" "t24"
-}
-{
-"origin" "-104 2352 40"
-"classname" "path_corner"
-"target" "t23"
-"targetname" "t24"
-}
-{
-"classname" "monster_army"
-"origin" "-432 2352 56"
-"spawnflags" "768"
-"target" "t23"
-}
-{
-"angle" "0"
-"classname" "monster_dog"
-"origin" "-544 2584 56"
-"spawnflags" "256"
-}
-{
-"classname" "monster_army"
-"origin" "-344 2656 -104"
-"angle" "270"
-}
-{
-"classname" "monster_dog"
-"origin" "-72 2896 -56"
-"spawnflags" "256"
-"angle" "225"
-}
-{
-"classname" "monster_army"
-"origin" "432 2920 -56"
-"target" "t25"
-}
-{
-"classname" "monster_army"
-"origin" "424 2832 -56"
-"spawnflags" "256"
-"angle" "180"
-}
-{
-"classname" "path_corner"
-"origin" "368 2936 -72"
-"targetname" "t25"
-"target" "t26"
-}
-{
-"origin" "368 2696 -72"
-"classname" "path_corner"
-"targetname" "t26"
-"target" "t27"
-}
-{
-"classname" "path_corner"
-"origin" "480 2696 -72"
-"targetname" "t27"
-"target" "t28"
-}
-{
-"origin" "480 2936 -72"
-"classname" "path_corner"
-"target" "t25"
-"targetname" "t28"
-}
-{
-"classname" "monster_army"
-"origin" "424 2672 -56"
-"target" "t27"
-}
-{
-"classname" "monster_army"
-"origin" "424 2880 -56"
-"angle" "180"
-"spawnflags" "768"
-}
-{
-"classname" "monster_army"
-"origin" "424 2760 -56"
-"spawnflags" "768"
-"angle" "180"
-}
-{
-"classname" "path_corner"
-"origin" "832 2712 -88"
-"targetname" "t29"
-"target" "t30"
-}
-{
-"origin" "832 2416 -104"
-"classname" "path_corner"
-"target" "t29"
-"targetname" "t30"
-}
-{
-"classname" "monster_army"
-"origin" "848 2584 -72"
-"spawnflags" "257"
-"target" "t29"
-}
-{
-"classname" "monster_army"
-"origin" "824 2008 -152"
-"angle" "90"
-"spawnflags" "768"
-}
-{
-"classname" "item_health"
-"origin" "-376 1704 -224"
-"spawnflags" "1"
-}
-{
-"angle" "180"
-"spawnflags" "768"
-"origin" "248 2352 40"
-"classname" "monster_army"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "-72 2464 40"
-"classname" "monster_army"
-}
-{
-"spawnflags" "768"
-"angle" "225"
-"origin" "904 1024 -248"
-"classname" "monster_army"
-}
-{
-"light" "100"
-"style" "10"
-"classname" "light"
-"origin" "688 0 80"
-}
-{
-"message" "Shoot this secret door..."
-"spawnflags" "1"
-"angle" "0"
-"classname" "func_door_secret"
-"model" "*43"
-}
-{
-"origin" "672 -40 48"
-"classname" "item_shells"
-}
-{
-"classname" "trigger_secret"
-"model" "*44"
-}
-{
-"classname" "trigger_secret"
-"model" "*45"
-}
-{
-"classname" "trigger_secret"
-"model" "*46"
-}
-{
-"classname" "trigger_secret"
-"model" "*47"
-}
-{
-"classname" "trigger_secret"
-"model" "*48"
-}
-{
-"classname" "trigger_secret"
-"model" "*49"
-}
-{
-"light" "100"
-"origin" "0 632 -88"
-"classname" "light"
-}
-{
-"classname" "item_health"
-"origin" "600 2200 -128"
-"spawnflags" "1"
-}
-{
-"light" "220"
-"classname" "light"
-"origin" "832 1880 -504"
-}
-{
-"origin" "72 2056 -208"
-"classname" "misc_explobox"
-}
-{
-"light" "200"
-"origin" "-128 584 72"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-128 568 -136"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "-56 632 -168"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-56 864 -136"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "40 1672 -40"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "216 1672 -40"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "128 1080 -152"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "128 1096 72"
-"classname" "light"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "-352 1656 72"
-}
-{
-"origin" "608 1640 72"
-"classname" "light"
-"light" "250"
-}
-{
-"origin" "-48 1144 -320"
-"classname" "light"
-"light" "170"
-}
-{
-"light" "170"
-"classname" "light"
-"origin" "-48 1256 -320"
-}
-{
-"origin" "320 1256 -320"
-"classname" "light"
-"light" "170"
-}
-{
-"light" "170"
-"classname" "light"
-"origin" "312 1128 -320"
-}
-{
-"origin" "136 1128 -320"
-"classname" "light"
-"light" "170"
-}
-{
-"light" "170"
-"classname" "light"
-"origin" "136 1272 -320"
-}
-{
-"spawnflags" "3072"
-"wait" "5"
-"sounds" "2"
-"message" "You can jump across..."
-"classname" "trigger_multiple"
-"targetname" "t32"
-"model" "*50"
-}
-{
-"spawnflags" "3072"
-"wait" "5"
-"message" "You can jump up here..."
-"sounds" "2"
-"classname" "trigger_multiple"
-"targetname" "t31"
-"model" "*51"
-}
-{
-"light" "150"
-"origin" "1008 2128 -408"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1312 544 -184"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "1208 456 -184"
-}
-{
-"origin" "1416 456 -184"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "170"
-"origin" "1312 728 -56"
-"classname" "light"
-}
-{
-"map" "e1m2"
-"classname" "trigger_changelevel"
-"model" "*52"
-}
-{
-"classname" "item_health"
-"origin" "1224 2464 -304"
-"spawnflags" "1"
-}
-{
-"classname" "light"
-"origin" "688 1680 -160"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "-392 1688 -160"
-"classname" "light"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "288 1536 -200"
-"classname" "monster_army"
-}
-{
-"spawnflags" "768"
-"origin" "968 2432 -112"
-"classname" "monster_army"
-}
-{
-"wait" "5"
-"message" "Walk into the slipgate to exit."
-"classname" "trigger_multiple"
-"sounds" "2"
-"angle" "270"
-"model" "*53"
-}
-{
-"classname" "trigger_once"
-"killtarget" "t31"
-"target" "t31"
-"spawnflags" "3072"
-"model" "*54"
-}
-{
-"classname" "trigger_once"
-"spawnflags" "3072"
-"target" "t32"
-"killtarget" "t32"
-"model" "*55"
-}
-{
-"classname" "item_armor2"
-"origin" "1312 1048 -432"
-}
-{
-"classname" "ambient_comp_hum"
-"origin" "250 194 72"
-}
-{
-"origin" "714 194 72"
-"classname" "ambient_comp_hum"
-}
-{
-"classname" "ambient_comp_hum"
-"origin" "626 2058 -104"
-}
-{
-"origin" "466 2226 -104"
-"classname" "ambient_comp_hum"
-}
-{
-"classname" "info_intermission"
-"origin" "-112 704 56"
-"mangle" "20 45 0"
-}
-{
-"classname" "info_intermission"
-"origin" "-208 2736 192"
-"mangle" "20 225 0"
-}
-{
-"classname" "info_intermission"
-"origin" "240 2664 104"
-"mangle" "20 120 0"
-}
-{
-"classname" "info_intermission"
-"origin" "1376 1936 64"
-"mangle" "20 135 0"
-}
-{
-"angle" "90"
-"origin" "528 -296 72"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "432 -296 72"
-"angle" "90"
-}
-{
-"angle" "90"
-"origin" "480 -240 72"
-"classname" "info_player_coop"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*56"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*57"
-}
-{
-"classname" "ambient_drone"
-"origin" "1314 450 -200"
-}
diff --git a/Misc/pak/maps/e1m2.diff b/Misc/pak/maps/e1m2.diff
new file mode 100644
index 000000000..408089893
--- /dev/null
+++ b/Misc/pak/maps/e1m2.diff
@@ -0,0 +1,28 @@
+--- e1m2.ent
++++ e1m2@0caa.ent
+@@ -1567,23 +1567,23 @@
+ {
+ "light" "200"
+ "origin" "-612 -500 548"
+ "classname" "light"
+ }
+ {
+ "classname" "func_door"
+-"angle" "90"
++"angle" "91" // svdijk -- changed to prevent z-fighting (was "90")
+ "targetname" "t110"
+ "wait" "-1"
+ "model" "*33"
+ }
+ {
+ "sounds" "3"
+ "classname" "func_door"
+-"angle" "270"
++"angle" "269" // svdijk -- changed to prevent z-fighting (was "270")
+ "wait" "-1"
+ "model" "*34"
+ }
+ {
+ "classname" "trigger_once"
+ "target" "t110"
+ "model" "*35"
diff --git a/Misc/pak/maps/e1m2.ent.orig b/Misc/pak/maps/e1m2.ent.orig
deleted file mode 100644
index 942ae608b..000000000
--- a/Misc/pak/maps/e1m2.ent.orig
+++ /dev/null
@@ -1,3019 +0,0 @@
-{
-"message" "Castle of the Damned"
-"wad" "gfx/wizard.wad"
-"classname" "worldspawn"
-"worldtype" "0"
-"sounds" "8"
-}
-{
-"angle" "270"
-"origin" "1496 1664 296"
-"classname" "info_player_start"
-}
-{
-"origin" "1432 672 336"
-"classname" "light"
-"light" "250"
-}
-{
-"light" "200"
-"origin" "1496 888 272"
-"classname" "light"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "932 640 340"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1104 812 340"
-}
-{
-"classname" "light"
-"origin" "1104 640 544"
-"light" "300"
-}
-{
-"light" "175"
-"origin" "1216 536 353"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1816 328 448"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1632 472 208"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1792 -392 240"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1452 -124 508"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1196 -124 508"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1044 -124 508"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "756 -124 508"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "744 336 145"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1176 -912 672"
-"classname" "light"
-}
-{
-"origin" "1328 -544 552"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1528 -912 640"
-"light" "200"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "880 -648 672"
-}
-{
-"origin" "240 -264 392"
-"classname" "light"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-352 -504 464"
-"light" "200"
-}
-{
-"origin" "-448 -608 804"
-"classname" "light"
-"light" "450"
-}
-{
-"light" "250"
-"origin" "776 -912 472"
-"classname" "light"
-}
-{
-"light" "300"
-"origin" "1630 -806 428"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "150"
-"origin" "1528 -912 464"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1180 -484 560"
-}
-{
-"classname" "light"
-"origin" "1184 -612 560"
-}
-{
-"classname" "light"
-"origin" "1016 -368 472"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1016 -464 472"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1020 -560 472"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1208 -776 472"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1288 -776 472"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1360 -776 472"
-"light" "100"
-}
-{
-"light" "200"
-"origin" "1792 120 376"
-"classname" "light"
-}
-{
-"origin" "1538 182 356"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "200"
-"origin" "1640 80 360"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1928 80 360"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1792 296 208"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1800 40 160"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1776 -392 160"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1304 -392 152"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1632 112 136"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1432 312 136"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1136 -656 160"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1136 -416 160"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1448 -552 160"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1920 440 136"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "968 88 177"
-"classname" "light"
-}
-{
-"light" "300"
-"origin" "1088 312 129"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1376 168 129"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "112 -384 392"
-"classname" "light"
-}
-{
-"origin" "300 -1004 508"
-"classname" "light"
-}
-{
-"origin" "296 -812 505"
-"classname" "light"
-}
-{
-"origin" "300 -1204 505"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "470 -1006 468"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "250"
-"origin" "984 -1216 496"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "888 -1128 552"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "800 -1216 592"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "664 -1216 592"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "584 -1136 592"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "584 -968 592"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "584 -744 592"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "528 -1144 464"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "528 -856 464"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "1496 1544 440"
-}
-{
-"origin" "1384 1392 440"
-"classname" "light"
-"light" "250"
-}
-{
-"origin" "1496 1104 520"
-"classname" "light"
-}
-{
-"origin" "1608 1400 440"
-"classname" "light"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "1240 1712 360"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1744 1696 360"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1384 1136 440"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1608 1144 440"
-"light" "250"
-}
-{
-"classname" "path_corner"
-"origin" "1168 736 296"
-"targetname" "t5"
-"target" "t6"
-}
-{
-"classname" "path_corner"
-"origin" "992 744 296"
-"targetname" "t6"
-"target" "t7"
-}
-{
-"classname" "path_corner"
-"origin" "1000 544 296"
-"targetname" "t7"
-"target" "t34"
-}
-{
-"classname" "item_health"
-"origin" "960 704 288"
-}
-{
-"classname" "item_shells"
-"origin" "952 512 288"
-}
-{
-"classname" "path_corner"
-"origin" "1344 -128 304"
-"targetname" "t9"
-"target" "t8"
-}
-{
-"classname" "path_corner"
-"origin" "898 -128 304"
-"targetname" "t8"
-"target" "t9"
-}
-{
-"spawnflags" "1"
-"classname" "monster_ogre"
-"origin" "1018 -126 320"
-"angle" "0"
-"target" "t8"
-}
-{
-"classname" "item_health"
-"origin" "1344 -224 296"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "1400 -224 296"
-"spawnflags" "1"
-}
-{
-"origin" "1528 192 296"
-"classname" "item_shells"
-}
-{
-"classname" "path_corner"
-"origin" "1496 1040 184"
-"targetname" "t22"
-"target" "t23"
-}
-{
-"classname" "path_corner"
-"origin" "1496 840 248"
-"targetname" "t23"
-"target" "t33"
-}
-{
-"spawnflags" "1"
-"classname" "item_shells"
-"origin" "1056 -648 288"
-}
-{
-"classname" "item_health"
-"origin" "1184 -736 288"
-}
-{
-"spawnflags" "257"
-"classname" "monster_army"
-"origin" "1646 -698 360"
-"angle" "180"
-"targetname" "t89"
-}
-{
-"classname" "path_corner"
-"origin" "1400 640 272"
-"targetname" "t30"
-"target" "t79"
-}
-{
-"classname" "path_corner"
-"origin" "1496 752 232"
-"targetname" "t33"
-"target" "t77"
-}
-{
-"classname" "path_corner"
-"origin" "1192 560 296"
-"targetname" "t34"
-"target" "t80"
-}
-{
-"classname" "item_shells"
-"origin" "1616 1280 176"
-}
-{
-"classname" "item_health"
-"origin" "1056 -840 416"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "1104 -840 416"
-"spawnflags" "1"
-}
-{
-"spawnflags" "1"
-"classname" "monster_army"
-"origin" "262 -458 320"
-"angle" "0"
-"target" "t96"
-}
-{
-"spawnflags" "1024"
-"classname" "item_health"
-"origin" "136 -296 296"
-}
-{
-"classname" "path_corner"
-"origin" "-536 -704 472"
-"targetname" "t42"
-"target" "t41"
-}
-{
-"classname" "path_corner"
-"origin" "-576 -416 472"
-"targetname" "t41"
-"target" "t42"
-}
-{
-"classname" "monster_knight"
-"origin" "-578 -654 480"
-"target" "t41"
-"spawnflags" "1"
-}
-{
-"classname" "item_shells"
-"origin" "-368 -752 456"
-}
-{
-"classname" "item_health"
-"origin" "-16 -520 360"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "-16 -576 360"
-"spawnflags" "1"
-}
-{
-"classname" "light"
-"origin" "1848 -568 320"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1760 -560 408"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1624 -560 352"
-"light" "150"
-}
-{
-"targetname" "t43"
-"angle" "270"
-"origin" "800 368 312"
-"classname" "info_teleport_destination"
-}
-{
-"origin" "752 168 296"
-"classname" "item_health"
-}
-{
-"target" "t43"
-"classname" "trigger_teleport"
-"model" "*1"
-}
-{
-"origin" "1712 -568 256"
-"classname" "item_health"
-}
-{
-"classname" "monster_ogre"
-"origin" "1494 1134 208"
-"angle" "270"
-"target" "t22"
-}
-{
-"light" "300"
-"origin" "1856 1288 384"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1136 1288 384"
-}
-{
-"light" "200"
-"origin" "1920 328 380"
-"classname" "light"
-}
-{
-"target" "t122"
-"spawnflags" "2048"
-"sounds" "1"
-"classname" "item_key1"
-"origin" "880 -300 464"
-}
-{
-"light" "300"
-"origin" "648 -384 430"
-"classname" "light_flame_small_yellow"
-}
-{
-"light" "250"
-"classname" "light_flame_small_yellow"
-"origin" "1104 -224 406"
-}
-{
-"light" "250"
-"origin" "1456 -128 406"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light"
-"origin" "988 532 353"
-"light" "175"
-}
-{
-"light" "125"
-"origin" "1100 648 328"
-"classname" "light"
-}
-{
-"origin" "1616 936 310"
-"classname" "light_flame_small_yellow"
-"light" "300"
-}
-{
-"light" "300"
-"classname" "light_flame_small_yellow"
-"origin" "1360 936 310"
-}
-{
-"origin" "1792 504 390"
-"classname" "light_flame_small_yellow"
-"light" "300"
-}
-{
-"origin" "1972 -252 332"
-"classname" "info_null"
-"targetname" "t47"
-}
-{
-"light" "800"
-"origin" "1992 -252 336"
-"classname" "light"
-"target" "t47"
-}
-{
-"classname" "info_null"
-"origin" "1948 -292 332"
-"targetname" "t48"
-}
-{
-"light" "800"
-"classname" "light"
-"origin" "1948 -312 336"
-"target" "t48"
-}
-{
-"origin" "880 -328 562"
-"classname" "light_flame_small_yellow"
-"light" "300"
-}
-{
-"classname" "light"
-"origin" "1056 -1288 504"
-}
-{
-"origin" "1184 -1288 504"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1312 -1288 504"
-}
-{
-"origin" "1440 -1288 504"
-"classname" "light"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"angle" "-2"
-"wait" "-1"
-"targetname" "t50"
-"model" "*2"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"wait" "-1"
-"angle" "-2"
-"targetname" "t50"
-"model" "*3"
-}
-{
-"classname" "trigger_once"
-"target" "t50"
-"model" "*4"
-}
-{
-"classname" "light"
-"origin" "1368 -1016 504"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1120 -1024 504"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1248 -1184 464"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "776 -480 480"
-"light" "225"
-}
-{
-"classname" "light"
-"origin" "1904 -144 168"
-"light" "200"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1706 -206 316"
-"light" "300"
-}
-{
-"light" "300"
-"origin" "2134 -34 316"
-"classname" "light_torch_small_walltorch"
-}
-{
-"origin" "1152 -296 422"
-"classname" "light_flame_small_yellow"
-"light" "250"
-}
-{
-"light" "250"
-"classname" "light_flame_small_yellow"
-"origin" "1152 -760 422"
-}
-{
-"origin" "1528 -556 478"
-"classname" "light_flame_small_yellow"
-"light" "250"
-}
-{
-"targetname" "t52"
-"origin" "1532 -552 328"
-"classname" "info_null"
-}
-{
-"origin" "1340 -544 384"
-"classname" "item_armor2"
-}
-{
-"sounds" "1"
-"targetname" "t53"
-"lip" "64"
-"wait" "-1"
-"angle" "-1"
-"classname" "func_door"
-"model" "*5"
-}
-{
-"sounds" "1"
-"targetname" "t53"
-"classname" "func_door"
-"angle" "-1"
-"wait" "-1"
-"lip" "64"
-"model" "*6"
-}
-{
-"targetname" "t53"
-"target" "t54"
-"classname" "trigger_teleport"
-"spawnflags" "2"
-"model" "*7"
-}
-{
-"targetname" "t54"
-"angle" "180"
-"origin" "1408 -688 449"
-"classname" "info_teleport_destination"
-}
-{
-"targetname" "t53"
-"target" "t57"
-"classname" "trigger_teleport"
-"spawnflags" "2"
-"model" "*8"
-}
-{
-"targetname" "t57"
-"angle" "180"
-"origin" "1408 -400 361"
-"classname" "info_teleport_destination"
-}
-{
-"spawnflags" "768"
-"targetname" "t53"
-"angle" "180"
-"origin" "1912 -856 217"
-"classname" "monster_wizard"
-}
-{
-"spawnflags" "768"
-"targetname" "t53"
-"classname" "monster_wizard"
-"origin" "1912 -936 217"
-"angle" "180"
-}
-{
-"targetname" "t50"
-"angle" "90"
-"origin" "1320 -1112 441"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "256"
-"targetname" "t50"
-"angle" "0"
-"origin" "1056 -1144 441"
-"classname" "monster_knight"
-}
-{
-"sounds" "1"
-"targetname" "t61"
-"wait" "-1"
-"angle" "-2"
-"classname" "func_door"
-"model" "*9"
-}
-{
-"sounds" "3"
-"lip" "64"
-"spawnflags" "1"
-"targetname" "t58"
-"angle" "270"
-"wait" "-1"
-"classname" "func_door"
-"model" "*10"
-}
-{
-"sounds" "1"
-"wait" "-1"
-"angle" "270"
-"target" "t58"
-"classname" "func_button"
-"model" "*11"
-}
-{
-"target" "t61"
-"classname" "trigger_once"
-"model" "*12"
-}
-{
-"light" "225"
-"origin" "984 -480 480"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "880 -368 176"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "880 -592 240"
-"light" "175"
-}
-{
-"light" "200"
-"origin" "880 -488 184"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "880 -304 472"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-96 308 864"
-"light" "850"
-}
-{
-"origin" "-32 -440 624"
-"classname" "light"
-}
-{
-"sounds" "1"
-"targetname" "t73"
-"wait" "-1"
-"lip" "196"
-"angle" "-1"
-"classname" "func_door"
-"model" "*13"
-}
-{
-"light" "300"
-"origin" "104 144 688"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-264 144 688"
-"light" "300"
-}
-{
-"sounds" "1"
-"targetname" "t73"
-"wait" "-1"
-"classname" "func_door"
-"angle" "-1"
-"lip" "196"
-"model" "*14"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "-24 -232 414"
-"light" "250"
-}
-{
-"lip" "-2"
-"sounds" "3"
-"speed" "350"
-"targetname" "t73"
-"angle" "180"
-"wait" "-1"
-"classname" "func_door"
-"model" "*15"
-}
-{
-"target" "t63"
-"targetname" "t62"
-"origin" "-12 312 264"
-"classname" "path_corner"
-}
-{
-"target" "t64"
-"targetname" "t63"
-"origin" "-12 312 356"
-"classname" "path_corner"
-}
-{
-"wait" "-1"
-"target" "t66"
-"targetname" "t64"
-"classname" "path_corner"
-"origin" "-13 440 355"
-}
-{
-"sounds" "1"
-"targetname" "t71"
-"wait" "-1"
-"target" "t65"
-"angle" "-2"
-"classname" "func_button"
-"model" "*16"
-}
-{
-"target" "t64"
-"targetname" "t66"
-"origin" "-13 440 355"
-"classname" "path_corner"
-}
-{
-"light" "200"
-"origin" "-96 440 376"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "8 456 376"
-"classname" "light"
-}
-{
-"targetname" "t70"
-"target" "t67"
-"classname" "path_corner"
-"origin" "-220 312 264"
-}
-{
-"target" "t68"
-"targetname" "t67"
-"classname" "path_corner"
-"origin" "-220 312 356"
-}
-{
-"wait" "-1"
-"target" "t69"
-"targetname" "t68"
-"origin" "-221 440 355"
-"classname" "path_corner"
-}
-{
-"target" "t68"
-"targetname" "t69"
-"classname" "path_corner"
-"origin" "-221 440 355"
-}
-{
-"classname" "light"
-"origin" "-200 456 376"
-"light" "150"
-}
-{
-"targetname" "t65"
-"target" "t62"
-"classname" "func_train"
-"speed" "50"
-"sounds" "1"
-"model" "*17"
-}
-{
-"light" "250"
-"origin" "-96 632 406"
-"classname" "light_flame_small_yellow"
-}
-{
-"targetname" "t72"
-"origin" "-96 288 304"
-"classname" "info_null"
-}
-{
-"light" "450"
-"target" "t72"
-"origin" "-96 288 368"
-"classname" "light"
-}
-{
-"target" "t70"
-"targetname" "t65"
-"speed" "50"
-"classname" "func_train"
-"sounds" "1"
-"model" "*18"
-}
-{
-"lip" "-2"
-"sounds" "0"
-"speed" "350"
-"classname" "func_door"
-"wait" "-1"
-"angle" "0"
-"model" "*19"
-}
-{
-"targetname" "t65"
-"delay" "4.7"
-"target" "t73"
-"classname" "trigger_once"
-"model" "*20"
-}
-{
-"targetname" "t73"
-"angle" "270"
-"origin" "-96 552 320"
-"classname" "monster_demon1"
-"spawnflags" "1024"
-}
-{
-"targetname" "t74"
-"angle" "90"
-"origin" "132 -192 476"
-"classname" "info_teleport_destination"
-}
-{
-"targetname" "t75"
-"classname" "info_teleport_destination"
-"origin" "-328 -196 476"
-"angle" "90"
-}
-{
-"target" "t75"
-"classname" "trigger_teleport"
-"spawnflags" "1"
-"model" "*21"
-}
-{
-"target" "t74"
-"classname" "trigger_teleport"
-"spawnflags" "1"
-"model" "*22"
-}
-{
-"light" "200"
-"origin" "-418 306 356"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "260 308 356"
-"light" "200"
-}
-{
-"sounds" "0"
-"targetname" "t73"
-"wait" "-1"
-"angle" "180"
-"classname" "func_door"
-"model" "*23"
-}
-{
-"sounds" "0"
-"targetname" "t73"
-"wait" "-1"
-"angle" "0"
-"classname" "func_door"
-"model" "*24"
-}
-{
-"sounds" "0"
-"wait" "-1"
-"angle" "0"
-"targetname" "t73"
-"classname" "func_door"
-"model" "*25"
-}
-{
-"sounds" "0"
-"targetname" "t73"
-"angle" "180"
-"wait" "-1"
-"classname" "func_door"
-"model" "*26"
-}
-{
-"sounds" "3"
-"wait" "-1"
-"angle" "-2"
-"targetname" "t73"
-"classname" "func_door"
-"model" "*27"
-}
-{
-"classname" "light"
-"origin" "-96 24 360"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "-96 -40 360"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-160 -568 624"
-}
-{
-"origin" "-160 -440 624"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-32 -568 624"
-}
-{
-"classname" "light"
-"origin" "-96 -88 484"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "-440 -408 804"
-"light" "450"
-}
-{
-"classname" "light"
-"origin" "600 -128 352"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "576 -608 504"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "384 -504 392"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1264 240 295"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "944 240 295"
-"classname" "light"
-}
-{
-"classname" "path_corner"
-"origin" "1480 704 264"
-"targetname" "t77"
-"target" "t78"
-}
-{
-"classname" "path_corner"
-"origin" "1448 656 264"
-"targetname" "t78"
-"target" "t30"
-}
-{
-"classname" "path_corner"
-"origin" "1264 640 304"
-"targetname" "t80"
-"target" "t5"
-}
-{
-"classname" "path_corner"
-"origin" "1328 640 304"
-"targetname" "t79"
-"target" "t80"
-}
-{
-"light" "200"
-"origin" "1488 -392 216"
-"classname" "light"
-}
-{
-"classname" "path_corner"
-"origin" "816 80 304"
-"targetname" "t83"
-"target" "t82"
-"spawnflags" "256"
-}
-{
-"origin" "816 312 304"
-"classname" "path_corner"
-"targetname" "t82"
-"target" "t83"
-"spawnflags" "256"
-}
-{
-"classname" "monster_army"
-"origin" "806 206 320"
-"angle" "90"
-"target" "t82"
-"spawnflags" "256"
-}
-{
-"classname" "trigger_once"
-"target" "t84"
-"model" "*28"
-}
-{
-"classname" "monster_ogre"
-"origin" "1790 -146 312"
-"angle" "90"
-"targetname" "t84"
-}
-{
-"classname" "path_corner"
-"origin" "1088 -672 296"
-"target" "t85"
-"targetname" "t88"
-}
-{
-"origin" "1088 -376 296"
-"classname" "path_corner"
-"targetname" "t85"
-"target" "t86"
-}
-{
-"classname" "path_corner"
-"origin" "1088 -376 296"
-"targetname" "t87"
-"target" "t88"
-}
-{
-"origin" "1448 -376 296"
-"classname" "path_corner"
-"targetname" "t86"
-"target" "t87"
-}
-{
-"spawnflags" "1"
-"classname" "monster_ogre"
-"origin" "1086 -498 312"
-"angle" "270"
-"target" "t88"
-}
-{
-"spawnflags" "256"
-"classname" "trigger_once"
-"target" "t89"
-"model" "*29"
-}
-{
-"classname" "item_health"
-"origin" "352 -752 408"
-"spawnflags" "1025"
-}
-{
-"spawnflags" "1025"
-"origin" "352 -792 408"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "352 -832 408"
-"spawnflags" "1"
-}
-{
-"classname" "path_corner"
-"origin" "408 -776 416"
-"targetname" "t94"
-"target" "t95"
-}
-{
-"origin" "400 -1088 416"
-"classname" "path_corner"
-"targetname" "t95"
-"target" "t94"
-}
-{
-"classname" "path_corner"
-"origin" "584 -1096 416"
-"targetname" "t92"
-"target" "t93"
-}
-{
-"origin" "584 -792 416"
-"classname" "path_corner"
-"targetname" "t93"
-"target" "t92"
-}
-{
-"classname" "monster_army"
-"origin" "390 -970 432"
-"angle" "0"
-"target" "t94"
-}
-{
-"classname" "monster_army"
-"origin" "566 -970 432"
-"angle" "270"
-"target" "t92"
-}
-{
-"classname" "path_corner"
-"origin" "208 -304 304"
-"targetname" "t97"
-"target" "t96"
-}
-{
-"classname" "path_corner"
-"origin" "208 -464 304"
-"targetname" "t96"
-"target" "t97"
-}
-{
-"spawnflags" "1280"
-"classname" "path_corner"
-"origin" "-344 160 304"
-"targetname" "t100"
-"target" "t99"
-}
-{
-"spawnflags" "1280"
-"origin" "168 152 304"
-"classname" "path_corner"
-"targetname" "t99"
-"target" "t100"
-}
-{
-"spawnflags" "1280"
-"classname" "monster_ogre"
-"origin" "240 152 320"
-"angle" "180"
-"target" "t99"
-}
-{
-"spawnflags" "768"
-"classname" "monster_ogre"
-"origin" "-392 80 320"
-"angle" "0"
-"targetname" "t101"
-}
-{
-"spawnflags" "768"
-"classname" "trigger_once"
-"target" "t101"
-"model" "*30"
-}
-{
-"classname" "item_health"
-"origin" "40 -16 464"
-}
-{
-"origin" "80 -48 464"
-"classname" "item_health"
-}
-{
-"origin" "520 -72 296"
-"classname" "item_shells"
-}
-{
-"spawnflags" "1"
-"origin" "-424 -216 296"
-"classname" "item_shells"
-}
-{
-"spawnflags" "769"
-"angle" "270"
-"origin" "880 -400 568"
-"classname" "monster_wizard"
-}
-{
-"light" "200"
-"origin" "432 176 152"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "432 -56 256"
-"classname" "light"
-}
-{
-"origin" "264 -96 300"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "264 -140 300"
-}
-{
-"spawnflags" "1"
-"origin" "1184 1568 240"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "1184 1616 240"
-"spawnflags" "1"
-}
-{
-"light" "150"
-"origin" "1496 1112 108"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1120 1152 96"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1080 692 184"
-"classname" "light"
-}
-{
-"light" "300"
-"classname" "light_flame_small_yellow"
-"origin" "832 1184 294"
-}
-{
-"origin" "464 536 358"
-"classname" "light_flame_small_yellow"
-"light" "300"
-}
-{
-"light" "300"
-"classname" "light_flame_small_yellow"
-"origin" "600 704 334"
-}
-{
-"light" "150"
-"origin" "1736 1096 110"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "832 1056 134"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "784 704 294"
-"classname" "light"
-}
-{
-"origin" "856 592 182"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "824 552 182"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "-416 -144 320"
-"angle" "90"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "168 -480 320"
-"angle" "45"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1496 1328 200"
-"angle" "270"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1936 -136 312"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "936 -1216 432"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "792 -992 440"
-"angle" "45"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1080 -720 312"
-"angle" "0"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "408 -752 432"
-"angle" "270"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "792 -208 320"
-"angle" "45"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "784 808 206"
-"angle" "225"
-}
-{
-"sounds" "3"
-"wait" "3"
-"angle" "90"
-"classname" "func_door"
-"model" "*31"
-}
-{
-"sounds" "0"
-"wait" "3"
-"angle" "270"
-"classname" "func_door"
-"model" "*32"
-}
-{
-"spawnflags" "1"
-"origin" "680 832 182"
-"classname" "item_shells"
-}
-{
-"origin" "1392 240 300"
-"classname" "weapon_supershotgun"
-}
-{
-"spawnflags" "769"
-"angle" "270"
-"origin" "954 -754 444"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "1"
-"origin" "520 -1280 408"
-"classname" "item_shells"
-}
-{
-"light" "200"
-"origin" "-612 -500 548"
-"classname" "light"
-}
-{
-"classname" "func_door"
-"angle" "90"
-"targetname" "t110"
-"wait" "-1"
-"model" "*33"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"angle" "270"
-"wait" "-1"
-"model" "*34"
-}
-{
-"classname" "trigger_once"
-"target" "t110"
-"model" "*35"
-}
-{
-"classname" "trigger_changelevel"
-"map" "e1m3"
-"model" "*36"
-}
-{
-"spawnflags" "1792"
-"origin" "680 728 184"
-"classname" "weapon_rocketlauncher"
-}
-{
-"spawnflags" "1792"
-"origin" "1496 1256 176"
-"classname" "weapon_nailgun"
-}
-{
-"angle" "180"
-"spawnflags" "1792"
-"origin" "-96 -496 360"
-"classname" "weapon_supernailgun"
-}
-{
-"spawnflags" "1794"
-"origin" "-112 -8 464"
-"classname" "item_health"
-}
-{
-"spawnflags" "1793"
-"origin" "-112 -568 360"
-"classname" "item_spikes"
-}
-{
-"spawnflags" "1792"
-"origin" "1616 1424 176"
-"classname" "item_spikes"
-}
-{
-"spawnflags" "1792"
-"classname" "item_spikes"
-"origin" "1656 1424 176"
-}
-{
-"spawnflags" "1792"
-"origin" "1696 1424 176"
-"classname" "item_spikes"
-}
-{
-"spawnflags" "768"
-"target" "t34"
-"angle" "315"
-"origin" "1070 646 312"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "768"
-"targetname" "t84"
-"angle" "90"
-"origin" "1624 88 376"
-"classname" "monster_wizard"
-}
-{
-"spawnflags" "768"
-"angle" "90"
-"targetname" "t84"
-"origin" "1866 -378 312"
-"classname" "monster_ogre"
-}
-{
-"angle" "45"
-"origin" "1088 -1096 440"
-"classname" "monster_knight"
-"targetname" "t50"
-}
-{
-"spawnflags" "768"
-"classname" "monster_knight"
-"origin" "1400 -1144 440"
-"angle" "90"
-"targetname" "t50"
-}
-{
-"spawnflags" "256"
-"target" "t111"
-"targetname" "t112"
-"origin" "896 -1216 416"
-"classname" "path_corner"
-}
-{
-"spawnflags" "256"
-"target" "t112"
-"targetname" "t111"
-"classname" "path_corner"
-"origin" "704 -1216 416"
-}
-{
-"spawnflags" "257"
-"target" "t111"
-"angle" "180"
-"origin" "758 -1218 432"
-"classname" "monster_army"
-}
-{
-"spawnflags" "768"
-"target" "t114"
-"targetname" "t113"
-"origin" "-96 -520 368"
-"classname" "path_corner"
-}
-{
-"spawnflags" "768"
-"target" "t113"
-"targetname" "t114"
-"origin" "-96 -152 304"
-"classname" "path_corner"
-}
-{
-"targetname" "t116"
-"spawnflags" "769"
-"target" "t113"
-"angle" "270"
-"origin" "-98 -194 320"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "1536"
-"origin" "1936 -96 289"
-"classname" "item_health"
-}
-{
-"spawnflags" "1025"
-"origin" "1040 -1200 417"
-"classname" "item_health"
-}
-{
-"spawnflags" "769"
-"target" "t117"
-"angle" "315"
-"origin" "-560 -312 592"
-"classname" "monster_wizard"
-}
-{
-"spawnflags" "768"
-"target" "t118"
-"targetname" "t117"
-"origin" "-528 -344 576"
-"classname" "path_corner"
-}
-{
-"spawnflags" "768"
-"target" "t117"
-"targetname" "t118"
-"origin" "-352 -656 576"
-"classname" "path_corner"
-}
-{
-"classname" "light"
-"origin" "1360 976 224"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1616 976 224"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1208 1296 368"
-"light" "250"
-}
-{
-"origin" "1784 1288 368"
-"classname" "light"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1496 1664 336"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1752 1176 112"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "1776 976 112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1216 976 112"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "1224 1176 112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1496 1432 520"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1496 1304 264"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1496 1432 288"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1608 1120 88"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1384 1120 88"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1496 864 368"
-"light" "150"
-}
-{
-"light" "175"
-"origin" "980 764 353"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1228 764 353"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "1104 464 353"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1104 -40 423"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "1416 -128 367"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1104 -184 367"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1184 56 423"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1024 56 423"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1272 -64 399"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "888 -64 399"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1104 152 129"
-"light" "300"
-}
-{
-"classname" "light"
-"origin" "976 392 129"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1104 656 120"
-}
-{
-"classname" "light"
-"origin" "896 712 144"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "640 704 280"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "464 496 296"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "888 1152 96"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "840 880 240"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "848 584 240"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "784 160 144"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "440 336 144"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "584 336 144"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "432 24 136"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "656 328 224"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "432 -128 312"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "600 -384 360"
-"light" "200"
-}
-{
-"origin" "520 -128 406"
-"classname" "light_flame_small_yellow"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "424 -320 352"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "664 -1216 472"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "336 -1208 504"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "336 -1008 504"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "336 -816 504"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "880 -1000 496"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "880 -792 496"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "880 -376 304"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1048 -912 480"
-"light" "225"
-}
-{
-"classname" "light"
-"origin" "1120 -1192 468"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1376 -1192 468"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1472 -912 464"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "880 -304 480"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "880 -680 480"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "1600 -704 484"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1504 -704 348"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "1336 -704 348"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1152 -640 332"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1096 -552 348"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "1160 -456 332"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1216 -384 348"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1344 -384 348"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1544 392 156"
-"light" "225"
-}
-{
-"light" "225"
-"origin" "1848 248 156"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1936 136 156"
-"light" "225"
-}
-{
-"light" "200"
-"origin" "2096 -80 156"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "2048 -408 156"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1456 -392 444"
-"light" "225"
-}
-{
-"classname" "light"
-"origin" "1640 -384 352"
-"light" "225"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "2134 -474 316"
-"light" "250"
-}
-{
-"light" "200"
-"origin" "168 216 496"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-328 208 496"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-96 360 432"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-96 144 432"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-376 32 432"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "208 -72 432"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-96 72 360"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-64 -232 368"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-96 -320 560"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "-96 -496 448"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-416 -104 392"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-344 -152 528"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "160 -152 528"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-96 8 528"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-560 -504 688"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-440 -368 688"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-440 -656 688"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-336 -504 688"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "2084 -208 336"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "2012 -252 332"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1948 -328 332"
-"light" "100"
-}
-{
-"light" "150"
-"origin" "1892 -452 332"
-"classname" "light"
-}
-{
-"sounds" "1"
-"targetname" "t120"
-"wait" "-1"
-"angle" "-2"
-"classname" "func_door"
-"lip" "4"
-"model" "*37"
-}
-{
-"target" "t120"
-"classname" "trigger_once"
-"model" "*38"
-}
-{
-"light" "100"
-"origin" "2076 -312 336"
-"classname" "light"
-}
-{
-"sounds" "3"
-"spawnflags" "2064"
-"angle" "0"
-"wait" "-1"
-"classname" "func_door"
-"model" "*39"
-}
-{
-"spawnflags" "2064"
-"wait" "-1"
-"angle" "180"
-"classname" "func_door"
-"model" "*40"
-}
-{
-"light" "100"
-"origin" "332 -264 356"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "144 -264 356"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "1104 572 316"
-"classname" "light"
-}
-{
-"target" "t121"
-"wait" ".8"
-"classname" "trigger_multiple"
-"model" "*41"
-}
-{
-"targetname" "t121"
-"angle" "180"
-"origin" "2120 -256 332"
-"classname" "trap_spikeshooter"
-"spawnflags" "1024"
-}
-{
-"targetname" "t121"
-"angle" "90"
-"origin" "1944 -456 332"
-"classname" "trap_spikeshooter"
-"spawnflags" "1024"
-}
-{
-"light" "150"
-"origin" "1312 -856 472"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1184 -856 472"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "1560 -568 224"
-"light" "200"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"wait" "-1"
-"speed" "50"
-"sounds" "1"
-"targetname" "t123"
-"lip" "6"
-"model" "*42"
-}
-{
-"classname" "trigger_once"
-"target" "t123"
-"model" "*43"
-}
-{
-"classname" "light"
-"origin" "1496 -552 330"
-"light" "700"
-"target" "t52"
-}
-{
-"classname" "light"
-"origin" "1288 80 140"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1288 400 80"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1328 -664 160"
-"light" "200"
-}
-{
-"classname" "item_armor1"
-"origin" "784 56 304"
-}
-{
-"classname" "light"
-"origin" "1544 464 352"
-"light" "75"
-}
-{
-"classname" "func_plat"
-"model" "*44"
-}
-{
-"classname" "light"
-"origin" "1496 1192 280"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1608 1192 136"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "1384 1184 136"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "1608 1048 136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1384 1048 136"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1200 1148 92"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "876 -184 367"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "768 -128 384"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1104 388 552"
-"light" "250"
-}
-{
-"light" "200"
-"origin" "1392 240 384"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1392 80 368"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1272 400 367"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "920 400 367"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "816 208 368"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "800 24 368"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "800 376 385"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1400 400 385"
-"classname" "light"
-}
-{
-"classname" "path_corner"
-"origin" "1104 336 300"
-"target" "t126"
-"targetname" "t127"
-}
-{
-"origin" "1104 24 300"
-"classname" "path_corner"
-"targetname" "t126"
-"target" "t127"
-}
-{
-"classname" "monster_army"
-"origin" "1104 424 316"
-"angle" "270"
-"target" "t127"
-}
-{
-"targetname" "t128"
-"origin" "1392 240 308"
-"classname" "info_null"
-}
-{
-"light" "300"
-"target" "t128"
-"origin" "1392 240 376"
-"classname" "light"
-}
-{
-"targetname" "t129"
-"angle" "0"
-"origin" "552 -128 320"
-"classname" "monster_army"
-}
-{
-"target" "t129"
-"classname" "trigger_once"
-"model" "*45"
-}
-{
-"sounds" "1"
-"classname" "trigger_secret"
-"model" "*46"
-}
-{
-"sounds" "1"
-"classname" "trigger_secret"
-"model" "*47"
-}
-{
-"classname" "light"
-"origin" "1104 24 536"
-"light" "350"
-}
-{
-"spawnflags" "1"
-"classname" "func_door_secret"
-"angle" "270"
-"model" "*48"
-}
-{
-"light" "200"
-"origin" "1680 1552 320"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1312 1552 320"
-"light" "200"
-}
-{
-"classname" "item_spikes"
-"origin" "1480 1104 68"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "1760 -568 256"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "1232 -1200 416"
-}
-{
-"message" "This door is opened elsewhere..."
-"classname" "func_door"
-"sounds" "3"
-"angle" "180"
-"wait" "-1"
-"targetname" "t122"
-"speed" "35"
-"spawnflags" "2048"
-"model" "*49"
-}
-{
-"classname" "func_door"
-"angle" "0"
-"wait" "-1"
-"speed" "30"
-"spawnflags" "2048"
-"model" "*50"
-}
-{
-"classname" "light"
-"origin" "1496 1600 296"
-"light" "150 "
-}
-{
-"light" "150"
-"origin" "1568 1664 296"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1424 1664 296"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1328 1424 296"
-"light" "200"
-}
-{
-"light" "250"
-"origin" "1696 1416 296"
-"classname" "light"
-}
-{
-"classname" "monster_army"
-"origin" "1592 1296 200"
-"angle" "270"
-}
-{
-"spawnflags" "768"
-"classname" "monster_demon1"
-"origin" "-96 576 320"
-"angle" "270"
-"targetname" "t73"
-"target" "t143"
-}
-{
-"classname" "path_corner"
-"origin" "1392 416 304"
-"targetname" "t131"
-"target" "t130"
-"spawnflags" "768"
-}
-{
-"origin" "1392 296 304"
-"classname" "path_corner"
-"targetname" "t130"
-"target" "t131"
-"spawnflags" "768"
-}
-{
-"classname" "monster_army"
-"origin" "1392 352 320"
-"angle" "270"
-"target" "t130"
-"spawnflags" "768"
-}
-{
-"target" "t132"
-"targetname" "t133"
-"origin" "296 -328 304"
-"classname" "path_corner"
-}
-{
-"target" "t133"
-"targetname" "t132"
-"classname" "path_corner"
-"origin" "472 -416 304"
-}
-{
-"spawnflags" "1"
-"target" "t132"
-"angle" "90"
-"origin" "472 -456 320"
-"classname" "monster_army"
-}
-{
-"spawnflags" "1"
-"targetname" "t89"
-"angle" "135"
-"origin" "1712 -784 376"
-"classname" "monster_army"
-}
-{
-"target" "t135"
-"spawnflags" "256"
-"targetname" "t134"
-"origin" "400 -1128 416"
-"classname" "path_corner"
-}
-{
-"target" "t134"
-"spawnflags" "256"
-"targetname" "t135"
-"classname" "path_corner"
-"origin" "400 -1248 416"
-}
-{
-"target" "t134"
-"spawnflags" "257"
-"angle" "90"
-"origin" "408 -1208 432"
-"classname" "monster_army"
-}
-{
-"targetname" "t101"
-"angle" "90"
-"origin" "-288 -24 488"
-"classname" "monster_army"
-"spawnflags" "768"
-}
-{
-"spawnflags" "768"
-"targetname" "t101"
-"classname" "monster_army"
-"origin" "136 -128 488"
-"angle" "90"
-}
-{
-"spawnflags" "1792"
-"origin" "-264 -24 464"
-"classname" "item_rockets"
-}
-{
-"spawnflags" "2048"
-"origin" "-240 -8 464"
-"classname" "item_spikes"
-}
-{
-"classname" "monster_ogre"
-"origin" "-304 -304 488"
-"angle" "225"
-"spawnflags" "769"
-}
-{
-"classname" "func_wall"
-"spawnflags" "768"
-"model" "*51"
-}
-{
-"classname" "trap_spikeshooter"
-"origin" "2048 -48 332"
-"angle" "270"
-"spawnflags" "769"
-"targetname" "t121"
-}
-{
-"origin" "2048 -476 332"
-"classname" "info_null"
-"targetname" "t136"
-}
-{
-"style" "32"
-"origin" "2048 -456 336"
-"classname" "light"
-"light" "800"
-"spawnflags" "1"
-"target" "t136"
-"targetname" "t137"
-}
-{
-"style" "32"
-"classname" "trigger_once"
-"spawnflags" "768"
-"target" "t137"
-"model" "*52"
-}
-{
-"classname" "monster_wizard"
-"origin" "672 328 384"
-"angle" "180"
-"spawnflags" "768"
-"targetname" "t138"
-}
-{
-"classname" "trigger_once"
-"target" "t138"
-"model" "*53"
-}
-{
-"style" "32"
-"classname" "light"
-"origin" "2004 -52 332"
-"light" "100"
-"spawnflags" "1"
-"targetname" "t137"
-}
-{
-"classname" "item_shells"
-"origin" "1416 224 300"
-"spawnflags" "768"
-}
-{
-"classname" "path_corner"
-"origin" "-344 136 304"
-"targetname" "t139"
-"target" "t140"
-"spawnflags" "768"
-}
-{
-"origin" "168 128 304"
-"classname" "path_corner"
-"target" "t139"
-"targetname" "t140"
-"spawnflags" "768"
-}
-{
-"classname" "monster_ogre"
-"origin" "-400 168 320"
-"spawnflags" "768"
-"target" "t139"
-}
-{
-"classname" "trap_spikeshooter"
-"origin" "2120 -256 332"
-"angle" "180"
-"spawnflags" "769"
-"targetname" "t121"
-}
-{
-"classname" "trap_spikeshooter"
-"origin" "1944 -456 332"
-"targetname" "t121"
-"angle" "90"
-"spawnflags" "769"
-}
-{
-"classname" "item_spikes"
-"origin" "-336 -80 470"
-"spawnflags" "768"
-}
-{
-"targetname" "t143"
-"classname" "trigger_teleport"
-"target" "t142"
-"spawnflags" "2"
-"model" "*54"
-}
-{
-"targetname" "t143"
-"classname" "trigger_teleport"
-"target" "t141"
-"spawnflags" "2"
-"model" "*55"
-}
-{
-"classname" "monster_demon1"
-"origin" "32 840 359"
-"angle" "270"
-"targetname" "t143"
-"spawnflags" "768"
-}
-{
-"angle" "270"
-"origin" "-192 840 359"
-"classname" "monster_demon1"
-"targetname" "t143"
-"spawnflags" "768"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "80 216 303"
-"angle" "270"
-"targetname" "t141"
-}
-{
-"angle" "270"
-"origin" "-264 224 303"
-"classname" "info_teleport_destination"
-"targetname" "t142"
-}
-{
-"wait" "-1"
-"target" "t53"
-"health" "1"
-"classname" "func_button"
-"model" "*56"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "1408 1296 200"
-"classname" "monster_army"
-}
-{
-"classname" "item_shells"
-"origin" "772 -856 420"
-"spawnflags" "768"
-}
-{
-"spawnflags" "1792"
-"origin" "1248 -1128 420"
-"classname" "weapon_grenadelauncher"
-}
-{
-"spawnflags" "1793"
-"origin" "864 -312 440"
-"classname" "item_rockets"
-}
-{
-"classname" "trigger_once"
-"message" "Pass through the arch to exit..."
-"model" "*57"
-}
-{
-"mangle" "20 300 0"
-"classname" "info_intermission"
-"origin" "-224 424 512"
-}
-{
-"mangle" "20 45 0"
-"origin" "1048 -744 488"
-"classname" "info_intermission"
-}
-{
-"mangle" "20 270 0"
-"origin" "1104 424 528"
-"classname" "info_intermission"
-}
-{
-"mangle" "20 45 0"
-"origin" "1240 984 416"
-"classname" "info_intermission"
-}
-{
-"sounds" "1"
-"speed" "20"
-"classname" "func_button"
-"angle" "0"
-"wait" "-1"
-"target" "t144"
-"model" "*58"
-}
-{
-"classname" "light"
-"origin" "400 -1392 480"
-"light" "150"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"wait" "-1"
-"speed" "20"
-"sounds" "1"
-"targetname" "t144"
-"model" "*59"
-}
-{
-"classname" "trigger_secret"
-"model" "*60"
-}
-{
-"classname" "item_artifact_super_damage"
-"origin" "400 -1360 432"
-}
-{
-"classname" "item_spikes"
-"origin" "808 -632 192"
-"spawnflags" "2049"
-}
-{
-"classname" "item_health"
-"origin" "924 -632 192"
-"spawnflags" "2048"
-}
-{
-"classname" "weapon_supernailgun"
-"origin" "880 -616 192"
-"spawnflags" "1792"
-}
-{
-"classname" "ambient_drip"
-"origin" "842 978 344"
-}
-{
-"classname" "ambient_drip"
-"origin" "546 330 400"
-}
-{
-"classname" "info_player_coop"
-"origin" "1608 1664 264"
-"angle" "270"
-}
-{
-"angle" "270"
-"origin" "1392 1664 264"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "1496 1560 264"
-"angle" "270"
-}
-{
-"spawnflags" "256"
-"angle" "270"
-"origin" "232 -176 320"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "1280"
-"angle" "225"
-"origin" "-368 -312 480"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*61"
-}
-{
-"origin" "1810 274 200"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "1802 -102 200"
-}
-{
-"origin" "2050 -214 200"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "2002 -390 200"
-}
-{
-"origin" "1738 -398 200"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "1346 -398 200"
-}
-{
-"origin" "1138 -542 200"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "882 -494 200"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "1722 1090 176"
-}
-{
-"origin" "1242 1090 176"
-"classname" "ambient_swamp1"
-}
-{
-"classname" "ambient_swamp2"
-"origin" "1106 642 192"
-}
-{
-"origin" "1346 242 192"
-"classname" "ambient_swamp2"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "866 210 192"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "1802 90 192"
-}
-{
-"origin" "1546 -398 192"
-"classname" "ambient_swamp1"
-}
-{
-"classname" "ambient_swamp2"
-"origin" "2042 -310 192"
-}
-{
-"origin" "1178 -398 192"
-"classname" "ambient_swamp2"
-}
-{
-"classname" "ambient_swamp2"
-"origin" "1202 -678 192"
-}
diff --git a/Misc/pak/maps/e1m4.diff b/Misc/pak/maps/e1m4.diff
new file mode 100644
index 000000000..7e420ff89
--- /dev/null
+++ b/Misc/pak/maps/e1m4.diff
@@ -0,0 +1,30 @@
+--- e1m4.ent
++++ e1m4@958e.ent
+@@ -2143,12 +2143,13 @@
+ {
+ "classname" "func_door_secret"
+ "angle" "0"
+ "spawnflags" "1"
+ "targetname" "t91"
+ "model" "*53"
++"t_length" "73" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "func_button"
+ "angle" "-2"
+ "wait" "-1"
+ "target" "t92"
+@@ -2202,12 +2203,13 @@
+ {
+ "spawnflags" "3"
+ "angle" "0"
+ "classname" "func_door_secret"
+ "targetname" "t91"
+ "model" "*60"
++"t_length" "73" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "light" "150"
+ "origin" "680 -256 1144"
+ "classname" "light"
+ }
diff --git a/Misc/pak/maps/e1m4.ent.orig b/Misc/pak/maps/e1m4.ent.orig
deleted file mode 100644
index a710d6c76..000000000
--- a/Misc/pak/maps/e1m4.ent.orig
+++ /dev/null
@@ -1,3169 +0,0 @@
-{
-"message" "the Grisly Grotto"
-"worldtype" "0"
-"classname" "worldspawn"
-"wad" "gfx/wizard.wad"
-"sounds" "5"
-}
-{
-"classname" "light"
-"origin" "464 480 1656"
-"light" "300"
-}
-{
-"light" "400"
-"origin" "712 296 1512"
-"classname" "light"
-}
-{
-"sounds" "3"
-"angle" "180"
-"classname" "func_door"
-"model" "*1"
-}
-{
-"angle" "0"
-"classname" "func_door"
-"model" "*2"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "560 -112 1374"
-}
-{
-"origin" "848 -112 1374"
-"classname" "light_flame_small_yellow"
-}
-{
-"origin" "760 656 1536"
-"classname" "light"
-}
-{
-"light" "400"
-"origin" "834 498 1040"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "944 728 1456"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "1016 80 998"
-}
-{
-"origin" "392 80 998"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light"
-"origin" "680 1224 516"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "704 992 516"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "696 1608 628"
-"classname" "light"
-}
-{
-"origin" "704 1368 588"
-"classname" "light"
-}
-{
-"origin" "816 1616 444"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "712 1728 444"
-}
-{
-"origin" "592 1608 444"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "624 1096 444"
-}
-{
-"light" "300"
-"origin" "432 1328 816"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "696 1112 816"
-"light" "300"
-}
-{
-"classname" "light"
-"origin" "704 -80 960"
-"light" "200"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "818 18 948"
-"light" "200"
-}
-{
-"origin" "586 18 948"
-"classname" "light_torch_small_walltorch"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "688 496 880"
-"classname" "light"
-}
-{
-"origin" "489 483 1356"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "200"
-"origin" "704 -120 1360"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1216 936 1560"
-"light" "200"
-}
-{
-"origin" "1294 826 1576"
-"classname" "light_flame_large_yellow"
-}
-{
-"sounds" "1"
-"targetname" "t1"
-"wait" "-1"
-"angle" "180"
-"classname" "func_door"
-"model" "*3"
-}
-{
-"angle" "0"
-"wait" "-1"
-"classname" "func_door"
-"model" "*4"
-}
-{
-"target" "t1"
-"classname" "trigger_once"
-"model" "*5"
-}
-{
-"map" "e1m5"
-"classname" "trigger_changelevel"
-"model" "*6"
-}
-{
-"wait" "-1"
-"angle" "0"
-"classname" "func_door"
-"speed" "50"
-"model" "*7"
-}
-{
-"classname" "info_player_start"
-"origin" "-256 2272 1240"
-"angle" "270"
-}
-{
-"targetname" "t23"
-"classname" "func_door"
-"angle" "180"
-"wait" "-1"
-"speed" "50"
-"sounds" "3"
-"model" "*8"
-}
-{
-"classname" "light"
-"origin" "696 704 820"
-}
-{
-"classname" "light"
-"origin" "704 776 672"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "360 904 520"
-"light" "200"
-}
-{
-"origin" "704 856 400"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "944 880 416"
-"light" "150"
-}
-{
-"origin" "1056 1176 424"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1096 1408 360"
-}
-{
-"classname" "light"
-"origin" "416 1696 360"
-}
-{
-"origin" "328 1368 360"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200 "
-"classname" "light"
-"origin" "696 752 896"
-}
-{
-"light" "250"
-"origin" "798 1850 1024"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "642 1850 1024"
-"light" "250"
-}
-{
-"light" "200 "
-"origin" "700 1364 952"
-"classname" "light"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "1094 1494 1064"
-}
-{
-"origin" "324 1104 1064"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "200 "
-"origin" "704 1660 952"
-"classname" "light"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"angle" "180"
-"wait" "-1"
-"targetname" "t2"
-"model" "*9"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"wait" "-1"
-"angle" "0"
-"targetname" "t4"
-"model" "*10"
-}
-{
-"classname" "trigger_once"
-"targetname" "t4"
-"target" "t7"
-"model" "*11"
-}
-{
-"classname" "trigger_once"
-"targetname" "t2"
-"target" "t7"
-"model" "*12"
-}
-{
-"dmg" "90"
-"speed" "200"
-"classname" "func_train"
-"target" "t5"
-"targetname" "t8"
-"model" "*13"
-}
-{
-"classname" "path_corner"
-"origin" "-359 1528 1316"
-"targetname" "t5"
-"target" "t6"
-}
-{
-"classname" "path_corner"
-"origin" "-359 1528 880"
-"targetname" "t6"
-"target" "t5"
-"wait" "-1"
-}
-{
-"classname" "trigger_counter"
-"targetname" "t7"
-"target" "t8"
-"count" "2"
-"model" "*14"
-}
-{
-"targetname" "t11"
-"origin" "-96 1640 1256"
-"classname" "info_null"
-}
-{
-"targetname" "t9"
-"origin" "-416 1640 1256"
-"classname" "info_null"
-}
-{
-"light" "400"
-"target" "t9"
-"origin" "-396 1640 1256"
-"classname" "light"
-}
-{
-"light" "400"
-"target" "t11"
-"origin" "-116 1640 1256"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-328 1564 1532"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "-88 1640 1514"
-}
-{
-"origin" "-424 1640 1514"
-"classname" "light_flame_small_yellow"
-}
-{
-"origin" "-248 1464 1154"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "-256 1808 1046"
-}
-{
-"light" "200"
-"origin" "-164 1732 1268"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-348 1732 1268"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "-248 1500 1056"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-256 1772 956"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-128 1636 920"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-124 1640 920"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-172 1524 920"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-284 1516 920"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-360 1580 920"
-"light" "150"
-}
-{
-"light" "75"
-"origin" "-360 1700 920"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "72 1632 928"
-"light" "125"
-}
-{
-"light" "150"
-"origin" "80 1488 928"
-"classname" "light"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "158 1308 1064"
-}
-{
-"classname" "light"
-"origin" "-192 1688 1380"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "-192 1592 1380"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-320 1592 1380"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "-320 1688 1380"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-384 1640 1452"
-"light" "125"
-}
-{
-"classname" "light"
-"origin" "-112 1640 1452"
-"light" "125"
-}
-{
-"light" "200"
-"origin" "-248 1504 1336"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-128 1640 1336"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-384 1640 1336"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "696 1608 816"
-"light" "300"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "888 1328 424"
-}
-{
-"classname" "light"
-"origin" "160 1352 960"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "368 1104 1000"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1048 1504 1000"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "992 992 1048"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "48 1384 1008"
-"light" "100"
-}
-{
-"light" "150"
-"origin" "1080 1144 1048"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "968 824 976"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "896 1328 1000"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "368 1616 1000"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "256 1496 824"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "256 1352 824"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "856 1368 536"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "552 1360 536"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "872 1552 1056"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1032 1056 904"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1080 1184 904"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "864 848 904"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "312 1496 1016"
-"light" "175"
-}
-{
-"light" "200"
-"origin" "704 1368 808"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "464 816 904"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "944 888 800"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "888 1112 728"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "1008 1504 728"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "720 1848 1200"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "704 888 672"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "512 1456 1040"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "440 840 380"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "720 1848 1028"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "720 1936 1024"
-"classname" "light"
-}
-{
-"origin" "544 2128 984"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "712 1912 576"
-"classname" "light"
-}
-{
-"light" "300"
-"origin" "720 2544 856"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "888 2048 592"
-"classname" "light"
-}
-{
-"origin" "704 2496 1128"
-"classname" "light"
-}
-{
-"origin" "512 2048 976"
-"classname" "light"
-"light" "150"
-}
-{
-"origin" "952 2328 528"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "700 2760 808"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "700 2800 616"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "584 2780 584"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "808 2780 584"
-"classname" "light"
-}
-{
-"sounds" "3"
-"wait" "-1"
-"targetname" "t29"
-"classname" "func_door"
-"angle" "270"
-"model" "*15"
-}
-{
-"message" "This door is opened elsewhere..."
-"wait" "-1"
-"classname" "func_door"
-"angle" "90"
-"model" "*16"
-}
-{
-"classname" "light"
-"origin" "424 2304 1000"
-"light" "200"
-}
-{
-"light" "300"
-"origin" "696 2880 1062"
-"classname" "light_flame_small_yellow"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "864 2128 984"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "702 2154 1228"
-"light" "0"
-}
-{
-"classname" "light"
-"origin" "832 2008 1136"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "584 2008 1136"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "272 2016 1136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "272 2320 1136"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1104 2408 984"
-"classname" "light"
-}
-{
-"sounds" "2"
-"classname" "func_plat"
-"wait" "4"
-"model" "*17"
-}
-{
-"classname" "light"
-"origin" "700 2844 996"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "704 2216 1252"
-}
-{
-"origin" "936 2304 1252"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "936 2536 1252"
-}
-{
-"light" "300"
-"classname" "light"
-"origin" "488 2536 1252"
-}
-{
-"origin" "488 2304 1252"
-"classname" "light"
-"light" "300"
-}
-{
-"light" "0"
-"origin" "998 2306 1228"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "998 2534 1228"
-"light" "0"
-}
-{
-"light" "0"
-"origin" "426 2534 1228"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "426 2306 1228"
-"light" "0"
-}
-{
-"classname" "light"
-"origin" "704 2152 984"
-"light" "200"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "1160 2400 1038"
-"light" "250"
-}
-{
-"origin" "840 2536 630"
-"classname" "light_flame_small_yellow"
-"light" "250"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "584 2544 630"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "408 2304 694"
-"classname" "light_flame_small_yellow"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "960 2632 528"
-}
-{
-"classname" "light"
-"origin" "960 2480 528"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "456 2304 624"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "704 2416 576"
-"light" "250"
-}
-{
-"light" "150"
-"origin" "728 2184 528"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "512 2176 528"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "832 2336 656"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "592 2336 656"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "808 2584 576"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "616 2576 576"
-"classname" "light"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "488 2712 694"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "488 2624 608"
-"light" "175"
-}
-{
-"classname" "light"
-"origin" "480 2464 608"
-"light" "175"
-}
-{
-"light" "250"
-"origin" "184 2184 1038"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "512 2096 1038"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "224 2184 976"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "848 2024 992"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "256 1992 1000"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "272 2376 1000"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1112 2208 1032"
-"light" "150"
-}
-{
-"light" "0"
-"origin" "698 2860 1228"
-"classname" "light_flame_large_yellow"
-}
-{
-"origin" "700 2808 1252"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "472 2632 1062"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "952 2632 1062"
-"light" "250"
-}
-{
-"light" "150"
-"origin" "952 2424 894"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "480 2424 894"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "896 2296 966"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "704 2304 966"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "552 2304 966"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "704 2184 406"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "712 2000 406"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "504 2224 400"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "960 2576 400"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "960 2400 400"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "808 1112 592"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "600 1112 592"
-"light" "150"
-}
-{
-"light" "175"
-"origin" "1016 128 936"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "392 128 936"
-"light" "175"
-}
-{
-"light" "150"
-"origin" "848 -64 1304"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "560 -64 1304"
-"light" "150"
-}
-{
-"light" "175"
-"origin" "1248 832 1496"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1096 872 1496"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "896 2208 976"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1096 200 1512"
-"light" "350"
-}
-{
-"light" "350"
-"origin" "264 192 1512"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "488 448 1264"
-"classname" "light"
-}
-{
-"origin" "1048 728 1456"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "125"
-"origin" "1328 928 1448"
-"classname" "light"
-}
-{
-"light" "225"
-"origin" "696 672 1320"
-"classname" "light"
-}
-{
-"origin" "816 -56 1640"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "584 -56 1640"
-}
-{
-"light" "175"
-"origin" "880 96 1376"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "528 96 1376"
-"light" "175"
-}
-{
-"light" "200"
-"origin" "960 344 1072"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1120 264 1072"
-"light" "200"
-}
-{
-"light" "175"
-"origin" "1208 96 1016"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "1024 360 968"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "328 336 968"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "416 424 1072"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "296 256 1072"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "704 48 1040"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "384 464 976"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "224 264 976"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "952 2192 416"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1040 -464 1016"
-"light" "150"
-}
-{
-"sounds" "2"
-"spawnflags" "1"
-"classname" "func_plat"
-"model" "*18"
-}
-{
-"light" "250"
-"origin" "1072 -272 1262"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light"
-"origin" "1024 -272 1200"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "624 -240 1328"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "1080 -624 1168"
-"classname" "light"
-}
-{
-"origin" "456 -576 1230"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light"
-"origin" "504 -576 1168"
-"light" "175"
-}
-{
-"origin" "624 -448 924"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "624 -704 924"
-}
-{
-"light" "125"
-"origin" "664 -448 880"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "624 -488 880"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "584 -448 880"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "624 -408 880"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "624 -664 880"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "664 -704 880"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "624 -744 880"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "584 -704 880"
-"light" "125"
-}
-{
-"light" "250"
-"origin" "296 -96 968"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1112 -96 968"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "1056 -224 968"
-"classname" "light"
-}
-{
-"light" "500"
-"origin" "-264 2120 1504"
-"classname" "light"
-}
-{
-"spawnflags" "2064"
-"angle" "0"
-"classname" "func_door"
-"wait" "-1"
-"model" "*19"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"angle" "180"
-"spawnflags" "2064"
-"wait" "-1"
-"model" "*20"
-}
-{
-"light" "200"
-"origin" "704 32 952"
-"classname" "light"
-}
-{
-"target" "t101"
-"spawnflags" "256"
-"targetname" "t23"
-"angle" "90"
-"origin" "-248 1560 1224"
-"classname" "monster_wizard"
-}
-{
-"target" "t23"
-"classname" "trigger_once"
-"model" "*21"
-}
-{
-"origin" "-280 1560 1348"
-"classname" "item_armor2"
-}
-{
-"origin" "-488 2112 1220"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "-488 2064 1220"
-}
-{
-"spawnflags" "1536"
-"origin" "-272 1784 1156"
-"classname" "item_shells"
-}
-{
-"spawnflags" "256"
-"target" "t25"
-"targetname" "t24"
-"origin" "888 1640 1028"
-"classname" "path_corner"
-}
-{
-"spawnflags" "256"
-"target" "t24"
-"targetname" "t25"
-"classname" "path_corner"
-"origin" "624 1264 1028"
-}
-{
-"spawnflags" "256"
-"target" "t24"
-"origin" "928 1672 1028"
-"classname" "monster_wizard"
-}
-{
-"spawnflags" "2304"
-"target" "t26"
-"classname" "trigger_once"
-"model" "*22"
-}
-{
-"target" "t27"
-"targetname" "t28"
-"origin" "568 2040 928"
-"classname" "path_corner"
-}
-{
-"target" "t28"
-"targetname" "t27"
-"classname" "path_corner"
-"origin" "368 2044 928"
-}
-{
-"target" "t27"
-"origin" "472 2040 944"
-"classname" "monster_ogre"
-"spawnflags" "1"
-}
-{
-"sounds" "2"
-"target" "t29"
-"wait" "-1"
-"angle" "90"
-"classname" "func_button"
-"model" "*23"
-}
-{
-"sounds" "3"
-"angle" "180"
-"classname" "func_door"
-"model" "*24"
-}
-{
-"angle" "0"
-"classname" "func_door"
-"model" "*25"
-}
-{
-"light" "175"
-"origin" "1112 2520 964"
-"classname" "light"
-}
-{
-"origin" "104 1308 892"
-"classname" "item_health"
-}
-{
-"spawnflags" "2048"
-"origin" "704 1344 936"
-"classname" "item_key1"
-"sounds" "1"
-}
-{
-"target" "t34"
-"angle" "180"
-"origin" "920 2040 544"
-"classname" "monster_ogre"
-"spawnflags" "1"
-}
-{
-"target" "t35"
-"targetname" "t34"
-"origin" "864 2044 528"
-"classname" "path_corner"
-}
-{
-"target" "t37"
-"targetname" "t35"
-"classname" "path_corner"
-"origin" "704 2048 528"
-}
-{
-"target" "t34"
-"targetname" "t36"
-"origin" "704 2048 528"
-"classname" "path_corner"
-}
-{
-"target" "t36"
-"targetname" "t37"
-"classname" "path_corner"
-"origin" "704 1808 528"
-}
-{
-"targetname" "t38"
-"angle" "270"
-"origin" "456 2476 544"
-"classname" "monster_ogre"
-}
-{
-"target" "t38"
-"classname" "trigger_once"
-"model" "*26"
-}
-{
-"targetname" "t29"
-"angle" "0"
-"origin" "336 2272 952"
-"classname" "monster_knight"
-"spawnflags" "768"
-}
-{
-"targetname" "t39"
-"spawnflags" "1"
-"wait" "-1"
-"angle" "-2"
-"classname" "func_door"
-"sounds" "1"
-"model" "*27"
-}
-{
-"targetname" "t39"
-"angle" "270"
-"origin" "712 2540 448"
-"classname" "monster_ogre"
-}
-{
-"target" "t39"
-"classname" "trigger_once"
-"model" "*28"
-}
-{
-"classname" "light"
-"origin" "712 2544 440"
-"light" "200"
-}
-{
-"classname" "item_health"
-"origin" "1064 2184 920"
-"spawnflags" "1024"
-}
-{
-"spawnflags" "1"
-"origin" "1128 2184 920"
-"classname" "item_health"
-}
-{
-"classname" "item_spikes"
-"origin" "816 2840 920"
-}
-{
-"origin" "816 2800 920"
-"classname" "item_spikes"
-}
-{
-"spawnflags" "256"
-"classname" "monster_wizard"
-"origin" "1656 1496 968"
-"angle" "180"
-"target" "t41"
-}
-{
-"spawnflags" "2"
-"classname" "trigger_teleport"
-"target" "t40"
-"targetname" "t39"
-"model" "*29"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "984 1496 1000"
-"angle" "180"
-"targetname" "t40"
-}
-{
-"spawnflags" "256"
-"classname" "path_corner"
-"origin" "912 1496 1000"
-"targetname" "t41"
-"target" "t42"
-}
-{
-"spawnflags" "256"
-"origin" "528 1368 1000"
-"classname" "path_corner"
-"targetname" "t42"
-"target" "t41"
-}
-{
-"classname" "item_health"
-"origin" "408 2640 520"
-}
-{
-"classname" "item_shells"
-"origin" "456 2672 520"
-"spawnflags" "1"
-}
-{
-"angle" "0"
-"origin" "80 864 968"
-"classname" "monster_wizard"
-"target" "t44"
-}
-{
-"targetname" "t119"
-"spawnflags" "2"
-"classname" "trigger_teleport"
-"target" "t45"
-"model" "*30"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "432 856 952"
-"angle" "45"
-"targetname" "t45"
-}
-{
-"classname" "path_corner"
-"origin" "496 872 952"
-"target" "t43"
-"targetname" "t44"
-}
-{
-"origin" "872 1056 952"
-"classname" "path_corner"
-"targetname" "t43"
-"target" "t44"
-}
-{
-"classname" "trigger_once"
-"spawnflags" "1792"
-"target" "t39"
-"model" "*31"
-}
-{
-"spawnflags" "1024"
-"classname" "monster_knight"
-"origin" "1168 56 904"
-"angle" "135"
-"target" "t49"
-"targetname" "t67"
-}
-{
-"classname" "monster_ogre"
-"origin" "1800 224 920"
-"angle" "180"
-"target" "t116"
-"spawnflags" "256"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"wait" "-1"
-"targetname" "t49"
-"lip" "-24"
-"model" "*32"
-}
-{
-"wait" "-1"
-"angle" "-1"
-"classname" "func_door"
-"spawnflags" "1"
-"targetname" "t39"
-"lip" "-24"
-"model" "*33"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"wait" "-1"
-"targetname" "t29"
-"lip" "-24"
-"model" "*34"
-}
-{
-"spawnflags" "2"
-"classname" "trigger_teleport"
-"target" "t46"
-"model" "*35"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "1104 232 880"
-"angle" "180"
-"targetname" "t46"
-}
-{
-"classname" "path_corner"
-"origin" "1064 256 880"
-"target" "t47"
-"targetname" "t48"
-"spawnflags" "256"
-}
-{
-"origin" "312 232 880"
-"classname" "path_corner"
-"targetname" "t47"
-"target" "t48"
-"spawnflags" "256"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "704 -40 1256"
-"angle" "90"
-"targetname" "t50"
-}
-{
-"classname" "trigger_once"
-"target" "t52"
-"model" "*36"
-}
-{
-"spawnflags" "2"
-"classname" "trigger_teleport"
-"target" "t50"
-"targetname" "t52"
-"model" "*37"
-}
-{
-"angle" "90"
-"origin" "570 -898 1300"
-"classname" "monster_wizard"
-"targetname" "t52"
-}
-{
-"classname" "item_shells"
-"origin" "216 120 880"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "192 232 880"
-}
-{
-"origin" "192 192 880"
-"classname" "item_health"
-"spawnflags" "1024"
-}
-{
-"classname" "item_shells"
-"origin" "-216 1464 888"
-}
-{
-"classname" "item_health"
-"origin" "816 1160 512"
-"spawnflags" "1024"
-}
-{
-"spawnflags" "1"
-"origin" "816 1120 512"
-"classname" "item_health"
-}
-{
-"classname" "monster_wizard"
-"origin" "944 840 956"
-"angle" "135"
-"target" "t53"
-"targetname" "t64"
-}
-{
-"classname" "trigger_once"
-"target" "t64"
-"model" "*38"
-}
-{
-"classname" "monster_knight"
-"origin" "704 392 1280"
-"angle" "270"
-"target" "t65"
-"spawnflags" "1"
-}
-{
-"classname" "path_corner"
-"origin" "704 208 1264"
-"targetname" "t65"
-"target" "t66"
-}
-{
-"origin" "704 496 1264"
-"classname" "path_corner"
-"targetname" "t66"
-"target" "t65"
-}
-{
-"classname" "trigger_once"
-"target" "t67"
-"model" "*39"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"angle" "-2"
-"wait" "-1"
-"targetname" "t72"
-"model" "*40"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"wait" "-1"
-"angle" "-2"
-"targetname" "t72"
-"model" "*41"
-}
-{
-"classname" "trigger_once"
-"target" "t72"
-"model" "*42"
-}
-{
-"classname" "info_null"
-"origin" "852 -580 820"
-"targetname" "t73"
-}
-{
-"classname" "light"
-"origin" "856 -584 936"
-"light" "400"
-"target" "t73"
-}
-{
-"classname" "light"
-"origin" "920 -448 744"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "760 -448 744"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "552 -424 744"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "560 -728 744"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "776 -712 744"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "936 -712 744"
-"classname" "light"
-}
-{
-"classname" "path_corner"
-"origin" "652 -576 952"
-"targetname" "t75"
-"target" "t74"
-}
-{
-"origin" "908 -576 952"
-"classname" "path_corner"
-"targetname" "t74"
-"target" "t75"
-}
-{
-"classname" "monster_ogre"
-"origin" "816 -260 952"
-"angle" "270"
-"targetname" "t72"
-}
-{
-"classname" "monster_ogre"
-"origin" "724 -260 952"
-"angle" "270"
-"targetname" "t72"
-"spawnflags" "256"
-}
-{
-"classname" "item_health"
-"origin" "632 -548 820"
-"spawnflags" "3072"
-}
-{
-"origin" "672 -548 820"
-"classname" "item_health"
-}
-{
-"classname" "func_button"
-"angle" "-2"
-"wait" "-1"
-"target" "t76"
-"model" "*43"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"angle" "-1"
-"wait" "-1"
-"targetname" "t76"
-"model" "*44"
-}
-{
-"light" "150"
-"origin" "1040 -712 1016"
-"classname" "light"
-}
-{
-"origin" "1112 -576 942"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light"
-"origin" "1064 -576 896"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "888 -80 968"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "512 -80 968"
-"classname" "light"
-}
-{
-"classname" "item_armor2"
-"origin" "1184 -96 920"
-}
-{
-"classname" "monster_ogre"
-"origin" "392 8 912"
-"angle" "315"
-"targetname" "t77"
-"spawnflags" "256"
-}
-{
-"classname" "trigger_once"
-"target" "t77"
-"model" "*45"
-}
-{
-"classname" "item_health"
-"origin" "336 -224 888"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "968 16 888"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "560 2808 516"
-"spawnflags" "1"
-}
-{
-"classname" "path_corner"
-"origin" "1056 -384 824"
-"targetname" "t78"
-"target" "t79"
-"spawnflags" "256"
-}
-{
-"origin" "1056 -736 824"
-"classname" "path_corner"
-"targetname" "t79"
-"target" "t78"
-"spawnflags" "256"
-}
-{
-"classname" "monster_ogre"
-"origin" "1064 -656 840"
-"angle" "90"
-"target" "t78"
-"spawnflags" "257"
-}
-{
-"angle" "90"
-"origin" "848 -880 952"
-"classname" "monster_ogre"
-"targetname" "t72"
-}
-{
-"classname" "item_shells"
-"origin" "1160 16 1248"
-}
-{
-"classname" "item_health"
-"origin" "280 64 1248"
-}
-{
-"classname" "item_rockets"
-"origin" "648 -256 928"
-"spawnflags" "1025"
-}
-{
-"classname" "item_spikes"
-"origin" "648 -304 1248"
-}
-{
-"origin" "696 -304 1248"
-"classname" "item_spikes"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "768 -352 1230"
-}
-{
-"target" "t83"
-"wait" ".8"
-"classname" "trigger_multiple"
-"model" "*46"
-}
-{
-"target" "t83"
-"classname" "trigger_multiple"
-"wait" ".8"
-"model" "*47"
-}
-{
-"target" "t83"
-"wait" ".8"
-"classname" "trigger_multiple"
-"model" "*48"
-}
-{
-"target" "t83"
-"classname" "trigger_multiple"
-"wait" ".8"
-"model" "*49"
-}
-{
-"target" "t83"
-"wait" ".8"
-"classname" "trigger_multiple"
-"model" "*50"
-}
-{
-"targetname" "t83"
-"classname" "trap_spikeshooter"
-"origin" "1108 -576 1140"
-"spawnflags" "1"
-"angle" "180"
-}
-{
-"targetname" "t83"
-"angle" "90"
-"spawnflags" "1"
-"origin" "768 -796 1140"
-"classname" "trap_spikeshooter"
-}
-{
-"origin" "1112 -576 1230"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "768 -800 1230"
-}
-{
-"classname" "light"
-"origin" "712 -756 1168"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "768 -424 1168"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "888 -744 956"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "888 -408 956"
-"light" "175"
-}
-{
-"origin" "384 -224 888"
-"classname" "item_shells"
-}
-{
-"origin" "584 1784 920"
-"classname" "item_health"
-}
-{
-"origin" "832 2064 920"
-"classname" "item_shells"
-}
-{
-"target" "t72"
-"classname" "trigger_once"
-"model" "*51"
-}
-{
-"target" "t85"
-"targetname" "t84"
-"origin" "1560 216 896"
-"classname" "path_corner"
-}
-{
-"target" "t48"
-"targetname" "t85"
-"classname" "path_corner"
-"origin" "1456 216 896"
-}
-{
-"origin" "704 1368 516"
-"classname" "weapon_supernailgun"
-}
-{
-"spawnflags" "1"
-"origin" "184 1928 920"
-"classname" "item_spikes"
-}
-{
-"classname" "item_spikes"
-"origin" "656 1816 528"
-"spawnflags" "768"
-}
-{
-"classname" "item_shells"
-"origin" "1072 -800 820"
-"spawnflags" "1024"
-}
-{
-"classname" "monster_ogre"
-"origin" "840 -40 1276"
-"angle" "180"
-"targetname" "t86"
-"spawnflags" "768"
-}
-{
-"classname" "trigger_once"
-"target" "t86"
-"model" "*52"
-}
-{
-"classname" "light"
-"origin" "472 -576 876"
-"light" "150"
-}
-{
-"classname" "item_shells"
-"origin" "656 680 1256"
-"spawnflags" "1536"
-}
-{
-"angle" "270"
-"origin" "880 2224 536"
-"classname" "monster_knight"
-"spawnflags" "256"
-}
-{
-"angle" "180"
-"origin" "1112 2424 944"
-"classname" "monster_ogre"
-"spawnflags" "1281"
-}
-{
-"targetname" "t88"
-"target" "t87"
-"origin" "360 384 880"
-"classname" "path_corner"
-"spawnflags" "1280"
-}
-{
-"target" "t88"
-"targetname" "t87"
-"classname" "path_corner"
-"origin" "504 160 880"
-"spawnflags" "1280"
-}
-{
-"target" "t87"
-"angle" "315"
-"origin" "384 320 896"
-"classname" "monster_knight"
-"spawnflags" "1280"
-}
-{
-"spawnflags" "257"
-"targetname" "t86"
-"angle" "0"
-"origin" "376 120 1272"
-"classname" "monster_ogre"
-}
-{
-"origin" "776 1368 916"
-"classname" "item_shells"
-"spawnflags" "1024"
-}
-{
-"classname" "item_spikes"
-"origin" "184 1968 920"
-"spawnflags" "1"
-}
-{
-"classname" "monster_wizard"
-"origin" "312 936 944"
-"angle" "45"
-"spawnflags" "769"
-}
-{
-"classname" "monster_knight"
-"origin" "704 -80 908"
-"angle" "90"
-}
-{
-"angle" "0"
-"origin" "568 -56 1276"
-"classname" "monster_ogre"
-"targetname" "t86"
-"spawnflags" "768"
-}
-{
-"spawnflags" "1536"
-"targetname" "t90"
-"target" "t89"
-"origin" "720 1696 924"
-"classname" "path_corner"
-}
-{
-"spawnflags" "1536"
-"target" "t90"
-"targetname" "t89"
-"classname" "path_corner"
-"origin" "720 1416 924"
-}
-{
-"spawnflags" "1537"
-"target" "t90"
-"origin" "704 1784 948"
-"classname" "monster_ogre"
-}
-{
-"classname" "func_door_secret"
-"angle" "0"
-"spawnflags" "1"
-"targetname" "t91"
-"model" "*53"
-}
-{
-"classname" "func_button"
-"angle" "-2"
-"wait" "-1"
-"target" "t92"
-"model" "*54"
-}
-{
-"classname" "func_button"
-"angle" "-2"
-"wait" "-1"
-"target" "t92"
-"model" "*55"
-}
-{
-"classname" "func_button"
-"wait" "-1"
-"angle" "-2"
-"target" "t92"
-"model" "*56"
-}
-{
-"classname" "func_button"
-"angle" "-2"
-"wait" "-1"
-"target" "t92"
-"model" "*57"
-}
-{
-"classname" "func_button"
-"wait" "-1"
-"angle" "-2"
-"target" "t92"
-"model" "*58"
-}
-{
-"classname" "trigger_counter"
-"count" "5"
-"target" "t91"
-"targetname" "t92"
-"model" "*59"
-}
-{
-"classname" "light"
-"origin" "680 -920 1144"
-"light" "150"
-}
-{
-"classname" "item_spikes"
-"origin" "752 -876 928"
-"spawnflags" "1"
-}
-{
-"spawnflags" "3"
-"angle" "0"
-"classname" "func_door_secret"
-"targetname" "t91"
-"model" "*60"
-}
-{
-"light" "150"
-"origin" "680 -256 1144"
-"classname" "light"
-}
-{
-"classname" "trigger_once"
-"spawnflags" "1792"
-"target" "t72"
-"model" "*61"
-}
-{
-"classname" "trigger_secret"
-"sounds" "1"
-"targetname" "t8"
-"model" "*62"
-}
-{
-"angle" "270"
-"origin" "704 624 1280"
-"classname" "monster_knight"
-"spawnflags" "1"
-}
-{
-"angle" "225"
-"origin" "1016 -440 1128"
-"classname" "monster_knight"
-}
-{
-"angle" "180"
-"origin" "1024 -728 1128"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "256"
-"angle" "180"
-"origin" "1008 -568 1128"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "256"
-"classname" "monster_knight"
-"origin" "304 2312 952"
-"angle" "0"
-"targetname" "t29"
-}
-{
-"spawnflags" "1025"
-"classname" "monster_knight"
-"origin" "272 136 896"
-"angle" "45"
-}
-{
-"classname" "monster_wizard"
-"origin" "784 -576 960"
-"angle" "0"
-"target" "t74"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "732 -936 928"
-}
-{
-"origin" "772 -936 928"
-"classname" "item_health"
-}
-{
-"spawnflags" "256"
-"classname" "monster_knight"
-"origin" "704 -248 1272"
-"angle" "0"
-}
-{
-"classname" "path_corner"
-"origin" "1328 928 1396"
-"targetname" "t93"
-"target" "t94"
-"spawnflags" "512"
-}
-{
-"origin" "1176 928 1396"
-"classname" "path_corner"
-"target" "t93"
-"targetname" "t94"
-"spawnflags" "512"
-}
-{
-"classname" "monster_knight"
-"origin" "1192 884 1412"
-"angle" "0"
-"target" "t93"
-"spawnflags" "513"
-}
-{
-"classname" "monster_knight"
-"origin" "704 2376 944"
-"angle" "90"
-}
-{
-"classname" "monster_knight"
-"origin" "888 2312 944"
-"angle" "180"
-"targetname" "t95"
-}
-{
-"angle" "0"
-"origin" "512 2304 944"
-"classname" "monster_knight"
-"targetname" "t95"
-"spawnflags" "768"
-}
-{
-"classname" "trigger_once"
-"target" "t95"
-"model" "*63"
-}
-{
-"spawnflags" "256"
-"angle" "315"
-"origin" "728 2312 536"
-"classname" "monster_knight"
-}
-{
-"light" "200"
-"origin" "1296 1528 936"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1432 1360 982"
-"classname" "light_flame_small_yellow"
-}
-{
-"light" "150"
-"origin" "1400 1360 920"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1248 1344 680"
-"classname" "light"
-}
-{
-"lip" "-384"
-"wait" "-1"
-"angle" "90"
-"classname" "func_door"
-"targetname" "t98"
-"model" "*64"
-}
-{
-"light" "150"
-"origin" "1152 1328 584"
-"classname" "light"
-}
-{
-"origin" "1376 1480 864"
-"classname" "item_health"
-}
-{
-"sounds" "1"
-"classname" "trigger_secret"
-"model" "*65"
-}
-{
-"classname" "func_button"
-"sounds" "1"
-"angle" "0"
-"wait" "-1"
-"target" "t97"
-"model" "*66"
-}
-{
-"classname" "func_button"
-"wait" "-1"
-"angle" "0"
-"sounds" "1"
-"target" "t97"
-"model" "*67"
-}
-{
-"classname" "trigger_counter"
-"targetname" "t97"
-"target" "t98"
-"model" "*68"
-}
-{
-"classname" "light"
-"origin" "880 -888 968"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "880 -264 968"
-"classname" "light"
-}
-{
-"angle" "180"
-"origin" "1112 2344 944"
-"classname" "monster_ogre"
-"spawnflags" "769"
-}
-{
-"angle" "270"
-"origin" "1120 880 1412"
-"classname" "monster_ogre"
-"spawnflags" "257"
-}
-{
-"map" "e1m8"
-"classname" "trigger_changelevel"
-"model" "*69"
-}
-{
-"light" "175"
-"origin" "824 -756 1168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1080 -528 1168"
-"light" "175"
-}
-{
-"classname" "monster_wizard"
-"origin" "672 -392 1024"
-"angle" "315"
-"spawnflags" "257"
-}
-{
-"classname" "monster_knight"
-"origin" "1008 -656 1128"
-"angle" "180"
-"spawnflags" "768"
-}
-{
-"origin" "520 1064 440"
-"classname" "air_bubbles"
-}
-{
-"classname" "item_spikes"
-"origin" "16 1432 892"
-}
-{
-"classname" "trigger_once"
-"message" "A secret cave has opened..."
-"targetname" "t98"
-"model" "*70"
-}
-{
-"target" "t4"
-"health" "1"
-"wait" "-1"
-"angle" "0"
-"classname" "func_button"
-"model" "*71"
-}
-{
-"target" "t2"
-"health" "1"
-"wait" "-1"
-"angle" "180"
-"classname" "func_button"
-"model" "*72"
-}
-{
-"target" "t49"
-"spawnflags" "769"
-"angle" "135"
-"origin" "1208 128 904"
-"classname" "monster_demon1"
-}
-{
-"spawnflags" "769"
-"angle" "45"
-"origin" "288 160 896"
-"classname" "monster_demon1"
-}
-{
-"spawnflags" "768"
-"classname" "monster_ogre"
-"origin" "692 -884 952"
-"angle" "90"
-}
-{
-"classname" "monster_ogre"
-"origin" "-312 1648 1372"
-"angle" "90"
-"targetname" "t23"
-"spawnflags" "768"
-}
-{
-"angle" "90"
-"origin" "-192 1648 1372"
-"classname" "monster_ogre"
-"targetname" "t23"
-"spawnflags" "768"
-}
-{
-"classname" "monster_ogre"
-"origin" "704 1288 540"
-"angle" "270"
-"spawnflags" "768"
-}
-{
-"targetname" "t101"
-"target" "t106"
-"spawnflags" "770"
-"classname" "trigger_teleport"
-"model" "*73"
-}
-{
-"spawnflags" "768"
-"targetname" "t101"
-"angle" "270"
-"origin" "-256 2424 1288"
-"classname" "monster_wizard"
-}
-{
-"targetname" "t101"
-"origin" "-248 2440 1280"
-"classname" "trigger_relay"
-}
-{
-"targetname" "t29"
-"spawnflags" "256"
-"angle" "0"
-"origin" "144 2648 1024"
-"classname" "monster_wizard"
-}
-{
-"targetname" "t29"
-"spawnflags" "768"
-"classname" "monster_wizard"
-"origin" "144 2592 1024"
-"angle" "0"
-}
-{
-"targetname" "t29"
-"spawnflags" "768"
-"angle" "0"
-"origin" "144 2536 1024"
-"classname" "monster_wizard"
-}
-{
-"targetname" "t29"
-"target" "t102"
-"spawnflags" "258"
-"classname" "trigger_teleport"
-"model" "*74"
-}
-{
-"targetname" "t29"
-"target" "t103"
-"spawnflags" "770"
-"classname" "trigger_teleport"
-"model" "*75"
-}
-{
-"targetname" "t29"
-"target" "t104"
-"spawnflags" "770"
-"classname" "trigger_teleport"
-"model" "*76"
-}
-{
-"angle" "270"
-"targetname" "t102"
-"spawnflags" "256"
-"origin" "704 2656 1008"
-"classname" "info_teleport_destination"
-}
-{
-"angle" "270"
-"targetname" "t103"
-"spawnflags" "768"
-"classname" "info_teleport_destination"
-"origin" "920 2520 1008"
-}
-{
-"angle" "0"
-"targetname" "t104"
-"spawnflags" "768"
-"origin" "592 2192 1008"
-"classname" "info_teleport_destination"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"angle" "0"
-"wait" "-1"
-"speed" "150"
-"targetname" "t105"
-"model" "*77"
-}
-{
-"classname" "monster_demon1"
-"origin" "1056 -880 1128"
-"angle" "90"
-"spawnflags" "768"
-"targetname" "t105"
-}
-{
-"classname" "trigger_once"
-"spawnflags" "768"
-"target" "t105"
-"model" "*78"
-}
-{
-"classname" "light"
-"origin" "1056 -920 1184"
-"light" "125"
-}
-{
-"classname" "trigger_relay"
-"origin" "1104 -864 1120"
-"target" "t105"
-}
-{
-"classname" "monster_ogre"
-"origin" "1120 768 1416"
-"angle" "180"
-"spawnflags" "769"
-}
-{
-"classname" "air_bubbles"
-"origin" "884 1616 440"
-}
-{
-"targetname" "t106"
-"spawnflags" "768"
-"angle" "270"
-"origin" "-264 2232 1296"
-"classname" "info_teleport_destination"
-}
-{
-"classname" "path_corner"
-"origin" "568 1984 928"
-"targetname" "t107"
-"target" "t108"
-"spawnflags" "256"
-}
-{
-"origin" "424 1960 928"
-"classname" "path_corner"
-"target" "t107"
-"spawnflags" "256"
-"targetname" "t111"
-}
-{
-"classname" "path_corner"
-"origin" "704 2024 928"
-"targetname" "t108"
-"target" "t109"
-"spawnflags" "256"
-}
-{
-"origin" "712 1712 928"
-"classname" "path_corner"
-"targetname" "t109"
-"target" "t110"
-"spawnflags" "256"
-}
-{
-"classname" "path_corner"
-"origin" "712 1416 928"
-"targetname" "t110"
-"target" "t109"
-"spawnflags" "256"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"wait" "-1"
-"lip" "-24"
-"targetname" "t26"
-"spawnflags" "2304"
-"model" "*79"
-}
-{
-"classname" "monster_ogre"
-"origin" "240 2048 944"
-"angle" "0"
-"spawnflags" "257"
-"target" "t111"
-}
-{
-"target" "t23"
-"spawnflags" "1792"
-"classname" "trigger_once"
-"model" "*80"
-}
-{
-"classname" "monster_knight"
-"origin" "576 2768 536"
-"angle" "0"
-"spawnflags" "256"
-}
-{
-"spawnflags" "256"
-"angle" "180"
-"origin" "824 2776 536"
-"classname" "monster_knight"
-}
-{
-"classname" "monster_wizard"
-"origin" "704 -1032 1024"
-"angle" "90"
-"spawnflags" "256"
-"targetname" "t52"
-}
-{
-"angle" "90"
-"origin" "760 -1032 1024"
-"classname" "monster_wizard"
-"spawnflags" "768"
-"targetname" "t114"
-}
-{
-"classname" "monster_wizard"
-"origin" "816 -1032 1024"
-"angle" "90"
-"spawnflags" "768"
-"targetname" "t114"
-}
-{
-"targetname" "t52"
-"classname" "trigger_teleport"
-"spawnflags" "258"
-"target" "t112"
-"model" "*81"
-}
-{
-"classname" "trigger_teleport"
-"spawnflags" "770"
-"target" "t113"
-"targetname" "t114"
-"model" "*82"
-}
-{
-"targetname" "t114"
-"classname" "trigger_teleport"
-"spawnflags" "770"
-"target" "t115"
-"model" "*83"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "896 224 1352"
-"angle" "135"
-"spawnflags" "256"
-"targetname" "t112"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "488 1648 1016"
-"angle" "315"
-"spawnflags" "768"
-"targetname" "t113"
-}
-{
-"classname" "trigger_once"
-"spawnflags" "768"
-"target" "t114"
-"model" "*84"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "800 904 928"
-"angle" "90"
-"spawnflags" "768"
-"targetname" "t115"
-}
-{
-"angle" "270"
-"origin" "-256 2232 1242"
-"classname" "info_player_deathmatch"
-}
-{
-"spawnflags" "1792"
-"origin" "-256 2096 1218"
-"classname" "weapon_supershotgun"
-}
-{
-"angle" "270"
-"origin" "704 424 1266"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "270"
-"origin" "704 2488 946"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "270"
-"origin" "704 1968 546"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "90"
-"origin" "704 104 898"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "270"
-"origin" "704 1568 938"
-"classname" "info_player_deathmatch"
-}
-{
-"spawnflags" "1792"
-"origin" "704 1344 912"
-"classname" "weapon_rocketlauncher"
-}
-{
-"angle" "0"
-"origin" "712 -576 840"
-"classname" "info_player_deathmatch"
-}
-{
-"spawnflags" "1792"
-"origin" "944 -576 816"
-"classname" "weapon_nailgun"
-}
-{
-"angle" "180"
-"origin" "1064 -576 1128"
-"classname" "info_player_deathmatch"
-}
-{
-"spawnflags" "1792"
-"origin" "696 584 1256"
-"classname" "weapon_grenadelauncher"
-}
-{
-"classname" "light"
-"origin" "316 804 780"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "316 804 644"
-"light" "75"
-}
-{
-"classname" "item_rockets"
-"origin" "298 710 706"
-"spawnflags" "1"
-}
-{
-"classname" "item_shells"
-"origin" "988 -928 1104"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "-56 2112 1220"
-"spawnflags" "3584"
-}
-{
-"classname" "item_health"
-"origin" "-56 2072 1220"
-"spawnflags" "2305"
-}
-{
-"spawnflags" "1"
-"origin" "584 2416 512"
-"classname" "item_spikes"
-}
-{
-"origin" "688 1392 516"
-"classname" "item_spikes"
-}
-{
-"classname" "item_artifact_invulnerability"
-"origin" "712 2312 948"
-"spawnflags" "1792"
-}
-{
-"origin" "32 1392 916"
-"classname" "item_artifact_envirosuit"
-}
-{
-"mangle" "26 310 0"
-"origin" "384 488 1552"
-"classname" "info_intermission"
-}
-{
-"light" "100"
-"origin" "800 1160 464"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "608 1160 464"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "604 1472 464"
-"classname" "light"
-}
-{
-"target" "t40"
-"classname" "trigger_teleport"
-"model" "*85"
-}
-{
-"mangle" "-20 75 0"
-"origin" "456 2144 568"
-"classname" "info_intermission"
-}
-{
-"mangle" "10 80 0"
-"origin" "464 1032 1000"
-"classname" "info_intermission"
-}
-{
-"mangle" "20 135 0"
-"origin" "1080 -752 1008"
-"classname" "info_intermission"
-}
-{
-"classname" "trigger_secret"
-"model" "*86"
-}
-{
-"classname" "path_corner"
-"origin" "1632 216 896"
-"targetname" "t116"
-"target" "t84"
-}
-{
-"classname" "item_spikes"
-"origin" "1200 48 872"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "928 2664 320"
-"spawnflags" "1"
-}
-{
-"classname" "item_shells"
-"origin" "1240 768 1384"
-"spawnflags" "1"
-}
-{
-"classname" "item_shells"
-"origin" "-88 2160 1224"
-"spawnflags" "2049"
-}
-{
-"classname" "info_player_coop"
-"origin" "-208 2272 1240"
-"angle" "270"
-}
-{
-"angle" "270"
-"origin" "-304 2272 1240"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "-352 2272 1240"
-"angle" "270"
-}
-{
-"light" "200"
-"origin" "1288 1648 956"
-"classname" "light"
-}
-{
-"classname" "item_spikes"
-"origin" "-264 1464 888"
-}
-{
-"spawnflags" "1792"
-"origin" "1296 1488 888"
-"classname" "item_artifact_invisibility"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*87"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*88"
-}
-{
-"target" "t118"
-"targetname" "t117"
-"origin" "-176 1640 888"
-"classname" "path_corner"
-}
-{
-"targetname" "t118"
-"target" "t117"
-"classname" "path_corner"
-"origin" "-320 1640 888"
-}
-{
-"target" "t117"
-"origin" "-256 1632 904"
-"classname" "monster_knight"
-"spawnflags" "1"
-}
-{
-"origin" "1376 1424 864"
-"classname" "weapon_grenadelauncher"
-}
-{
-"spawnflags" "1"
-"targetname" "t120"
-"target" "t119"
-"classname" "trigger_counter"
-"model" "*89"
-}
-{
-"target" "t120"
-"targetname" "t53"
-"classname" "trigger_once"
-"model" "*90"
-}
-{
-"target" "t120"
-"targetname" "t39"
-"classname" "trigger_once"
-"model" "*91"
-}
-{
-"classname" "light"
-"origin" "480 2568 568"
-"light" "125"
-}
-{
-"origin" "162 1482 976"
-"classname" "ambient_drip"
-}
-{
-"origin" "786 1010 584"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "778 1210 584"
-}
-{
-"origin" "594 1202 584"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "602 1010 584"
-}
-{
-"origin" "786 1514 584"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "794 1698 584"
-}
-{
-"origin" "618 1690 584"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "618 1522 584"
-}
-{
-"origin" "698 1362 584"
-"classname" "ambient_drip"
-}
-{
-"origin" "714 1970 592"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "898 2170 592"
-}
-{
-"origin" "938 2346 592"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "682 2298 592"
-}
-{
-"origin" "458 2306 592"
-"classname" "ambient_drip"
-}
-{
-"origin" "458 1690 880"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "322 1506 880"
-}
-{
-"origin" "338 1226 880"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "466 1090 880"
-}
-{
-"origin" "394 882 880"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "674 810 880"
-}
-{
-"origin" "914 818 880"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "922 1034 880"
-}
-{
-"origin" "1082 1266 880"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "994 1442 880"
-}
-{
-"origin" "898 1714 880"
-"classname" "ambient_drip"
-}
-{
-"origin" "706 1362 1080"
-"classname" "ambient_drip"
-}
-{
-"origin" "1194 1522 1032"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "1314 1354 1032"
-}
-{
-"origin" "442 354 920"
-"classname" "ambient_swamp1"
-}
-{
-"origin" "978 314 920"
-"classname" "ambient_swamp2"
-}
diff --git a/Misc/pak/maps/e2m2.diff b/Misc/pak/maps/e2m2.diff
new file mode 100644
index 000000000..4dbf2dc5b
--- /dev/null
+++ b/Misc/pak/maps/e2m2.diff
@@ -0,0 +1,54 @@
+--- e2m2.ent
++++ e2m2@fbfe.ent
+@@ -908,20 +908,21 @@
+ {
+ "classname" "func_door"
+ "angle" "-2"
+ "spawnflags" "33"
+ "speed" "10"
+ "sounds" "3"
+ "wait" "-1"
+ "targetname" "t16"
+ "dmg" "100"
+ "model" "*13"
++"lip" "7" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "sounds" "3"
+ "classname" "func_door"
+ "angle" "90"
+ "spawnflags" "2056"
+ "wait" "-1"
+ "model" "*14"
+ }
+ {
+@@ -1423,27 +1424,27 @@
+ {
+ "target" "t39"
+ "targetname" "t40"
+ "origin" "-216 280 104"
+ "classname" "path_corner"
+ }
+ {
+ "target" "t40"
+ "targetname" "t38"
+ "classname" "path_corner"
+-"origin" "-16 280 104"
++"origin" "-15 280 104" // svdijk -- changed to prevent z-fighting (was "-16 280 104")
+ }
+ {
+ "target" "t38"
+ "wait" "-1"
+ "targetname" "t39"
+-"origin" "-16 280 104"
++"origin" "-15 280 104" // svdijk -- changed to prevent z-fighting (was "-16 280 104")
+ "classname" "path_corner"
+ }
+ {
+ "angle" "180"
+ "origin" "680 1472 24"
+ "classname" "monster_ogre"
+ "spawnflags" "256"
+ }
+ {
+ "spawnflags" "256"
diff --git a/Misc/pak/maps/e2m2.ent.orig b/Misc/pak/maps/e2m2.ent.orig
deleted file mode 100644
index 1a92a2471..000000000
--- a/Misc/pak/maps/e2m2.ent.orig
+++ /dev/null
@@ -1,2004 +0,0 @@
-{
-"message" "the Ogre Citadel"
-"sounds" "8"
-"wad" "gfx/wizard.wad"
-"classname" "worldspawn"
-"worldtype" "0"
-}
-{
-"origin" "160 -160 120"
-"classname" "light"
-}
-{
-"angle" "90"
-"origin" "-256 -1952 280"
-"classname" "info_player_start"
-}
-{
-"classname" "light"
-"origin" "160 -392 248"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "160 -648 184"
-}
-{
-"classname" "light"
-"origin" "-56 -392 248"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "376 -392 248"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "288 -416 -72"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "32 -416 -72"
-"light" "200"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "10 -270 148"
-"light" "250"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "314 -270 148"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-264 -440 248"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "584 -440 248"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "544 -648 248"
-}
-{
-"light" "150"
-"origin" "648 -456 -184"
-"classname" "light"
-}
-{
-"origin" "376 -800 184"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-152 -752 184"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-232 -592 184"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "160 112 184"
-}
-{
-"classname" "light"
-"origin" "160 352 120"
-}
-{
-"classname" "light"
-"origin" "160 216 -48"
-"light" "120"
-}
-{
-"classname" "light"
-"origin" "160 16 -48"
-"light" "120"
-}
-{
-"classname" "light"
-"origin" "160 544 144"
-"light" "225"
-}
-{
-"classname" "light"
-"origin" "480 576 88"
-}
-{
-"classname" "light"
-"origin" "480 448 88"
-}
-{
-"classname" "light"
-"origin" "480 576 168"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "480 448 168"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "160 896 312"
-"light" "350"
-}
-{
-"classname" "light"
-"origin" "288 896 312"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "32 896 312"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "160 1008 312"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "160 784 312"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "392 120 184"
-"light" "350"
-}
-{
-"classname" "light"
-"origin" "568 208 184"
-"light" "350"
-}
-{
-"classname" "light"
-"origin" "720 480 184"
-}
-{
-"classname" "light"
-"origin" "640 632 184"
-}
-{
-"classname" "light"
-"origin" "472 1152 56"
-}
-{
-"classname" "light"
-"origin" "512 896 152"
-}
-{
-"origin" "800 800 184"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "632 1264 -40"
-"classname" "light"
-}
-{
-"origin" "800 1032 184"
-"classname" "light"
-}
-{
-"origin" "760 1472 64"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "544 1416 56"
-"classname" "light"
-}
-{
-"origin" "672 1256 184"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1024 1272 184"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "992 1440 184"
-"classname" "light"
-}
-{
-"origin" "1240 488 184"
-"classname" "light"
-}
-{
-"origin" "1280 136 176"
-"classname" "light"
-}
-{
-"origin" "160 1304 136"
-"classname" "light"
-}
-{
-"origin" "160 1648 256"
-"classname" "light"
-"light" "200"
-}
-{
-"origin" "240 1600 256"
-"classname" "light"
-"light" "200"
-}
-{
-"origin" "16 1616 168"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-120 1304 40"
-"classname" "light"
-}
-{
-"origin" "-352 1144 16"
-"classname" "light"
-"light" "250"
-}
-{
-"origin" "-56 1096 64"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-56 1152 280"
-"classname" "light"
-}
-{
-"light" "350"
-"origin" "-440 1144 200"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-352 1336 -72"
-"classname" "light"
-}
-{
-"origin" "-488 368 56"
-"classname" "light"
-"light" "250"
-}
-{
-"light" "350"
-"origin" "-488 896 136"
-"classname" "light"
-}
-{
-"origin" "-216 896 184"
-"classname" "light"
-"light" "250"
-}
-{
-"origin" "-128 536 168"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "-104 480 32"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-208 936 56"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-208 736 32"
-"classname" "light"
-}
-{
-"origin" "-344 64 184"
-"classname" "light"
-}
-{
-"light" "350"
-"origin" "-648 384 184"
-"classname" "light"
-}
-{
-"light" "350"
-"origin" "-488 688 184"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-680 496 -36"
-"classname" "light"
-}
-{
-"light" "350"
-"origin" "-600 1104 96"
-"classname" "light"
-}
-{
-"origin" "-824 896 168"
-"classname" "light"
-}
-{
-"origin" "-896 600 160"
-"classname" "light"
-}
-{
-"target" "t1"
-"classname" "trigger_teleport"
-"model" "*1"
-}
-{
-"spawnflags" "1792"
-"targetname" "t1"
-"origin" "-448 264 -56"
-"classname" "info_teleport_destination"
-"angle" "45"
-}
-{
-"light" "250"
-"origin" "-168 1320 160"
-"classname" "light"
-}
-{
-"origin" "-24 896 184"
-"classname" "light"
-}
-{
-"origin" "-104 896 184"
-"classname" "light"
-"light" "250"
-}
-{
-"spawnflags" "2"
-"origin" "-680 880 48"
-"classname" "item_health"
-}
-{
-"angle" "90"
-"origin" "-896 512 24"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "90"
-"origin" "-184 560 128"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "270"
-"origin" "160 1640 160"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "90"
-"origin" "1272 112 80"
-"classname" "info_player_deathmatch"
-}
-{
-"angle" "90"
-"origin" "176 -784 24"
-"classname" "info_player_deathmatch"
-}
-{
-"spawnflags" "1"
-"origin" "208 -160 0"
-"classname" "item_rockets"
-}
-{
-"origin" "64 464 0"
-"classname" "item_health"
-}
-{
-"origin" "120 464 0"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "-8 840 64"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "-8 952 64"
-"classname" "item_health"
-}
-{
-"spawnflags" "9"
-"origin" "568 880 0"
-"classname" "item_weapon"
-}
-{
-"origin" "456 1104 -88"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "664 1272 -88"
-"classname" "item_shells"
-}
-{
-"angle" "225"
-"origin" "888 1312 120"
-"classname" "info_player_deathmatch"
-}
-{
-"origin" "1328 168 56"
-"classname" "item_health"
-}
-{
-"origin" "1328 128 56"
-"classname" "item_health"
-}
-{
-"origin" "1328 208 56"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "816 1472 0"
-"classname" "item_shells"
-}
-{
-"light" "200"
-"origin" "-64 -120 -56"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-296 -160 -56"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-296 -208 -272"
-"classname" "light"
-}
-{
-"classname" "func_plat"
-"model" "*2"
-}
-{
-"spawnflags" "2"
-"origin" "-192 -176 -80"
-"classname" "item_health"
-}
-{
-"light" "350"
-"origin" "-816 128 184"
-"classname" "light"
-}
-{
-"light" "350"
-"origin" "-664 -80 184"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "-656 112 32"
-"classname" "light"
-}
-{
-"origin" "-352 208 56"
-"classname" "light"
-"light" "250"
-}
-{
-"origin" "-184 504 24"
-"classname" "light"
-"light" "250"
-}
-{
-"classname" "item_armor1"
-"origin" "400 -888 0"
-}
-{
-"spawnflags" "1792"
-"classname" "item_armorInv"
-"origin" "-104 448 104"
-}
-{
-"classname" "item_armor2"
-"origin" "-680 496 32"
-}
-{
-"classname" "weapon_grenadelauncher"
-"origin" "168 1608 136"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_rocketlauncher"
-"origin" "1232 176 56"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_supernailgun"
-"origin" "-960 944 40"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_supershotgun"
-"origin" "752 1464 0"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_nailgun"
-"origin" "160 120 24"
-"spawnflags" "1792"
-}
-{
-"classname" "item_rockets"
-"origin" "-224 792 104"
-"spawnflags" "1792"
-}
-{
-"classname" "item_rockets"
-"origin" "-640 120 -56"
-"spawnflags" "1792"
-}
-{
-"light" "200"
-"origin" "-70 -1126 212"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "200"
-"classname" "light_torch_small_walltorch"
-"origin" "186 -1134 148"
-}
-{
-"light" "200"
-"origin" "138 -966 100"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "200"
-"classname" "light_torch_small_walltorch"
-"origin" "-150 -1318 260"
-}
-{
-"light" "150"
-"origin" "184 -880 72"
-"classname" "light"
-}
-{
-"style" "6"
-"light" "200"
-"origin" "-46 -1742 340"
-"classname" "light_torch_small_walltorch"
-}
-{
-"style" "1"
-"light" "200"
-"classname" "light_torch_small_walltorch"
-"origin" "-486 -1726 340"
-}
-{
-"origin" "-272 -1544 384"
-"classname" "light"
-"light" "200"
-}
-{
-"style" "6"
-"light" "200"
-"classname" "light_torch_small_walltorch"
-"origin" "-414 -2006 340"
-}
-{
-"style" "1"
-"light" "200"
-"origin" "-134 -1958 340"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "150"
-"origin" "-472 -1840 328"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-72 -1592 328"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-320 -1424 264"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-256 -1952 280"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "-272 -1720 312"
-}
-{
-"origin" "-232 -1280 168"
-"classname" "path_corner"
-"targetname" "t5"
-"target" "t6"
-}
-{
-"classname" "path_corner"
-"origin" "-64 -1176 120"
-"targetname" "t6"
-"target" "t7"
-}
-{
-"origin" "152 -1104 56"
-"classname" "path_corner"
-"targetname" "t7"
-"target" "t8"
-}
-{
-"classname" "path_corner"
-"origin" "192 -952 8"
-"targetname" "t8"
-"target" "t9"
-}
-{
-"origin" "184 -808 8"
-"classname" "path_corner"
-"target" "t3"
-"targetname" "t9"
-}
-{
-"classname" "path_corner"
-"origin" "512 -776 8"
-"targetname" "t3"
-"target" "t10"
-}
-{
-"origin" "-200 -648 8"
-"classname" "path_corner"
-"targetname" "t4"
-"target" "t11"
-}
-{
-"classname" "monster_knight"
-"origin" "-360 -1616 232"
-"target" "t5"
-"angle" "90"
-}
-{
-"origin" "512 -648 8"
-"classname" "path_corner"
-"targetname" "t10"
-"target" "t4"
-}
-{
-"classname" "path_corner"
-"origin" "-200 -776 8"
-"targetname" "t11"
-"target" "t3"
-}
-{
-"classname" "monster_knight"
-"origin" "24 -632 24"
-"spawnflags" "256"
-"target" "t4"
-}
-{
-"classname" "monster_knight"
-"origin" "336 -752 24"
-"spawnflags" "256"
-"target" "t3"
-}
-{
-"classname" "monster_knight"
-"origin" "56 -712 24"
-"angle" "270"
-"spawnflags" "768"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "160 -712 24"
-"classname" "monster_knight"
-}
-{
-"classname" "monster_knight"
-"origin" "264 -712 24"
-"angle" "270"
-"spawnflags" "768"
-}
-{
-"classname" "item_health"
-"origin" "-432 -1640 208"
-"spawnflags" "1"
-}
-{
-"classname" "item_shells"
-"origin" "-352 -592 0"
-}
-{
-"classname" "func_door"
-"angle" "90"
-"spawnflags" "1"
-"targetname" "t13"
-"wait" "-1"
-"sounds" "3"
-"dmg" "100"
-"model" "*3"
-}
-{
-"health" "1"
-"angle" "90"
-"classname" "func_button"
-"target" "t12"
-"wait" "-1"
-"sounds" "1"
-"model" "*4"
-}
-{
-"classname" "func_button"
-"angle" "90"
-"health" "1"
-"target" "t12"
-"wait" "-1"
-"sounds" "1"
-"model" "*5"
-}
-{
-"classname" "trigger_counter"
-"targetname" "t12"
-"count" "2"
-"target" "t13"
-"model" "*6"
-}
-{
-"classname" "monster_demon1"
-"origin" "160 -128 24"
-"angle" "270"
-"targetname" "t12"
-}
-{
-"classname" "light"
-"origin" "-8 -288 64"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "328 -288 64"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-296 -448 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "160 -368 -248"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "616 -448 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "408 -456 -248"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-40 -424 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-280 -448 32"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "632 -424 32"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "160 -480 8"
-"light" "150"
-}
-{
-"classname" "func_door"
-"angle" "180"
-"targetname" "t12"
-"sounds" "3"
-"speed" "200"
-"wait" "-1"
-"lip" "-2"
-"model" "*7"
-}
-{
-"classname" "func_door"
-"angle" "0"
-"speed" "200"
-"wait" "-1"
-"lip" "-2"
-"model" "*8"
-}
-{
-"classname" "light"
-"origin" "160 -304 112"
-"light" "170"
-}
-{
-"classname" "light"
-"origin" "160 640 104"
-"light" "200"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"targetname" "t14"
-"sounds" "1"
-"model" "*9"
-}
-{
-"classname" "trigger_multiple"
-"target" "t14"
-"wait" "10"
-"model" "*10"
-}
-{
-"targetname" "t28"
-"classname" "func_door"
-"angle" "-1"
-"wait" "-1"
-"sounds" "1"
-"speed" "200"
-"spawnflags" "2048"
-"model" "*11"
-}
-{
-"angle" "270"
-"classname" "func_button"
-"target" "t15"
-"wait" "-1"
-"lip" "2"
-"sounds" "1"
-"spawnflags" "2048"
-"model" "*12"
-}
-{
-"classname" "light"
-"origin" "-296 432 0"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-312 416 152"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-184 320 146"
-"light" "200"
-}
-{
-"classname" "item_key2"
-"origin" "-552 192 -40"
-"sounds" "1"
-"spawnflags" "2048"
-}
-{
-"classname" "item_spikes"
-"origin" "-680 88 -48"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "33"
-"speed" "10"
-"sounds" "3"
-"wait" "-1"
-"targetname" "t16"
-"dmg" "100"
-"model" "*13"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"angle" "90"
-"spawnflags" "2056"
-"wait" "-1"
-"model" "*14"
-}
-{
-"spawnflags" "2056"
-"angle" "270"
-"classname" "func_door"
-"wait" "-1"
-"model" "*15"
-}
-{
-"classname" "func_button"
-"angle" "-2"
-"wait" "-1"
-"target" "t16"
-"lip" "12"
-"model" "*16"
-}
-{
-"classname" "light"
-"origin" "888 1080 -104"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "888 888 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "880 696 -104"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "696 888 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "696 1080 -104"
-"light" "160"
-}
-{
-"light" "200"
-"origin" "696 672 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "568 512 -104"
-"light" "200"
-}
-{
-"light" "160"
-"origin" "840 504 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "832 328 -104"
-"light" "160"
-}
-{
-"classname" "light"
-"origin" "936 512 96"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "-248 1080 56"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "888 1264 176"
-"light" "170"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"targetname" "t17"
-"sounds" "1"
-"model" "*17"
-}
-{
-"classname" "trigger_multiple"
-"target" "t17"
-"wait" "5"
-"model" "*18"
-}
-{
-"classname" "light"
-"origin" "160 120 -24"
-"light" "160"
-}
-{
-"spawnflags" "256"
-"classname" "trigger_multiple"
-"target" "t18"
-"targetname" "t23"
-"model" "*19"
-}
-{
-"wait" "0.5"
-"classname" "trap_spikeshooter"
-"origin" "88 368 40"
-"angle" "0"
-"targetname" "t18"
-}
-{
-"classname" "func_wall"
-"spawnflags" "2048"
-"model" "*20"
-}
-{
-"classname" "monster_demon1"
-"origin" "-160 608 128"
-"targetname" "t19"
-}
-{
-"classname" "trigger_once"
-"target" "t19"
-"model" "*21"
-}
-{
-"classname" "light"
-"origin" "-528 512 -104"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-344 592 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-336 760 -104"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-432 856 -104"
-"classname" "light"
-}
-{
-"classname" "monster_ogre"
-"origin" "-416 440 -40"
-"spawnflags" "1536"
-"target" "t20"
-}
-{
-"classname" "monster_shambler"
-"origin" "-272 296 -40"
-"spawnflags" "256"
-"target" "t20"
-}
-{
-"classname" "path_corner"
-"origin" "-328 272 -56"
-"targetname" "t20"
-"target" "t21"
-}
-{
-"origin" "-400 480 -56"
-"classname" "path_corner"
-"target" "t20"
-"targetname" "t21"
-}
-{
-"classname" "item_health"
-"origin" "-600 144 -64"
-}
-{
-"classname" "weapon_supershotgun"
-"origin" "440 512 0"
-"spawnflags" "2048"
-}
-{
-"classname" "light"
-"origin" "-120 176 184"
-"light" "250"
-}
-{
-"origin" "-96 0 184"
-"classname" "light"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "312 116 -48"
-"light" "200"
-}
-{
-"classname" "path_corner"
-"origin" "8 112 32"
-"target" "t25"
-"targetname" "t24"
-}
-{
-"origin" "312 112 32"
-"classname" "path_corner"
-"targetname" "t25"
-"target" "t24"
-}
-{
-"classname" "monster_ogre"
-"origin" "112 112 48"
-"target" "t24"
-"spawnflags" "256"
-}
-{
-"classname" "item_shells"
-"origin" "88 -160 0"
-"spawnflags" "1"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "-352 144 56"
-}
-{
-"classname" "monster_demon1"
-"origin" "-80 -440 -296"
-"spawnflags" "256"
-"target" "t26"
-}
-{
-"classname" "path_corner"
-"origin" "-216 -456 -312"
-"targetname" "t26"
-"target" "t27"
-}
-{
-"origin" "536 -448 -312"
-"classname" "path_corner"
-"target" "t26"
-"targetname" "t27"
-}
-{
-"light" "200"
-"origin" "320 232 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "312 0 -104"
-"light" "200"
-}
-{
-"light" "160"
-"origin" "-8 0 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-8 232 -104"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-16 112 -104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-248 -8 -104"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-472 120 -104"
-"classname" "light"
-}
-{
-"wait" "-1"
-"classname" "func_door"
-"angle" "-1"
-"targetname" "t15"
-"sounds" "1"
-"spawnflags" "2048"
-"model" "*22"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "2081"
-"targetname" "t28"
-"wait" "10"
-"speed" "200"
-"sounds" "1"
-"model" "*23"
-}
-{
-"classname" "trigger_once"
-"target" "t28"
-"model" "*24"
-}
-{
-"classname" "trigger_once"
-"target" "t12"
-"model" "*25"
-}
-{
-"classname" "monster_ogre"
-"origin" "160 1432 128"
-"angle" "270"
-}
-{
-"classname" "monster_ogre"
-"origin" "-216 784 128"
-"angle" "90"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "-360 888 24"
-"spawnflags" "2048"
-"targetname" "t1"
-}
-{
-"classname" "monster_zombie"
-"origin" "-288 -232 -296"
-"angle" "270"
-}
-{
-"classname" "monster_zombie"
-"origin" "168 -8 -104"
-"angle" "90"
-}
-{
-"classname" "monster_ogre"
-"origin" "648 1232 -64"
-"angle" "180"
-}
-{
-"sounds" "1"
-"classname" "func_door"
-"angle" "-2"
-"targetname" "t29"
-"model" "*26"
-}
-{
-"classname" "monster_ogre"
-"origin" "520 752 24"
-"angle" "90"
-"spawnflags" "256"
-"targetname" "t29"
-}
-{
-"classname" "trigger_once"
-"target" "t29"
-"model" "*27"
-}
-{
-"classname" "weapon_nailgun"
-"origin" "152 1608 136"
-"spawnflags" "2048"
-}
-{
-"classname" "path_corner"
-"origin" "544 896 8"
-"targetname" "t30"
-"target" "t31"
-}
-{
-"origin" "56 896 72"
-"classname" "path_corner"
-"target" "t30"
-"targetname" "t31"
-}
-{
-"classname" "path_corner"
-"origin" "168 552 8"
-"targetname" "t32"
-"target" "t33"
-}
-{
-"origin" "168 1392 8"
-"classname" "path_corner"
-"target" "t32"
-"targetname" "t33"
-}
-{
-"classname" "monster_knight"
-"origin" "240 584 24"
-"target" "t32"
-}
-{
-"classname" "monster_knight"
-"origin" "504 960 24"
-"target" "t30"
-"spawnflags" "256"
-}
-{
-"classname" "monster_knight"
-"origin" "-16 896 88"
-"angle" "0"
-}
-{
-"classname" "monster_knight"
-"origin" "256 1224 24"
-"angle" "225"
-"spawnflags" "256"
-}
-{
-"target" "t49"
-"origin" "-24 1064 16"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "256"
-"angle" "45"
-"origin" "-184 1080 128"
-"classname" "monster_ogre"
-}
-{
-"angle" "45"
-"origin" "-256 1216 128"
-"classname" "monster_knight"
-}
-{
-"targetname" "t16"
-"angle" "270"
-"origin" "784 520 56"
-"classname" "monster_demon1"
-}
-{
-"classname" "path_corner"
-"origin" "-352 888 16"
-"targetname" "t34"
-"target" "t35"
-}
-{
-"origin" "-120 888 8"
-"classname" "path_corner"
-"target" "t34"
-"targetname" "t35"
-}
-{
-"classname" "monster_ogre"
-"origin" "-184 912 24"
-"target" "t34"
-"spawnflags" "256"
-}
-{
-"classname" "monster_ogre"
-"origin" "-720 896 64"
-}
-{
-"classname" "monster_knight"
-"origin" "-344 760 24"
-"angle" "135"
-"spawnflags" "256"
-}
-{
-"classname" "monster_knight"
-"origin" "-392 584 24"
-"angle" "90"
-"spawnflags" "256"
-}
-{
-"angle" "90"
-"classname" "monster_knight"
-"origin" "-528 528 24"
-"spawnflags" "768"
-}
-{
-"targetname" "t37"
-"target" "t36"
-"origin" "-896 968 48"
-"classname" "path_corner"
-}
-{
-"target" "t37"
-"targetname" "t36"
-"classname" "path_corner"
-"origin" "-896 568 48"
-}
-{
-"spawnflags" "256"
-"target" "t36"
-"origin" "-840 600 24"
-"classname" "monster_ogre"
-}
-{
-"style" "32"
-"targetname" "t15"
-"light" "200"
-"origin" "-56 304 152"
-"classname" "light"
-}
-{
-"dmg" "100"
-"speed" "200"
-"targetname" "t15"
-"target" "t38"
-"classname" "func_train"
-"model" "*28"
-}
-{
-"target" "t39"
-"targetname" "t40"
-"origin" "-216 280 104"
-"classname" "path_corner"
-}
-{
-"target" "t40"
-"targetname" "t38"
-"classname" "path_corner"
-"origin" "-16 280 104"
-}
-{
-"target" "t38"
-"wait" "-1"
-"targetname" "t39"
-"origin" "-16 280 104"
-"classname" "path_corner"
-}
-{
-"angle" "180"
-"origin" "680 1472 24"
-"classname" "monster_ogre"
-"spawnflags" "256"
-}
-{
-"spawnflags" "256"
-"angle" "180"
-"origin" "864 1448 24"
-"classname" "monster_knight"
-}
-{
-"target" "t42"
-"targetname" "t41"
-"origin" "1024 1264 104"
-"classname" "path_corner"
-}
-{
-"targetname" "t42"
-"target" "t41"
-"classname" "path_corner"
-"origin" "704 1264 104"
-}
-{
-"target" "t41"
-"origin" "1056 1320 120"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "257"
-"origin" "552 1280 128"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "1"
-"origin" "432 1280 128"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "2048"
-"angle" "0"
-"wait" "-1"
-"sounds" "0"
-"health" "1"
-"target" "t28"
-"classname" "func_button"
-"model" "*29"
-}
-{
-"origin" "-72 296 104"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "-64 504 104"
-}
-{
-"origin" "-312 192 -64"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "-80 384 -64"
-"classname" "item_spikes"
-}
-{
-"origin" "-224 976 104"
-"classname" "item_shells"
-}
-{
-"target" "t666"
-"classname" "trigger_multiple"
-"wait" "10"
-"model" "*30"
-}
-{
-"target" "t45"
-"targetname" "t44"
-"origin" "984 568 8"
-"classname" "path_corner"
-}
-{
-"target" "t46"
-"targetname" "t45"
-"classname" "path_corner"
-"origin" "976 464 8"
-}
-{
-"target" "t47"
-"targetname" "t46"
-"origin" "1224 448 40"
-"classname" "path_corner"
-}
-{
-"target" "t44"
-"targetname" "t43"
-"classname" "path_corner"
-"origin" "1272 520 40"
-}
-{
-"target" "t48"
-"targetname" "t47"
-"classname" "path_corner"
-"origin" "1224 144 64"
-}
-{
-"targetname" "t48"
-"target" "t43"
-"origin" "1344 120 64"
-"classname" "path_corner"
-}
-{
-"target" "t45"
-"origin" "968 520 24"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "256"
-"target" "t43"
-"origin" "1312 328 80"
-"classname" "monster_knight"
-}
-{
-"spawnflags" "768"
-"target" "t47"
-"origin" "1240 296 80"
-"classname" "monster_ogre"
-}
-{
-"origin" "-360 1064 -8"
-"classname" "weapon_grenadelauncher"
-}
-{
-"target" "t50"
-"targetname" "t49"
-"origin" "-16 1168 0"
-"classname" "path_corner"
-}
-{
-"targetname" "t50"
-"target" "t49"
-"classname" "path_corner"
-"origin" "-232 1168 0"
-}
-{
-"origin" "1448 -128 -56"
-"classname" "light"
-}
-{
-"wait" "-1"
-"classname" "func_door"
-"angle" "270"
-"model" "*31"
-}
-{
-"wait" "-1"
-"targetname" "t52"
-"sounds" "3"
-"classname" "func_door"
-"angle" "90"
-"model" "*32"
-}
-{
-"classname" "light"
-"origin" "1984 -184 288"
-"light" "350"
-}
-{
-"classname" "light"
-"origin" "1760 -312 -184"
-"light" "200"
-}
-{
-"origin" "1832 -64 -184"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "160"
-"origin" "1808 -296 -24"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1224 -8 -184"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "1240 -208 -184"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1680 -104 -184"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "1584 -304 -184"
-"classname" "light"
-}
-{
-"origin" "1592 -72 288"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1328 -232 288"
-}
-{
-"classname" "light"
-"origin" "1280 -16 327"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1792 -152 88"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "1632 -296 88"
-"classname" "light"
-}
-{
-"origin" "1696 -280 288"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1240 -224 -8"
-"light" "200"
-}
-{
-"classname" "func_wall"
-"spawnflags" "3072"
-"model" "*33"
-}
-{
-"classname" "func_wall"
-"spawnflags" "3072"
-"model" "*34"
-}
-{
-"classname" "func_wall"
-"spawnflags" "3072"
-"model" "*35"
-}
-{
-"classname" "func_wall"
-"spawnflags" "3072"
-"model" "*36"
-}
-{
-"classname" "func_wall"
-"spawnflags" "3072"
-"model" "*37"
-}
-{
-"classname" "monster_ogre"
-"origin" "1992 -192 200"
-"angle" "180"
-"spawnflags" "256"
-}
-{
-"classname" "func_door_secret"
-"angle" "90"
-"spawnflags" "2"
-"targetname" "t51"
-"model" "*38"
-}
-{
-"classname" "trigger_multiple"
-"target" "t51"
-"model" "*39"
-}
-{
-"classname" "func_plat"
-"model" "*40"
-}
-{
-"classname" "light"
-"origin" "1480 56 -168"
-"light" "160"
-}
-{
-"origin" "1432 280 -64"
-"classname" "light"
-"light" "160"
-}
-{
-"light" "160"
-"classname" "light"
-"origin" "1424 280 96"
-}
-{
-"light" "160"
-"origin" "1472 232 -168"
-"classname" "light"
-}
-{
-"classname" "monster_zombie"
-"origin" "1592 -24 160"
-"angle" "180"
-}
-{
-"classname" "monster_zombie"
-"origin" "1432 -304 112"
-"angle" "135"
-"spawnflags" "256"
-}
-{
-"classname" "monster_zombie"
-"origin" "1304 -288 112"
-"angle" "90"
-"spawnflags" "256"
-}
-{
-"classname" "monster_zombie"
-"origin" "1576 -216 136"
-"angle" "180"
-"spawnflags" "768"
-}
-{
-"classname" "monster_zombie"
-"origin" "1928 -80 200"
-"spawnflags" "768"
-"angle" "180"
-}
-{
-"angle" "180"
-"spawnflags" "768"
-"origin" "1928 -280 200"
-"classname" "monster_zombie"
-}
-{
-"classname" "trigger_changelevel"
-"map" "e2m3"
-"model" "*41"
-}
-{
-"classname" "light"
-"origin" "80 1544 40"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "-112 1544 40"
-"classname" "light"
-}
-{
-"classname" "item_shells"
-"origin" "1056 552 8"
-}
-{
-"classname" "light"
-"origin" "-112 1672 40"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "88 1680 40"
-"classname" "light"
-}
-{
-"classname" "item_health"
-"origin" "-168 1688 -8"
-"spawnflags" "1"
-}
-{
-"classname" "monster_knight"
-"origin" "-112 1616 16"
-"angle" "45"
-"spawnflags" "768"
-}
-{
-"classname" "monster_demon1"
-"origin" "1760 -208 -216"
-"angle" "180"
-}
-{
-"classname" "trigger_secret"
-"model" "*42"
-}
-{
-"classname" "trigger_secret"
-"model" "*43"
-}
-{
-"classname" "trigger_secret"
-"model" "*44"
-}
-{
-"classname" "trigger_multiple"
-"target" "t29"
-"model" "*45"
-}
-{
-"classname" "item_shells"
-"origin" "-144 -1728 288"
-"spawnflags" "768"
-}
-{
-"classname" "item_rockets"
-"origin" "2000 -304 176"
-"spawnflags" "1793"
-}
-{
-"classname" "item_rockets"
-"origin" "2000 -112 176"
-"spawnflags" "1793"
-}
-{
-"origin" "-62 -702 72"
-"classname" "ambient_swamp1"
-}
-{
-"classname" "ambient_swamp2"
-"origin" "386 -702 72"
-}
-{
-"origin" "-246 -470 -264"
-"classname" "ambient_swamp2"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "554 -454 -264"
-}
-{
-"origin" "162 -430 -264"
-"classname" "ambient_swamp1"
-}
-{
-"spawnflags" "1"
-"origin" "-72 576 104"
-"classname" "item_shells"
-}
-{
-"spawnflags" "2048"
-"wait" "10"
-"target" "t16"
-"classname" "trigger_multiple"
-"model" "*46"
-}
-{
-"targetname" "t16"
-"sounds" "4"
-"wait" "-1"
-"angle" "-1"
-"classname" "func_door"
-"model" "*47"
-}
-{
-"origin" "-184 1480 168"
-"classname" "light"
-"light" "160"
-}
-{
-"classname" "light"
-"origin" "-224 1592 168"
-"light" "100"
-}
-{
-"target" "t52"
-"classname" "trigger_once"
-"model" "*48"
-}
-{
-"mangle" "20 30 0"
-"origin" "1224 -288 336"
-"classname" "info_intermission"
-}
-{
-"mangle" "20 180 0"
-"origin" "-352 760 240"
-"classname" "info_intermission"
-}
-{
-"mangle" "20 135 0"
-"origin" "480 -440 208"
-"classname" "info_intermission"
-}
-{
-"angle" "90"
-"origin" "-176 -1904 264"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "-128 -1848 264"
-"angle" "90"
-}
-{
-"angle" "90"
-"origin" "-192 -1808 264"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "-320 -1824 264"
-"angle" "90"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*49"
-}
-{
-"spawnflags" "1792"
-"origin" "200 -664 0"
-"classname" "weapon_lightning"
-}
-{
-"origin" "-184 1512 144"
-"classname" "item_artifact_super_damage"
-}
-{
-"classname" "item_cells"
-"origin" "240 -664 0"
-"spawnflags" "1793"
-}
-{
-"classname" "item_cells"
-"origin" "392 640 0"
-"spawnflags" "1793"
-}
-{
-"classname" "item_cells"
-"origin" "-168 456 104"
-"spawnflags" "1793"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"spawnflags" "1"
-"wait" "6"
-"speed" "1000"
-"sounds" "3"
-"targetname" "t15"
-"model" "*50"
-}
-{
-"classname" "weapon_grenadelauncher"
-"origin" "1312 280 56"
-"spawnflags" "3584"
-}
-{
-"sounds" "2"
-"wait" "5"
-"message" "Shoot the buttons..."
-"spawnflags" "3584"
-"classname" "trigger_multiple"
-"targetname" "t53"
-"model" "*51"
-}
-{
-"classname" "trigger_relay"
-"origin" "-72 -320 48"
-"targetname" "t13"
-"killtarget" "t53"
-}
diff --git a/Misc/pak/maps/e2m3.diff b/Misc/pak/maps/e2m3.diff
new file mode 100644
index 000000000..4d51967d7
--- /dev/null
+++ b/Misc/pak/maps/e2m3.diff
@@ -0,0 +1,74 @@
+--- e2m3.ent
++++ e2m3@237a.ent
+@@ -1226,21 +1226,23 @@
+ {
+ "classname" "func_door"
+ "angle" "-2"
+ "spawnflags" "1"
+ "targetname" "t11"
+ "wait" "10"
+ "model" "*25"
++"lip" "7" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "func_door_secret"
+ "angle" "90"
+ "spawnflags" "8"
+ "targetname" "t11"
+ "model" "*26"
++"t_length" "65" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "light"
+ "origin" "1248 -288 312"
+ "light" "150"
+ }
+ {
+@@ -1907,14 +1909,15 @@
+ }
+ {
+ "classname" "func_door_secret"
+ "spawnflags" "2051"
+ "targetname" "t36"
+ "angle" "90"
+ "model" "*37"
++"t_length" "65" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "light"
+ "origin" "-1288 640 -80"
+ "light" "160"
+ }
+ {
+@@ -1939,14 +1942,15 @@
+ }
+ {
+ "classname" "func_door_secret"
+ "targetname" "t36"
+ "angle" "270"
+ "spawnflags" "2049"
+ "model" "*38"
++"t_length" "65" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "item_armor2"
+ "origin" "1128 600 -176"
+ "spawnflags" "1024"
+ }
+ {
+@@ -2643,14 +2647,15 @@
+ }
+ {
+ "classname" "func_door_secret"
+ "angle" "180"
+ "spawnflags" "2"
+ "targetname" "t41"
+ "model" "*66"
++"t_length" "65" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "trigger_multiple"
+ "target" "t41"
+ "model" "*67"
+ }
+ {
diff --git a/Misc/pak/maps/e2m3.ent.orig b/Misc/pak/maps/e2m3.ent.orig
deleted file mode 100644
index 3ff5bd575..000000000
--- a/Misc/pak/maps/e2m3.ent.orig
+++ /dev/null
@@ -1,2860 +0,0 @@
-{
-"classname" "worldspawn"
-"wad" "gfx/jr_med.wad"
-"worldtype" "0"
-"sounds" "9"
-"message" "the Crypt of Decay"
-}
-{
-"classname" "light"
-"origin" "192 -648 128"
-}
-{
-"classname" "info_player_start"
-"origin" "688 -1600 -312"
-"angle" "180"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "650 -438 4"
-}
-{
-"origin" "386 -438 4"
-"classname" "light_flame_large_yellow"
-}
-{
-"origin" "66 -886 4"
-"classname" "light_flame_large_yellow"
-}
-{
-"origin" "322 -886 4"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "250"
-"origin" "192 -1408 288"
-"classname" "light"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "192 -1088 288"
-}
-{
-"light" "250"
-"origin" "112 -1248 272"
-"classname" "light"
-}
-{
-"light" "250"
-"classname" "light"
-"origin" "272 -1248 272"
-}
-{
-"light" "200"
-"origin" "192 -1056 32"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "192 -1248 24"
-"classname" "light"
-}
-{
-"origin" "194 -1462 108"
-"classname" "light_flame_large_yellow"
-}
-{
-"origin" "194 -1030 164"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "150"
-"origin" "192 -1440 32"
-"classname" "light"
-}
-{
-"sounds" "2"
-"classname" "func_plat"
-"spawnflags" "1"
-"model" "*1"
-}
-{
-"origin" "226 -1670 -212"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "150"
-"origin" "88 -1552 -184"
-"classname" "light"
-}
-{
-"origin" "-22 -1374 -212"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "150"
-"origin" "328 -1256 -184"
-"classname" "light"
-}
-{
-"light" "150"
-"classname" "light"
-"origin" "56 -1256 -184"
-}
-{
-"classname" "light"
-"origin" "248 -1480 -184"
-"light" "150"
-}
-{
-"light" "250"
-"origin" "552 -1608 -72"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "432 -1656 -224"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "432 -1496 -224"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "192 -1248 -40"
-"classname" "light"
-}
-{
-"origin" "10 -438 4"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "-254 -438 4"
-}
-{
-"light" "150"
-"origin" "192 -704 -136"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "192 -512 -136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "416 -512 -136"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-32 -512 -136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-208 -512 -136"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "592 -512 -136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 -840 -136"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-352 -672 -168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-320 -832 -168"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-320 -512 -168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "696 -512 -168"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "736 -672 -168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "704 -832 -168"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "512 -864 -168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-128 -864 -168"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "-128 -320 8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "512 -320 8"
-"light" "200"
-}
-{
-"origin" "384 -24 32"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "0 -24 32"
-}
-{
-"light" "200"
-"origin" "416 -192 -8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-32 -192 -8"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "840 48 72"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "576 -24 -56"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "624 -24 72"
-"classname" "light"
-}
-{
-"origin" "1002 354 -60"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "100"
-"origin" "1000 352 -128"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "736 8 72"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "936 88 72"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "688 -8 -32"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "784 24 -104"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "888 72 -32"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "872 208 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "872 400 -56"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "872 592 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "744 568 88"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "744 648 88"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "704 608 -80"
-"light" "150"
-}
-{
-"origin" "866 730 -60"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light"
-"origin" "864 728 -128"
-"light" "100"
-}
-{
-"sounds" "3"
-"wait" "-1"
-"targetname" "t8"
-"spawnflags" "2049"
-"angle" "0"
-"classname" "func_door"
-"model" "*2"
-}
-{
-"spawnflags" "2048"
-"angle" "90"
-"target" "t8"
-"classname" "func_button"
-"wait" "-1"
-"model" "*3"
-}
-{
-"origin" "520 608 -64"
-"classname" "light"
-}
-{
-"light" "400"
-"origin" "192 608 -24"
-"classname" "light"
-}
-{
-"sounds" "1"
-"wait" "-1"
-"angle" "270"
-"spawnflags" "2058"
-"classname" "func_door_secret"
-"targetname" "t9"
-"model" "*4"
-}
-{
-"light" "150"
-"origin" "1064 640 -112"
-"classname" "light"
-}
-{
-"targetname" "t9"
-"angle" "180"
-"origin" "1024 640 -152"
-"classname" "monster_zombie"
-}
-{
-"targetname" "t9"
-"angle" "180"
-"origin" "1120 672 -152"
-"classname" "monster_zombie"
-}
-{
-"targetname" "t9"
-"angle" "180"
-"origin" "1088 600 -152"
-"classname" "monster_zombie"
-}
-{
-"origin" "976 336 -176"
-"classname" "item_health"
-}
-{
-"light" "150"
-"origin" "192 608 -104"
-"classname" "light"
-}
-{
-"origin" "192 288 -64"
-"classname" "light"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "66 106 4"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-30 106 4"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light"
-"origin" "504 120 -248"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "704 224 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "704 472 -248"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "304 112 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "80 112 -248"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "720 608 -248"
-"classname" "light"
-}
-{
-"spawnflags" "2048"
-"sounds" "1"
-"wait" "-1"
-"targetname" "t3"
-"classname" "func_door"
-"angle" "90"
-"model" "*5"
-}
-{
-"spawnflags" "2048"
-"wait" "-1"
-"angle" "270"
-"classname" "func_door"
-"message" "This door opens nearby..."
-"model" "*6"
-}
-{
-"spawnflags" "2048"
-"target" "t3"
-"wait" "-1"
-"classname" "func_button"
-"angle" "180"
-"model" "*7"
-}
-{
-"light" "250"
-"origin" "-448 184 0"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-552 280 -224"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-392 280 -224"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-416 -32 104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-320 -32 104"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-224 -32 104"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "-352 -32 -32"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-1160 88 -248"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-1048 88 -32"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "-1160 224 -32"
-}
-{
-"origin" "-742 658 -44"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "-926 658 -44"
-}
-{
-"light" "200"
-"origin" "-736 632 -96"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-928 632 -96"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "-600 104 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-696 424 -248"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-1152 408 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-944 432 -248"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-856 64 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-160 152 -248"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-160 448 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-328 464 -248"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-256 176 -248"
-"classname" "light"
-}
-{
-"origin" "-574 410 -172"
-"classname" "light_flame_large_yellow"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "-470 410 -172"
-}
-{
-"target" "t4"
-"classname" "trigger_teleport"
-"model" "*8"
-}
-{
-"light" "200"
-"style" "2"
-"origin" "-760 576 -216"
-"classname" "light"
-}
-{
-"targetname" "t4"
-"angle" "180"
-"origin" "120 -32 -112"
-"classname" "info_teleport_destination"
-}
-{
-"light" "200"
-"origin" "-264 384 112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-264 288 112"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-264 192 112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-264 480 112"
-"light" "200"
-}
-{
-"light" "250"
-"origin" "-264 304 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-520 424 0"
-"light" "250"
-}
-{
-"light" "200"
-"origin" "-1120 608 72"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1024 584 72"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-928 584 72"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-832 584 72"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-544 584 72"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-640 584 72"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "-480 768 56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-384 768 56"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "-712 120 -32"
-"light" "200"
-}
-{
-"sounds" "3"
-"wait" "-1"
-"targetname" "t5"
-"spawnflags" "2049"
-"angle" "180"
-"classname" "func_door"
-"model" "*9"
-}
-{
-"spawnflags" "2048"
-"angle" "270"
-"target" "t5"
-"wait" "-1"
-"classname" "func_button"
-"model" "*10"
-}
-{
-"style" "32"
-"targetname" "t5"
-"light" "200"
-"origin" "-352 552 -56"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-432 768 -56"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-520 680 -56"
-"classname" "light"
-}
-{
-"spawnflags" "2048"
-"sounds" "3"
-"targetname" "t5"
-"wait" "-1"
-"angle" "-2"
-"classname" "func_door"
-"model" "*11"
-}
-{
-"sounds" "3"
-"targetname" "t5"
-"spawnflags" "2049"
-"wait" "-1"
-"angle" "90"
-"classname" "func_door"
-"model" "*12"
-}
-{
-"origin" "-72 848 -56"
-"classname" "light"
-}
-{
-"origin" "-120 600 -8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 904 -8"
-}
-{
-"light" "200"
-"origin" "192 888 -248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-104 600 -248"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "376 984 -120"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "504 760 -120"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-32 608 200"
-"classname" "light"
-}
-{
-"spawnflags" "2048"
-"sounds" "3"
-"wait" "-1"
-"angle" "-2"
-"classname" "func_door"
-"model" "*13"
-}
-{
-"origin" "-16 1456 16"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "384 1248 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "384 1440 -56"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "256 1440 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 1248 -56"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "384 1344 -88"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 1152 -88"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "8 1456 -120"
-"light" "200"
-}
-{
-"spawnflags" "2048"
-"sounds" "1"
-"classname" "item_key2"
-"origin" "-16 1456 -152"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"targetname" "t6"
-"speed" "400"
-"wait" "-1"
-"sounds" "4"
-"model" "*14"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"targetname" "t6"
-"speed" "400"
-"wait" "-1"
-"sounds" "4"
-"model" "*15"
-}
-{
-"classname" "func_door"
-"angle" "-1"
-"targetname" "t6"
-"speed" "400"
-"wait" "-1"
-"sounds" "4"
-"spawnflags" "2048"
-"model" "*16"
-}
-{
-"classname" "trigger_once"
-"target" "t6"
-"model" "*17"
-}
-{
-"classname" "light"
-"origin" "-192 1456 -136"
-"light" "80"
-}
-{
-"classname" "light"
-"origin" "-16 1280 -136"
-"light" "80"
-}
-{
-"spawnflags" "768"
-"classname" "monster_hell_knight"
-"origin" "-16 1280 -168"
-"angle" "90"
-"targetname" "t6"
-}
-{
-"spawnflags" "256"
-"angle" "270"
-"origin" "-16 1632 -168"
-"classname" "monster_hell_knight"
-"targetname" "t6"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "-192 1456 -168"
-"angle" "0"
-"targetname" "t6"
-}
-{
-"classname" "light"
-"origin" "152 1440 -56"
-"light" "150"
-}
-{
-"classname" "item_shells"
-"origin" "-104 1512 -192"
-"spawnflags" "1"
-}
-{
-"wait" "-1"
-"classname" "func_door"
-"angle" "0"
-"spawnflags" "2056"
-"model" "*18"
-}
-{
-"wait" "-1"
-"classname" "func_door"
-"angle" "180"
-"spawnflags" "2056"
-"model" "*19"
-}
-{
-"classname" "light"
-"origin" "-1120 832 -48"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-1120 976 -24"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-1240 1296 216"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-1240 1416 216"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1240 1176 216"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "-712 1416 216"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-712 1296 216"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-712 1176 216"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-856 1296 216"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1096 1296 216"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-976 1296 216"
-"classname" "light"
-}
-{
-"classname" "light_flame_small_white"
-"origin" "-1318 1514 -8"
-}
-{
-"origin" "-1318 1514 64"
-"classname" "light_flame_small_white"
-}
-{
-"classname" "light_flame_small_white"
-"origin" "-1318 1514 144"
-}
-{
-"origin" "-634 1078 -8"
-"classname" "light_flame_small_white"
-}
-{
-"classname" "light_flame_small_white"
-"origin" "-634 1078 64"
-}
-{
-"origin" "-634 1078 144"
-"classname" "light_flame_small_white"
-}
-{
-"classname" "func_plat"
-"spawnflags" "1"
-"model" "*20"
-}
-{
-"classname" "light"
-"origin" "-320 1536 184"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-376 1312 120"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-16 1536 184"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-560 1312 56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "24 1120 216"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "192 608 176"
-"light" "200"
-}
-{
-"wait" "-1"
-"classname" "func_door"
-"angle" "90"
-"spawnflags" "2049"
-"targetname" "t7"
-"sounds" "1"
-"model" "*21"
-}
-{
-"light" "150"
-"origin" "400 1104 224"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "-200 1056 224"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "192 960 224"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "192 784 224"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "672 264 184"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "384 184 184"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "512 256 8"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "8 184 200"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "584 744 200"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "0 432 200"
-"light" "200"
-}
-{
-"classname" "trigger_once"
-"targetname" "t8"
-"target" "t9"
-"delay" "10"
-"model" "*22"
-}
-{
-"classname" "light"
-"origin" "192 -72 216"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "360 -168 360"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "296 -168 360"
-"light" "200"
-}
-{
-"origin" "472 -168 368"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "408 -168 360"
-}
-{
-"classname" "light"
-"origin" "384 -168 248"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "936 -304 328"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1000 -232 360"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "864 -232 360"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "864 -368 360"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1000 -368 360"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "736 -248 280"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "552 -216 280"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "16 144 -32"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "0 432 -136"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "192 384 184"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "192 192 184"
-"classname" "light"
-}
-{
-"spawnflags" "2048"
-"classname" "func_button"
-"wait" "-1"
-"target" "t7"
-"model" "*23"
-}
-{
-"style" "33"
-"targetname" "t7"
-"classname" "light"
-"origin" "176 1152 200"
-"target" "t10"
-}
-{
-"classname" "info_null"
-"origin" "292 1152 180"
-"targetname" "t10"
-}
-{
-"classname" "light"
-"origin" "192 1224 200"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "192 1376 200"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 1536 200"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "192 1080 200"
-"classname" "light"
-}
-{
-"classname" "weapon_nailgun"
-"origin" "184 -1520 -272"
-}
-{
-"classname" "func_button"
-"target" "t11"
-"angle" "-1"
-"targetname" "t12"
-"lip" "4"
-"wait" "0.1"
-"speed" "300"
-"health" "1"
-"model" "*24"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "1"
-"targetname" "t11"
-"wait" "10"
-"model" "*25"
-}
-{
-"classname" "func_door_secret"
-"angle" "90"
-"spawnflags" "8"
-"targetname" "t11"
-"model" "*26"
-}
-{
-"classname" "light"
-"origin" "1248 -288 312"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "1176 -400 352"
-"classname" "light"
-}
-{
-"classname" "item_health"
-"origin" "1336 -536 256"
-"spawnflags" "2"
-}
-{
-"classname" "light"
-"origin" "1320 -488 352"
-"light" "200"
-}
-{
-"classname" "trigger_multiple"
-"target" "t11"
-"wait" "10"
-"model" "*27"
-}
-{
-"classname" "item_armor1"
-"origin" "192 -592 -64"
-}
-{
-"classname" "item_shells"
-"origin" "176 592 -160"
-"spawnflags" "1"
-}
-{
-"classname" "weapon_nailgun"
-"origin" "-80 1456 -192"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_rocketlauncher"
-"origin" "56 1144 128"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_grenadelauncher"
-"origin" "-736 608 -280"
-"spawnflags" "1792"
-}
-{
-"classname" "item_spikes"
-"origin" "1120 -384 256"
-"spawnflags" "1"
-}
-{
-"classname" "item_rockets"
-"origin" "840 -432 192"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "-456 312 -80"
-}
-{
-"classname" "monster_zombie"
-"origin" "-1152 96 -88"
-"spawnflags" "256"
-"target" "t36"
-}
-{
-"origin" "-1120 32 -88"
-"classname" "monster_zombie"
-"spawnflags" "768"
-"target" "t36"
-}
-{
-"classname" "monster_zombie"
-"origin" "-1192 168 -88"
-"target" "t36"
-}
-{
-"classname" "monster_shambler"
-"origin" "-1120 1104 -56"
-"angle" "270"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "-336 1312 8"
-"angle" "180"
-}
-{
-"classname" "monster_ogre"
-"origin" "-698 1446 -56"
-"angle" "270"
-"spawnflags" "256"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "-888 1128 8"
-"angle" "90"
-"spawnflags" "256"
-}
-{
-"classname" "item_health"
-"origin" "-336 784 -128"
-}
-{
-"origin" "-408 608 -128"
-"classname" "item_health"
-}
-{
-"classname" "path_corner"
-"origin" "-1096 584 -120"
-"targetname" "t13"
-"target" "t14"
-}
-{
-"origin" "-496 584 -120"
-"classname" "path_corner"
-"targetname" "t14"
-"target" "t13"
-}
-{
-"classname" "monster_demon1"
-"origin" "-712 576 -104"
-"angle" "180"
-"target" "t13"
-}
-{
-"classname" "path_corner"
-"origin" "-528 472 -96"
-"targetname" "t15"
-"target" "t16"
-}
-{
-"origin" "-368 -32 -96"
-"classname" "path_corner"
-"target" "t15"
-"targetname" "t16"
-}
-{
-"classname" "monster_ogre"
-"origin" "-466 262 -56"
-"target" "t16"
-"spawnflags" "256"
-}
-{
-"target" "t22"
-"targetname" "t21"
-"origin" "56 -184 -120"
-"classname" "path_corner"
-}
-{
-"target" "t21"
-"targetname" "t20"
-"classname" "path_corner"
-"origin" "-128 -224 -120"
-}
-{
-"target" "t20"
-"targetname" "t19"
-"origin" "-128 -504 -56"
-"classname" "path_corner"
-}
-{
-"target" "t19"
-"targetname" "t18"
-"classname" "path_corner"
-"origin" "512 -504 -56"
-}
-{
-"target" "t18"
-"targetname" "t17"
-"origin" "512 -224 -120"
-"classname" "path_corner"
-}
-{
-"targetname" "t26"
-"target" "t17"
-"classname" "path_corner"
-"origin" "328 -184 -120"
-}
-{
-"target" "t23"
-"targetname" "t22"
-"classname" "path_corner"
-"origin" "-128 -200 -120"
-}
-{
-"target" "t24"
-"targetname" "t23"
-"classname" "path_corner"
-"origin" "-128 -552 -56"
-}
-{
-"target" "t25"
-"targetname" "t24"
-"origin" "512 -552 -56"
-"classname" "path_corner"
-}
-{
-"target" "t26"
-"targetname" "t25"
-"classname" "path_corner"
-"origin" "512 -200 -120"
-}
-{
-"spawnflags" "256"
-"target" "t21"
-"origin" "0 -184 -104"
-"classname" "monster_hell_knight"
-}
-{
-"spawnflags" "1"
-"origin" "376 -160 -104"
-"classname" "monster_hell_knight"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "190 -706 -40"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "768"
-"angle" "90"
-"origin" "192 -1408 24"
-"classname" "monster_hell_knight"
-}
-{
-"origin" "40 -1424 0"
-"classname" "item_shells"
-"spawnflags" "1"
-}
-{
-"spawnflags" "1"
-"origin" "304 -1096 0"
-"classname" "item_health"
-}
-{
-"origin" "328 -1280 -272"
-"classname" "item_health"
-}
-{
-"origin" "40 -1256 -272"
-"classname" "item_spikes"
-}
-{
-"target" "t28"
-"targetname" "t27"
-"origin" "864 176 -168"
-"classname" "path_corner"
-}
-{
-"target" "t27"
-"targetname" "t28"
-"classname" "path_corner"
-"origin" "864 616 -168"
-}
-{
-"target" "t27"
-"origin" "862 446 -152"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "768"
-"angle" "180"
-"origin" "526 -26 -104"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "256"
-"angle" "0"
-"origin" "-72 -24 -104"
-"classname" "monster_hell_knight"
-}
-{
-"spawnflags" "256"
-"origin" "-274 -34 -104"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "768"
-"angle" "270"
-"origin" "-512 760 -104"
-"classname" "monster_hell_knight"
-}
-{
-"spawnflags" "1793"
-"origin" "336 1104 128"
-"classname" "item_rockets"
-}
-{
-"angle" "45"
-"spawnflags" "256"
-"origin" "104 256 -136"
-"classname" "monster_zombie"
-}
-{
-"spawnflags" "769"
-"angle" "90"
-"origin" "192 488 -136"
-"classname" "monster_hell_knight"
-}
-{
-"wait" "1"
-"speed" "250"
-"lip" "16"
-"spawnflags" "5"
-"targetname" "t29"
-"dmg" "20"
-"angle" "180"
-"classname" "func_door"
-"model" "*28"
-}
-{
-"wait" "1"
-"targetname" "t29"
-"speed" "250"
-"dmg" "20"
-"lip" "16"
-"spawnflags" "5"
-"classname" "func_door"
-"sounds" "1"
-"model" "*29"
-}
-{
-"wait" "2"
-"target" "t29"
-"classname" "trigger_multiple"
-"model" "*30"
-}
-{
-"origin" "506 1762 -124"
-"classname" "light_torch_small_walltorch"
-"style" "1"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "274 2010 -124"
-}
-{
-"light" "200"
-"origin" "152 1824 -40"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "288 1824 -40"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "288 1696 -40"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "152 1704 -40"
-"light" "200"
-}
-{
-"light" "220"
-"origin" "0 1704 -40"
-"classname" "light"
-}
-{
-"angle" "180"
-"classname" "func_door_secret"
-"targetname" "t35"
-"spawnflags" "16"
-"sounds" "1"
-"model" "*31"
-}
-{
-"spawnflags" "2"
-"origin" "-16 1816 -192"
-"classname" "item_health"
-}
-{
-"origin" "432 1672 -320"
-"classname" "light"
-"light" "220"
-}
-{
-"spawnflags" "1792"
-"origin" "-16 1752 -192"
-"classname" "item_rockets"
-}
-{
-"angle" "270"
-"origin" "-192 1580 168"
-"classname" "trap_spikeshooter"
-"targetname" "t32"
-}
-{
-"spawnflags" "256"
-"classname" "trap_spikeshooter"
-"origin" "236 1536 168"
-"angle" "180"
-"targetname" "t32"
-}
-{
-"classname" "trap_spikeshooter"
-"origin" "0 1580 168"
-"angle" "270"
-"targetname" "t32"
-}
-{
-"angle" "90"
-"origin" "-96 1492 168"
-"classname" "trap_spikeshooter"
-"targetname" "t32"
-}
-{
-"classname" "trap_spikeshooter"
-"origin" "148 1376 168"
-"angle" "0"
-"targetname" "t33"
-}
-{
-"angle" "180"
-"origin" "236 1256 168"
-"classname" "trap_spikeshooter"
-"targetname" "t33"
-}
-{
-"spawnflags" "256"
-"classname" "trap_spikeshooter"
-"origin" "192 1580 168"
-"angle" "270"
-"targetname" "t33"
-}
-{
-"spawnflags" "257"
-"angle" "90"
-"origin" "192 -16 153"
-"classname" "monster_hell_knight"
-}
-{
-"spawnflags" "257"
-"angle" "180"
-"origin" "864 -248 217"
-"classname" "monster_shambler"
-}
-{
-"angle" "180"
-"origin" "464 -184 185"
-"classname" "monster_hell_knight"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "192 -176 153"
-"angle" "90"
-"spawnflags" "1"
-"target" "t31"
-}
-{
-"spawnflags" "769"
-"angle" "90"
-"origin" "190 1166 153"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "2048"
-"origin" "48 1456 -192"
-"classname" "weapon_grenadelauncher"
-}
-{
-"spawnflags" "1"
-"origin" "-96 1376 -192"
-"classname" "item_rockets"
-}
-{
-"angle" "270"
-"spawnflags" "768"
-"classname" "monster_ogre"
-"origin" "862 662 -152"
-}
-{
-"light" "120"
-"origin" "192 -352 -264"
-"classname" "light"
-}
-{
-"spawnflags" "768"
-"origin" "326 -1490 -248"
-"classname" "monster_ogre"
-"angle" "180"
-"target" "t42"
-}
-{
-"origin" "192 552 128"
-"classname" "item_health"
-}
-{
-"spawnflags" "1024"
-"classname" "item_health"
-"origin" "176 672 128"
-}
-{
-"spawnflags" "1025"
-"origin" "184 1312 128"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "-16 1480 128"
-"spawnflags" "1025"
-}
-{
-"origin" "672 -328 176"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "776 -192 176"
-}
-{
-"origin" "784 312 -176"
-"classname" "item_shells"
-}
-{
-"spawnflags" "256"
-"angle" "315"
-"origin" "-26 1094 152"
-"classname" "monster_ogre"
-}
-{
-"classname" "monster_ogre"
-"origin" "406 1094 152"
-"angle" "225"
-"spawnflags" "768"
-}
-{
-"spawnflags" "1"
-"origin" "-200 1128 128"
-"classname" "item_rockets"
-}
-{
-"origin" "-550 -478 212"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "-550 -166 212"
-}
-{
-"origin" "-214 -326 252"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "150"
-"origin" "-120 -176 192"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "56 -176 192"
-"light" "150"
-}
-{
-"origin" "-816 1488 -80"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "-752 1488 -80"
-}
-{
-"spawnflags" "1536"
-"origin" "-688 1488 -80"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "176 1264 -160"
-"classname" "item_shells"
-}
-{
-"classname" "func_door"
-"angle" "270"
-"targetname" "t31"
-"wait" "-1"
-"spawnflags" "2048"
-"model" "*32"
-}
-{
-"wait" "-1"
-"sounds" "1"
-"speed" "300"
-"classname" "func_door"
-"angle" "90"
-"model" "*33"
-}
-{
-"speed" "300"
-"classname" "func_door"
-"angle" "270"
-"wait" "-1"
-"model" "*34"
-}
-{
-"classname" "item_health"
-"origin" "400 1464 -160"
-"spawnflags" "1024"
-}
-{
-"classname" "item_health"
-"origin" "-1136 528 -128"
-}
-{
-"classname" "monster_ogre"
-"origin" "-370 -218 88"
-"targetname" "t31"
-"spawnflags" "1"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "-64 -176 152"
-"angle" "0"
-"spawnflags" "768"
-"targetname" "t31"
-}
-{
-"classname" "item_health"
-"origin" "-488 -480 64"
-}
-{
-"classname" "light"
-"origin" "680 -1600 -160"
-}
-{
-"classname" "item_spikes"
-"origin" "984 -192 192"
-"spawnflags" "1"
-}
-{
-"classname" "monster_ogre"
-"origin" "-490 -410 88"
-"angle" "45"
-}
-{
-"classname" "trigger_multiple"
-"target" "t32"
-"wait" "1"
-"spawnflags" "1024"
-"targetname" "t44"
-"model" "*35"
-}
-{
-"classname" "trigger_multiple"
-"target" "t33"
-"wait" "1"
-"spawnflags" "1024"
-"model" "*36"
-}
-{
-"classname" "item_rockets"
-"origin" "-96 272 -384"
-}
-{
-"classname" "weapon_supernailgun"
-"origin" "-1200 208 -112"
-"spawnflags" "1792"
-}
-{
-"classname" "func_door_secret"
-"spawnflags" "2051"
-"targetname" "t36"
-"angle" "90"
-"model" "*37"
-}
-{
-"classname" "light"
-"origin" "-1288 640 -80"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "-1288 128 -80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1288 264 -80"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "-1288 392 -80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1288 520 -80"
-"light" "160"
-}
-{
-"classname" "func_door_secret"
-"targetname" "t36"
-"angle" "270"
-"spawnflags" "2049"
-"model" "*38"
-}
-{
-"classname" "item_armor2"
-"origin" "1128 600 -176"
-"spawnflags" "1024"
-}
-{
-"classname" "func_door_secret"
-"angle" "90"
-"spawnflags" "11"
-"targetname" "t34"
-"model" "*39"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "-246 -1310 -204"
-"light" "250"
-}
-{
-"classname" "trigger_once"
-"target" "t34"
-"model" "*40"
-}
-{
-"classname" "item_spikes"
-"origin" "-240 -1288 -312"
-"spawnflags" "1"
-}
-{
-"spawnflags" "1"
-"origin" "-240 -1368 -312"
-"classname" "item_spikes"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "3585"
-"wait" "90"
-"targetname" "t6"
-"model" "*41"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"targetname" "t6"
-"spawnflags" "3585"
-"angle" "-2"
-"wait" "90"
-"model" "*42"
-}
-{
-"sounds" "3"
-"classname" "func_door"
-"angle" "0"
-"spawnflags" "1537"
-"targetname" "t6"
-"wait" "90"
-"model" "*43"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "-42 1642 -108"
-"light" "200"
-}
-{
-"classname" "item_health"
-"origin" "-72 560 -384"
-}
-{
-"origin" "-152 560 -384"
-"classname" "item_health"
-}
-{
-"targetname" "t31"
-"spawnflags" "513"
-"angle" "90"
-"origin" "848 -376 216"
-"classname" "monster_hell_knight"
-}
-{
-"targetname" "t31"
-"spawnflags" "768"
-"origin" "-512 -248 88"
-"classname" "monster_shambler"
-}
-{
-"spawnflags" "768"
-"angle" "180"
-"origin" "382 1246 -136"
-"classname" "monster_ogre"
-}
-{
-"spawnflags" "768"
-"classname" "monster_ogre"
-"origin" "190 1438 -136"
-"angle" "0"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "640 -1664 -312"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "-400 -240 88"
-"angle" "0"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "-216 1088 152"
-"angle" "0"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "-512 792 -104"
-"angle" "270"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "888 624 -152"
-"angle" "270"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "-96 1456 -168"
-"angle" "0"
-}
-{
-"spawnflags" "2048"
-"classname" "func_wall"
-"model" "*44"
-}
-{
-"spawnflags" "2048"
-"classname" "func_wall"
-"model" "*45"
-}
-{
-"classname" "func_plat"
-"height" "192"
-"sounds" "2"
-"model" "*46"
-}
-{
-"classname" "item_health"
-"origin" "-1184 72 -352"
-}
-{
-"classname" "light"
-"origin" "-952 1408 80"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "-1120 1176 48"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "-104 288 -344"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "-512 376 -304"
-"light" "200"
-}
-{
-"classname" "trigger_multiple"
-"target" "t35"
-"model" "*47"
-}
-{
-"classname" "light"
-"origin" "192 -376 -16"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "192 -328 176"
-"light" "150"
-}
-{
-"classname" "trigger_multiple"
-"target" "t32"
-"spawnflags" "768"
-"wait" "0.5"
-"model" "*48"
-}
-{
-"classname" "trigger_multiple"
-"spawnflags" "768"
-"wait" "0.5"
-"target" "t33"
-"targetname" "t44"
-"model" "*49"
-}
-{
-"origin" "-1176 112 -112"
-"classname" "item_rockets"
-}
-{
-"origin" "-736 544 -280"
-"classname" "item_armorInv"
-}
-{
-"classname" "func_button"
-"angle" "180"
-"target" "t36"
-"model" "*50"
-}
-{
-"classname" "info_null"
-"origin" "-1332 1116 -36"
-"targetname" "t37"
-}
-{
-"classname" "light"
-"origin" "-1296 1120 -32"
-"target" "t37"
-"angle" "60"
-}
-{
-"spawnflags" "2048"
-"classname" "func_wall"
-"model" "*51"
-}
-{
-"spawnflags" "2048"
-"classname" "func_wall"
-"model" "*52"
-}
-{
-"classname" "light"
-"origin" "192 -152 -344"
-"light" "160"
-}
-{
-"classname" "light"
-"origin" "192 32 -344"
-"light" "160"
-}
-{
-"classname" "light"
-"origin" "32 168 -344"
-"light" "140"
-}
-{
-"light" "160"
-"origin" "-16 408 -344"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 368 -344"
-"light" "140"
-}
-{
-"light" "140"
-"origin" "448 368 -344"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "528 592 -344"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "408 808 -344"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 832 -344"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-40 728 -344"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-168 632 -344"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-160 976 -344"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "592 456 -344"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "192 352 -232"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "32 264 -232"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-184 432 -336"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "-192 144 -336"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-776 280 -312"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-864 432 -312"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1096 432 -312"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-1168 272 -312"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-944 64 -312"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "-664 136 -312"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "-1112 592 -96"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-1040 1256 -32"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "-880 1128 80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-712 1400 -16"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "104 -600 -224"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "280 -600 -224"
-"classname" "light"
-}
-{
-"classname" "trigger_changelevel"
-"map" "e2m4"
-"model" "*53"
-}
-{
-"light" "160"
-"origin" "-312 808 -72"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "192 1776 -312"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-392 568 -56"
-"light" "160"
-}
-{
-"classname" "light"
-"origin" "-1224 1504 8"
-"light" "170"
-}
-{
-"light" "170"
-"origin" "-1304 1392 8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-640 1168 -8"
-"light" "170"
-}
-{
-"light" "160"
-"origin" "352 -1248 56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "40 -1248 56"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "192 -1216 -176"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "24 -1376 -232"
-"light" "160"
-}
-{
-"light" "160"
-"origin" "224 -1624 -232"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "368 -1392 -232"
-"light" "160"
-}
-{
-"classname" "light"
-"origin" "8 -464 -40"
-"light" "140"
-}
-{
-"light" "140"
-"origin" "384 -464 -40"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-544 800 -56"
-"light" "140"
-}
-{
-"classname" "trigger_secret"
-"model" "*54"
-}
-{
-"classname" "trigger_secret"
-"model" "*55"
-}
-{
-"light" "200"
-"origin" "760 1856 -40"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "760 1664 -40"
-"light" "200"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "538 1762 -124"
-"style" "1"
-"light" "200"
-}
-{
-"style" "1"
-"classname" "light_torch_small_walltorch"
-"origin" "850 1930 -124"
-"light" "200"
-}
-{
-"origin" "850 1618 -124"
-"classname" "light_torch_small_walltorch"
-"style" "1"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "912 1856 -40"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "912 1664 -40"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1064 1776 -172"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1080 1856 -40"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1080 1664 -40"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1176 1776 -172"
-"light" "200"
-}
-{
-"light" "170"
-"origin" "672 1768 -296"
-"classname" "light"
-}
-{
-"target" "t38"
-"classname" "trigger_teleport"
-"model" "*56"
-}
-{
-"targetname" "t38"
-"origin" "1144 1776 -88"
-"classname" "info_teleport_destination"
-}
-{
-"map" "e2m7"
-"classname" "trigger_changelevel"
-"model" "*57"
-}
-{
-"light" "160"
-"origin" "840 1768 -200"
-"classname" "light"
-}
-{
-"light" "140"
-"origin" "408 608 -344"
-"classname" "light"
-}
-{
-"classname" "item_spikes"
-"origin" "-16 240 -160"
-"spawnflags" "2048"
-}
-{
-"classname" "weapon_supernailgun"
-"origin" "-1256 1448 -80"
-}
-{
-"origin" "432 1160 152"
-"classname" "item_artifact_super_damage"
-}
-{
-"message" "The portal lies beyond..."
-"targetname" "t40"
-"wait" "-1"
-"speed" "20"
-"sounds" "4"
-"angle" "-2"
-"classname" "func_door"
-"model" "*58"
-}
-{
-"origin" "432 1672 -368"
-"classname" "item_armor2"
-}
-{
-"target" "t39"
-"sounds" "1"
-"wait" "-1"
-"classname" "func_button"
-"model" "*59"
-}
-{
-"message" "The underwater barrier is lowered..."
-"target" "t40"
-"targetname" "t39"
-"spawnflags" "1"
-"classname" "trigger_once"
-"model" "*60"
-}
-{
-"classname" "trigger_secret"
-"model" "*61"
-}
-{
-"light" "200"
-"origin" "-128 -704 -224"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "512 -704 -224"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "192 -832 -224"
-"classname" "light"
-}
-{
-"mangle" "20 240 0"
-"origin" "400 1048 240"
-"classname" "info_intermission"
-}
-{
-"mangle" "20 145 0"
-"origin" "-160 144 64"
-"classname" "info_intermission"
-}
-{
-"mangle" "-20 45 0"
-"origin" "-320 -824 -144"
-"classname" "info_intermission"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*62"
-}
-{
-"classname" "item_artifact_super_damage"
-"origin" "928 1768 -240"
-"spawnflags" "1792"
-}
-{
-"classname" "light"
-"origin" "8 1800 -120"
-"light" "220"
-}
-{
-"classname" "weapon_lightning"
-"origin" "1216 1784 -264"
-"spawnflags" "1792"
-}
-{
-"classname" "item_cells"
-"origin" "880 1648 -264"
-"spawnflags" "1793"
-}
-{
-"spawnflags" "1793"
-"origin" "880 1864 -264"
-"classname" "item_cells"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*63"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*64"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*65"
-}
-{
-"classname" "info_player_coop"
-"origin" "664 -1520 -312"
-"angle" "180"
-}
-{
-"angle" "180"
-"origin" "592 -1600 -312"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "680 -1712 -312"
-"angle" "180"
-}
-{
-"classname" "air_bubbles"
-"origin" "720 1384 -320"
-}
-{
-"classname" "light"
-"origin" "680 1376 -312"
-}
-{
-"classname" "func_door_secret"
-"angle" "180"
-"spawnflags" "2"
-"targetname" "t41"
-"model" "*66"
-}
-{
-"classname" "trigger_multiple"
-"target" "t41"
-"model" "*67"
-}
-{
-"origin" "688 1176 -312"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "480 1408 -312"
-}
-{
-"origin" "448 1552 -312"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "840 1080 -312"
-}
-{
-"origin" "840 1080 -160"
-"classname" "light"
-"light" "200"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "840 1080 0"
-}
-{
-"classname" "light"
-"origin" "840 1080 232"
-"light" "200"
-}
-{
-"classname" "item_artifact_envirosuit"
-"origin" "576 1440 -344"
-}
-{
-"classname" "item_artifact_invulnerability"
-"origin" "544 1248 -344"
-}
-{
-"light" "200"
-"origin" "840 936 232"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "840 760 232"
-"light" "150"
-}
-{
-"light" "120"
-"origin" "808 600 232"
-"classname" "light"
-}
-{
-"classname" "item_health"
-"origin" "824 960 152"
-}
-{
-"origin" "848 880 152"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "808 768 152"
-}
-{
-"classname" "trigger_multiple"
-"message" "Welcome to the Well of Wishes!"
-"wait" "5"
-"sounds" "1"
-"model" "*68"
-}
-{
-"classname" "trigger_multiple"
-"sounds" "1"
-"wait" "3"
-"message" "The Dopefish Lives!"
-"model" "*69"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*70"
-}
-{
-"classname" "trigger_secret"
-"model" "*71"
-}
-{
-"spawnflags" "1"
-"origin" "-1312 1392 -80"
-"classname" "item_spikes"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*72"
-}
-{
-"classname" "light"
-"origin" "-544 600 -248"
-"light" "200"
-}
-{
-"light" "200"
-"classname" "light_torch_small_walltorch"
-"origin" "194 -214 196"
-"spawnflags" "2048"
-}
-{
-"light" "200"
-"origin" "352 984 -328"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "96 976 -328"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "640 776 -336"
-"light" "200"
-}
-{
-"classname" "func_plat"
-"spawnflags" "1"
-"model" "*73"
-}
-{
-"classname" "monster_fish"
-"origin" "656 352 -336"
-"spawnflags" "256"
-}
-{
-"spawnflags" "256"
-"origin" "432 424 -336"
-"classname" "monster_fish"
-}
-{
-"classname" "monster_fish"
-"origin" "296 968 -336"
-"spawnflags" "256"
-}
-{
-"origin" "-48 800 -336"
-"classname" "monster_fish"
-}
-{
-"classname" "monster_fish"
-"origin" "-896 248 -312"
-}
-{
-"origin" "-744 328 -312"
-"classname" "monster_fish"
-}
-{
-"classname" "path_corner"
-"origin" "272 -1504 -264"
-"targetname" "t42"
-"target" "t43"
-}
-{
-"origin" "56 -1352 -264"
-"classname" "path_corner"
-"target" "t42"
-"targetname" "t43"
-}
-{
-"classname" "item_health"
-"origin" "312 -1336 -272"
-}
-{
-"origin" "544 -1488 -336"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "312 1464 -160"
-}
-{
-"origin" "56 1488 -192"
-"classname" "item_health"
-}
-{
-"classname" "trigger_once"
-"killtarget" "t44"
-"spawnflags" "3072"
-"model" "*74"
-}
-{
-"classname" "item_rockets"
-"origin" "216 648 120"
-"spawnflags" "1"
-}
-{
-"classname" "item_shells"
-"origin" "136 648 120"
-"spawnflags" "1"
-}
diff --git a/Misc/pak/maps/e2m7.diff b/Misc/pak/maps/e2m7.diff
new file mode 100644
index 000000000..badaf2ef8
--- /dev/null
+++ b/Misc/pak/maps/e2m7.diff
@@ -0,0 +1,22 @@
+--- e2m7.ent
++++ e2m7@10a8.ent
+@@ -1449,18 +1449,19 @@
+ {
+ "targetname" "t119"
+ "classname" "func_door"
+ "wait" "-1"
+ "angle" "-1"
+ "speed" "30"
+ "message" "Go for a swim first..."
+ "sounds" "3"
+ "model" "*40"
++"origin" "-1 0 0" // svdijk -- added to prevent z-fighting
+ }
+ {
+ "classname" "func_button"
+ "angle" "0"
+ "wait" "-1"
+ "target" "t45"
+ "model" "*41"
+ }
+ {
diff --git a/Misc/pak/maps/e2m7.ent.orig b/Misc/pak/maps/e2m7.ent.orig
deleted file mode 100644
index d4bec275b..000000000
--- a/Misc/pak/maps/e2m7.ent.orig
+++ /dev/null
@@ -1,3632 +0,0 @@
-{
-"wad" "gfx/tim.wad"
-"classname" "worldspawn"
-"sounds" "7"
-"worldtype" "0"
-"message" "the Underearth"
-}
-{
-"angle" "90"
-"origin" "1136 -1100 -72"
-"classname" "info_player_start"
-}
-{
-"origin" "1184 -776 -152"
-"classname" "light"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1704 -584 -184"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1640 -688 -184"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1696 -888 -192"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1088 -960 -152"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1248 -960 -152"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1016 -768 -152"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "896 -920 -152"
-"light" "150"
-}
-{
-"light" "100"
-"origin" "1584 -208 -112"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "1776 -208 -112"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1584 -88 -112"
-"classname" "light"
-}
-{
-"origin" "1774 58 -76"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "100"
-"origin" "1584 -488 -232"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "1768 -480 -232"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1752 -112 -176"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1592 -120 -176"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1592 -248 -192"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1768 -240 -192"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1676 -220 -188"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1672 -40 -136"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1676 -376 -252"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1112 952 -92"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1280 928 -152"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "704 952 -92"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "824 1112 -92"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "952 760 -92"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "824 760 -92"
-"light" "200"
-}
-{
-"light" "250"
-"origin" "952 1112 -92"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1128 -848 288"
-"light" "500"
-}
-{
-"classname" "light"
-"origin" "1144 -432 288"
-}
-{
-"classname" "light"
-"origin" "864 -552 272"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1392 -568 168"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1416 -592 -24"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "888 -584 -24"
-"light" "150"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1058 -466 -24"
-"light" "225"
-}
-{
-"origin" "1214 -466 -24"
-"classname" "light_torch_small_walltorch"
-"light" "225"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1198 -66 40"
-"light" "300"
-}
-{
-"classname" "light"
-"origin" "1144 -204 172"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1144 -292 -32"
-"light" "150"
-}
-{
-"classname" "item_spikes"
-"origin" "880 -592 -96"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "1068 -944 -96"
-}
-{
-"classname" "light"
-"origin" "1128 -1084 96"
-"light" "300"
-}
-{
-"classname" "light"
-"origin" "888 -848 248"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1504 -896 248"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1304 -1048 24"
-"light" "225"
-}
-{
-"classname" "light"
-"origin" "1520 -872 -192"
-"light" "150"
-}
-{
-"light" "100"
-"origin" "1384 -776 -184"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1368 -912 -184"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1584 496 148"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1488 496 148"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1688 164 148"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1352 496 148"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1608 496 -36"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1456 496 -36"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1692 600 -12"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1274 618 -64"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1274 378 -64"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1256 496 -40"
-"light" "200"
-}
-{
-"spawnflags" "2056"
-"wait" "-1"
-"classname" "func_door"
-"angle" "270"
-"model" "*1"
-}
-{
-"wait" "-1"
-"spawnflags" "2056"
-"sounds" "3"
-"angle" "90"
-"classname" "func_door"
-"model" "*2"
-}
-{
-"light" "200"
-"origin" "1968 1792 -257"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1880 1792 -105"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1976 1944 56"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1992 1624 64"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1944 1736 64"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1944 1832 64"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1128 496 -24"
-"light" "250"
-}
-{
-"light" "150"
-"origin" "1120 632 -24"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "928 544 -24"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "640 664 -8"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "848 672 -8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1024 544 -188"
-"light" "175"
-}
-{
-"light" "250"
-"origin" "64 192 136"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "528 184 136"
-"light" "250"
-}
-{
-"light" "200"
-"origin" "72 408 8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "80 -48 8"
-"light" "200"
-}
-{
-"light" "250"
-"origin" "400 384 80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "392 -16 80"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "312 184 -80"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "440 184 -80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "504 368 -120"
-"light" "250"
-}
-{
-"light" "150"
-"origin" "632 192 -120"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "504 -16 -120"
-"light" "250"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "774 446 -172"
-"light" "250"
-}
-{
-"origin" "774 -70 -172"
-"classname" "light_torch_small_walltorch"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "896 -128 152"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "896 184 152"
-"light" "250"
-}
-{
-"light" "150"
-"origin" "656 184 216"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "304 368 -152"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "0 480 -168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "96 376 -168"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "16 1480 -96"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1280 1824 -120"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "504 1816 -120"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "712 1808 -120"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1064 1808 -120"
-"classname" "light"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "858 1950 -172"
-"light" "250"
-}
-{
-"origin" "658 1950 -172"
-"classname" "light_torch_small_walltorch"
-"light" "250"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "666 1682 -172"
-"light" "250"
-}
-{
-"origin" "858 1682 -172"
-"classname" "light_torch_small_walltorch"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1248 1384 -32"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1688 936 -136"
-"light" "200"
-}
-{
-"light" "250"
-"origin" "1856 1444 -52"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1864 1316 -192"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1776 1212 -192"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1696 1076 -192"
-"classname" "light"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1770 730 -64"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1760 1720 -201"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1632 1520 -201"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1984 1504 -201"
-"light" "200"
-}
-{
-"light" "250"
-"classname" "light_torch_small_walltorch"
-"origin" "1874 2104 -300"
-}
-{
-"light" "250"
-"origin" "1712 2104 -300"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "200"
-"classname" "light"
-"origin" "1792 2048 48"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "1362 1778 0"
-}
-{
-"classname" "light"
-"origin" "1408 1776 -124"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1520 1880 -84"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "1416 1512 -84"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1376 1568 -164"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1416 1888 -164"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1544 2072 -164"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1552 1968 36"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1416 1968 -16"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "1416 2176 -16"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1240 2176 -16"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "1240 2000 -16"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1264 1576 -72"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "992 1480 -40"
-"classname" "light"
-}
-{
-"light" "200"
-"classname" "light_torch_small_walltorch"
-"origin" "968 1632 -132"
-}
-{
-"light" "200"
-"origin" "968 1328 -132"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1474 2234 -133"
-"light" "200"
-}
-{
-"origin" "1182 2234 -133"
-"classname" "light_torch_small_walltorch"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "1936 1480 48"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1544 1528 64"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1472 1488 24"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "1400 1664 96"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "1792 2176 -221"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1880 2288 -221"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "2048 2288 -221"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2128 2208 -221"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "2160 1992 -205"
-"classname" "light"
-}
-{
-"origin" "2288 1952 -29"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "2274 1738 -172"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "2274 1682 -172"
-"light" "250"
-}
-{
-"light" "200"
-"origin" "2376 2184 -152"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "2618 1658 -169"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "2618 1368 -169"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "2176 1488 -169"
-"classname" "light_torch_small_walltorch"
-}
-{
-"light" "200"
-"origin" "2298 626 24"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1930 738 24"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "2050 394 24"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "func_plat"
-"model" "*3"
-}
-{
-"light" "150"
-"origin" "2152 1784 -312"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2232 936 -4"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "2232 1040 48"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "2034 1034 -164"
-"light" "200"
-}
-{
-"classname" "light"
-"origin" "2304 1040 280"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "2168 1040 280"
-"classname" "light"
-}
-{
-"origin" "2130 2452 -112"
-"classname" "light_flame_large_yellow"
-"light" "250"
-}
-{
-"classname" "light_flame_large_yellow"
-"origin" "1858 2452 -112"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "2132 2416 -188"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1860 2416 -188"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "2256 1968 -453"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2256 2184 -453"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "2216 2384 -453"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1792 2400 -453"
-"light" "200"
-}
-{
-"light" "175"
-"origin" "1984 2400 -453"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "2168 1608 -9"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2368 1600 -9"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "2240 1424 44"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2400 1424 44"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "2560 1424 44"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2560 1560 44"
-"light" "175"
-}
-{
-"light" "150"
-"origin" "2232 1288 44"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "2384 1424 -160"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2232 1288 -160"
-"light" "175"
-}
-{
-"light" "150"
-"origin" "2164 932 -172"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2308 932 -172"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "2232 776 24"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2192 664 24"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "2016 696 24"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1912 496 24"
-"light" "150"
-}
-{
-"light" "175"
-"origin" "80 1616 -120"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "72 1888 -120"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "296 1616 -120"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "304 1888 -120"
-"classname" "light"
-}
-{
-"targetname" "t20"
-"angle" "90"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t21"
-"angle" "120"
-"classname" "trap_spikeshooter"
-"origin" "192 1752 -208"
-"spawnflags" "1"
-}
-{
-"targetname" "t22"
-"angle" "150"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t19"
-"angle" "60"
-"classname" "trap_spikeshooter"
-"origin" "192 1752 -208"
-"spawnflags" "1"
-}
-{
-"targetname" "t18"
-"angle" "30"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t17"
-"angle" "0"
-"classname" "trap_spikeshooter"
-"origin" "192 1752 -208"
-"spawnflags" "1"
-}
-{
-"targetname" "t24"
-"angle" "210"
-"classname" "trap_spikeshooter"
-"origin" "192 1752 -208"
-"spawnflags" "1"
-}
-{
-"targetname" "t23"
-"angle" "180"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t25"
-"angle" "240"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t26"
-"angle" "270"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t27"
-"angle" "300"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t28"
-"angle" "330"
-"spawnflags" "1"
-"origin" "192 1752 -208"
-"classname" "trap_spikeshooter"
-}
-{
-"delay" ".1"
-"targetname" "t29"
-"target" "t17"
-"classname" "trigger_multiple"
-"model" "*4"
-}
-{
-"delay" ".1"
-"targetname" "t17"
-"target" "t18"
-"classname" "trigger_multiple"
-"model" "*5"
-}
-{
-"delay" ".1"
-"targetname" "t18"
-"target" "t19"
-"classname" "trigger_multiple"
-"model" "*6"
-}
-{
-"delay" ".1"
-"targetname" "t19"
-"target" "t20"
-"classname" "trigger_multiple"
-"model" "*7"
-}
-{
-"delay" ".1"
-"targetname" "t20"
-"target" "t21"
-"classname" "trigger_multiple"
-"model" "*8"
-}
-{
-"delay" ".1"
-"targetname" "t21"
-"target" "t22"
-"classname" "trigger_multiple"
-"model" "*9"
-}
-{
-"delay" ".1"
-"targetname" "t22"
-"target" "t23"
-"classname" "trigger_multiple"
-"model" "*10"
-}
-{
-"delay" ".1"
-"targetname" "t23"
-"target" "t24"
-"classname" "trigger_multiple"
-"model" "*11"
-}
-{
-"delay" ".1"
-"targetname" "t24"
-"target" "t25"
-"classname" "trigger_multiple"
-"model" "*12"
-}
-{
-"delay" ".1"
-"targetname" "t25"
-"target" "t26"
-"classname" "trigger_multiple"
-"model" "*13"
-}
-{
-"delay" ".1"
-"targetname" "t26"
-"target" "t27"
-"classname" "trigger_multiple"
-"model" "*14"
-}
-{
-"delay" ".1"
-"targetname" "t27"
-"target" "t28"
-"classname" "trigger_multiple"
-"model" "*15"
-}
-{
-"target" "t29"
-"wait" "1.3"
-"classname" "trigger_multiple"
-"model" "*16"
-}
-{
-"origin" "192 1750 -188"
-"classname" "light_flame_large_yellow"
-}
-{
-"light" "125"
-"origin" "214 1752 -166"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "192 1774 -166"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "170 1750 -166"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "194 1726 -166"
-"light" "125"
-}
-{
-"target" "t31"
-"wait" "-1"
-"angle" "0"
-"classname" "func_button"
-"model" "*17"
-}
-{
-"target" "t31"
-"angle" "180"
-"wait" "-1"
-"classname" "func_button"
-"model" "*18"
-}
-{
-"target" "t31"
-"wait" "-1"
-"angle" "180"
-"classname" "func_button"
-"model" "*19"
-}
-{
-"target" "t31"
-"angle" "90"
-"wait" "-1"
-"classname" "func_button"
-"model" "*20"
-}
-{
-"wait" "-1"
-"targetname" "t30"
-"sounds" "4"
-"speed" "50"
-"angle" "-1"
-"classname" "func_door"
-"model" "*21"
-}
-{
-"count" "4"
-"targetname" "t31"
-"target" "t30"
-"classname" "trigger_counter"
-"model" "*22"
-}
-{
-"light" "150"
-"origin" "2424 1080 -176"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2424 992 -176"
-"light" "150"
-}
-{
-"targetname" "t40"
-"angle" "180"
-"spawnflags" "1"
-"origin" "2434 1036 -192"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t40"
-"classname" "trap_spikeshooter"
-"origin" "2434 1036 -192"
-"spawnflags" "1"
-"angle" "160"
-}
-{
-"targetname" "t40"
-"angle" "140"
-"spawnflags" "1"
-"origin" "2434 1036 -192"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t40"
-"classname" "trap_spikeshooter"
-"origin" "2434 1036 -192"
-"spawnflags" "1"
-"angle" "120"
-}
-{
-"targetname" "t40"
-"angle" "200"
-"spawnflags" "1"
-"origin" "2434 1036 -192"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t40"
-"classname" "trap_spikeshooter"
-"origin" "2434 1036 -192"
-"spawnflags" "1"
-"angle" "220"
-}
-{
-"targetname" "t40"
-"angle" "240"
-"spawnflags" "1"
-"origin" "2434 1036 -192"
-"classname" "trap_spikeshooter"
-}
-{
-"targetname" "t41"
-"target" "t40"
-"wait" ".5"
-"classname" "trigger_multiple"
-"model" "*23"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*24"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*25"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*26"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*27"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*28"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*29"
-}
-{
-"target" "t41"
-"classname" "trigger_multiple"
-"model" "*30"
-}
-{
-"light" "125"
-"origin" "2196 1200 -204"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2284 1200 -204"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "2284 1112 -204"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2388 1104 -204"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "2284 1000 -204"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2140 1008 -204"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "2132 1096 -204"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2132 1160 -204"
-"light" "125"
-}
-{
-"light" "200"
-"origin" "528 1816 -392"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "736 1808 -392"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "1040 1808 -392"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "744 1424 -392"
-"light" "200"
-}
-{
-"light" "200"
-"origin" "752 1288 -416"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "760 1064 -376"
-"classname" "light"
-}
-{
-"classname" "func_train"
-"spawnflags" "33"
-"targetname" "t42"
-"dmg" "1000"
-"sounds" "1"
-"target" "t124"
-"speed" "250"
-"model" "*31"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"wait" "-1"
-"targetname" "t43"
-"speed" "50"
-"sounds" "3"
-"model" "*32"
-}
-{
-"classname" "func_button"
-"angle" "-2"
-"wait" "-1"
-"target" "t42"
-"sounds" "1"
-"model" "*33"
-}
-{
-"classname" "trigger_once"
-"target" "t43"
-"targetname" "t42"
-"delay" "2"
-"model" "*34"
-}
-{
-"classname" "light"
-"origin" "1936 1784 -288"
-"light" "125"
-}
-{
-"classname" "monster_ogre"
-"origin" "1976 1784 -328"
-"angle" "180"
-}
-{
-"classname" "func_door"
-"angle" "90"
-"wait" "-1"
-"sounds" "1"
-"model" "*35"
-}
-{
-"classname" "func_door"
-"angle" "270"
-"targetname" "t44"
-"wait" "-1"
-"model" "*36"
-}
-{
-"classname" "light"
-"origin" "64 264 8"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "64 120 8"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "64 192 8"
-"light" "100"
-}
-{
-"classname" "trigger_once"
-"target" "t44"
-"model" "*37"
-}
-{
-"classname" "light"
-"origin" "512 184 -8"
-"light" "175"
-}
-{
-"targetname" "t119"
-"classname" "func_door"
-"angle" "90"
-"wait" "-1"
-"speed" "40"
-"model" "*38"
-}
-{
-"targetname" "t119"
-"classname" "func_door"
-"wait" "-1"
-"angle" "270"
-"speed" "40"
-"sounds" "4"
-"model" "*39"
-}
-{
-"targetname" "t119"
-"classname" "func_door"
-"wait" "-1"
-"angle" "-1"
-"speed" "30"
-"message" "Go for a swim first..."
-"sounds" "3"
-"model" "*40"
-}
-{
-"classname" "func_button"
-"angle" "0"
-"wait" "-1"
-"target" "t45"
-"model" "*41"
-}
-{
-"classname" "light"
-"origin" "36 184 84"
-"light" "75"
-}
-{
-"classname" "light"
-"origin" "752 184 -192"
-"light" "150"
-}
-{
-"classname" "light"
-"origin" "544 536 -152"
-"light" "125"
-}
-{
-"classname" "func_door"
-"angle" "-2"
-"sounds" "1"
-"wait" "-1"
-"targetname" "t45"
-"model" "*42"
-}
-{
-"wait" "-1"
-"sounds" "1"
-"angle" "-2"
-"classname" "func_door"
-"targetname" "t45"
-"model" "*43"
-}
-{
-"light" "125"
-"origin" "544 -152 -152"
-"classname" "light"
-}
-{
-"classname" "item_artifact_envirosuit"
-"origin" "1024 492 -232"
-}
-{
-"classname" "item_armor1"
-"origin" "2128 1752 -352"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "1024 368 -4"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1024 400 -64"
-"light" "150"
-}
-{
-"wait" "5"
-"sounds" "1"
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "1"
-"targetname" "t51"
-"model" "*44"
-}
-{
-"wait" "5"
-"sounds" "1"
-"classname" "func_door"
-"angle" "-2"
-"spawnflags" "1"
-"targetname" "t51"
-"model" "*45"
-}
-{
-"sounds" "3"
-"classname" "func_button"
-"angle" "270"
-"wait" "3"
-"target" "t51"
-"model" "*46"
-}
-{
-"classname" "light"
-"origin" "1224 712 -216"
-"light" "100"
-}
-{
-"classname" "light"
-"origin" "1232 768 -192"
-"light" "100"
-}
-{
-"light" "75"
-"origin" "1168 760 -232"
-"classname" "light"
-}
-{
-"light" "100"
-"origin" "1232 800 -208"
-"classname" "light"
-}
-{
-"sounds" "1"
-"origin" "1860 472 -8"
-"classname" "item_key2"
-"spawnflags" "2048"
-}
-{
-"classname" "light"
-"origin" "1112 1568 -40"
-"light" "200"
-}
-{
-"light" "150"
-"origin" "-96 1440 -160"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "384 1440 -160"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "248 1408 -96"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "968 1480 -128"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1008 -592 -32"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1264 -592 -32"
-"light" "150"
-}
-{
-"light" "200"
-"origin" "880 -840 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1376 -856 -56"
-"light" "200"
-}
-{
-"light" "175"
-"origin" "264 184 -8"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "1464 -864 -208"
-"classname" "light"
-}
-{
-"light" "175"
-"origin" "1816 160 -56"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1560 160 -56"
-"light" "175"
-}
-{
-"light" "175"
-"origin" "1544 1632 104"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1792 1624 128"
-"light" "175"
-}
-{
-"classname" "item_health"
-"origin" "1068 -980 -104"
-}
-{
-"spawnflags" "1"
-"classname" "item_shells"
-"origin" "1344 -1160 -96"
-}
-{
-"classname" "monster_ogre"
-"origin" "1008 -128 40"
-"angle" "315"
-"targetname" "t59"
-"spawnflags" "1"
-}
-{
-"classname" "trigger_once"
-"target" "t59"
-"model" "*47"
-}
-{
-"classname" "monster_ogre"
-"origin" "896 96 56"
-"angle" "270"
-"target" "t60"
-"spawnflags" "1"
-}
-{
-"classname" "path_corner"
-"origin" "896 208 40"
-"target" "t60"
-"targetname" "t61"
-}
-{
-"origin" "896 -16 40"
-"classname" "path_corner"
-"targetname" "t60"
-"target" "t61"
-}
-{
-"classname" "path_corner"
-"origin" "168 392 -56"
-"target" "t62"
-"targetname" "t63"
-}
-{
-"origin" "168 -16 -56"
-"classname" "path_corner"
-"targetname" "t62"
-"target" "t63"
-}
-{
-"classname" "path_corner"
-"origin" "88 344 -56"
-"targetname" "t64"
-"target" "t65"
-"spawnflags" "256"
-}
-{
-"origin" "88 72 -56"
-"classname" "path_corner"
-"target" "t64"
-"targetname" "t65"
-"spawnflags" "256"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "88 224 -40"
-"angle" "90"
-"target" "t64"
-"spawnflags" "257"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "168 232 -40"
-"angle" "270"
-"target" "t62"
-"spawnflags" "1"
-}
-{
-"classname" "monster_zombie"
-"origin" "544 -120 -208"
-"angle" "90"
-"targetname" "t45"
-}
-{
-"classname" "monster_zombie"
-"origin" "544 496 -208"
-"angle" "270"
-"targetname" "t45"
-}
-{
-"classname" "monster_wizard"
-"origin" "664 428 216"
-"angle" "225"
-"spawnflags" "1"
-}
-{
-"angle" "135"
-"origin" "664 -56 216"
-"classname" "monster_wizard"
-"spawnflags" "257"
-}
-{
-"classname" "light"
-"origin" "1736 88 -40"
-"light" "100"
-}
-{
-"classname" "monster_ogre"
-"origin" "904 -120 56"
-"angle" "0"
-"targetname" "t66"
-"spawnflags" "1281"
-}
-{
-"classname" "trigger_once"
-"target" "t66"
-"spawnflags" "256"
-"model" "*48"
-}
-{
-"classname" "item_health"
-"origin" "1168 -408 -80"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "1168 -104 -16"
-}
-{
-"classname" "item_spikes"
-"origin" "928 216 32"
-}
-{
-"classname" "item_rockets"
-"origin" "632 -48 32"
-}
-{
-"classname" "item_health"
-"origin" "32 392 -64"
-}
-{
-"light" "200"
-"origin" "1688 288 148"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1688 464 148"
-"light" "200"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "1814 622 -64"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "1768 344 -72"
-"light" "200"
-}
-{
-"classname" "trigger_monsterjump"
-"angle" "0"
-"model" "*49"
-}
-{
-"targetname" "t100"
-"classname" "monster_ogre"
-"origin" "1504 272 24"
-"angle" "0"
-"spawnflags" "256"
-}
-{
-"targetname" "t68"
-"target" "t67"
-"origin" "1352 576 -120"
-"classname" "path_corner"
-"spawnflags" "256"
-}
-{
-"target" "t68"
-"targetname" "t67"
-"classname" "path_corner"
-"origin" "1352 416 -120"
-"spawnflags" "256"
-}
-{
-"target" "t68"
-"angle" "90"
-"origin" "1360 480 -104"
-"classname" "monster_demon1"
-"spawnflags" "257"
-}
-{
-"targetname" "t70"
-"target" "t69"
-"origin" "1472 496 -120"
-"classname" "path_corner"
-}
-{
-"target" "t70"
-"targetname" "t69"
-"classname" "path_corner"
-"origin" "1688 496 -120"
-}
-{
-"target" "t69"
-"angle" "270"
-"origin" "1648 544 -104"
-"classname" "monster_ogre"
-"spawnflags" "1"
-}
-{
-"target" "t71"
-"targetname" "t72"
-"origin" "1984 688 -24"
-"classname" "path_corner"
-"spawnflags" "256"
-}
-{
-"target" "t72"
-"targetname" "t71"
-"classname" "path_corner"
-"origin" "1984 448 -24"
-"spawnflags" "256"
-}
-{
-"target" "t71"
-"angle" "270"
-"origin" "1992 536 -8"
-"classname" "monster_ogre"
-"spawnflags" "257"
-}
-{
-"target" "t74"
-"targetname" "t73"
-"origin" "2120 680 -24"
-"classname" "path_corner"
-}
-{
-"targetname" "t74"
-"target" "t73"
-"classname" "path_corner"
-"origin" "2240 680 -24"
-}
-{
-"target" "t74"
-"angle" "225"
-"origin" "2256 736 -8"
-"classname" "monster_ogre"
-"spawnflags" "1"
-}
-{
-"targetname" "t78"
-"angle" "90"
-"origin" "2232 1312 -8"
-"classname" "monster_ogre"
-"spawnflags" "256"
-}
-{
-"target" "t76"
-"angle" "90"
-"origin" "2232 1008 -200"
-"classname" "monster_hell_knight"
-"spawnflags" "1"
-}
-{
-"targetname" "t76"
-"target" "t75"
-"origin" "2120 968 -216"
-"classname" "path_corner"
-}
-{
-"target" "t76"
-"targetname" "t75"
-"classname" "path_corner"
-"origin" "2336 968 -216"
-}
-{
-"classname" "light"
-"origin" "2384 2400 -152"
-"light" "200"
-}
-{
-"targetname" "t77"
-"wait" "-1"
-"sounds" "1"
-"speed" "300"
-"angle" "-2"
-"classname" "func_door"
-"model" "*50"
-}
-{
-"targetname" "t77"
-"angle" "180"
-"origin" "2512 2312 -200"
-"classname" "monster_demon1"
-"spawnflags" "256"
-}
-{
-"targetname" "t77"
-"classname" "monster_demon1"
-"origin" "2512 2160 -200"
-"angle" "180"
-}
-{
-"classname" "item_health"
-"origin" "2504 2200 -224"
-}
-{
-"light" "150"
-"origin" "2536 2312 -128"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "2536 2160 -128"
-"light" "150"
-}
-{
-"target" "t77"
-"classname" "trigger_once"
-"model" "*51"
-}
-{
-"spawnflags" "2"
-"origin" "2368 2336 -224"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "2504 2240 -224"
-"classname" "item_spikes"
-}
-{
-"origin" "2408 2072 -224"
-"classname" "item_shells"
-}
-{
-"target" "t78"
-"classname" "trigger_once"
-"model" "*52"
-}
-{
-"targetname" "t78"
-"angle" "90"
-"origin" "2240 1272 -200"
-"classname" "monster_demon1"
-}
-{
-"light" "150"
-"origin" "1120 1384 -40"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1200 1248 -104"
-"classname" "light"
-}
-{
-"light" "250"
-"origin" "1288 1032 -4"
-"classname" "light_flame_small_yellow"
-}
-{
-"light" "150"
-"origin" "1256 1032 -64"
-"classname" "light"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "568 1032 -4"
-"light" "250"
-}
-{
-"classname" "light"
-"origin" "600 1032 -64"
-"light" "150"
-}
-{
-"light" "250"
-"origin" "888 1272 -4"
-"classname" "light_flame_small_yellow"
-}
-{
-"light" "150"
-"origin" "888 1240 -64"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "608 1232 -108"
-"classname" "light"
-}
-{
-"target" "t79"
-"wait" "-1"
-"angle" "180"
-"classname" "func_button"
-"model" "*53"
-}
-{
-"targetname" "t79"
-"message" "This door is opened near by..."
-"sounds" "3"
-"speed" "35"
-"angle" "-1"
-"wait" "-1"
-"classname" "func_door"
-"model" "*54"
-}
-{
-"light" "100"
-"origin" "580 1208 -148"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "1224 736 -8"
-"classname" "light"
-}
-{
-"target" "t80"
-"classname" "trigger_once"
-"model" "*55"
-}
-{
-"targetname" "t80"
-"angle" "315"
-"origin" "640 1088 128"
-"classname" "monster_wizard"
-}
-{
-"targetname" "t80"
-"classname" "monster_wizard"
-"origin" "616 720 128"
-"angle" "0"
-}
-{
-"targetname" "t80"
-"angle" "180"
-"origin" "1280 680 128"
-"classname" "monster_wizard"
-"spawnflags" "256"
-}
-{
-"target" "t82"
-"origin" "1248 1080 24"
-"classname" "monster_wizard"
-"spawnflags" "1"
-}
-{
-"targetname" "t82"
-"target" "t81"
-"origin" "1168 1064 8"
-"classname" "path_corner"
-}
-{
-"target" "t82"
-"targetname" "t81"
-"classname" "path_corner"
-"origin" "720 1064 8"
-}
-{
-"targetname" "t80"
-"classname" "monster_wizard"
-"origin" "584 1112 128"
-"angle" "315"
-"spawnflags" "256"
-}
-{
-"origin" "1256 944 -184"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "1116 584 -256"
-"classname" "item_spikes"
-}
-{
-"targetname" "t79"
-"angle" "315"
-"origin" "1000 1464 -168"
-"classname" "monster_ogre"
-}
-{
-"target" "t85"
-"targetname" "t86"
-"origin" "1456 1824 -192"
-"classname" "path_corner"
-"spawnflags" "256"
-}
-{
-"target" "t86"
-"targetname" "t85"
-"classname" "path_corner"
-"origin" "1456 1560 -192"
-"spawnflags" "256"
-}
-{
-"target" "t85"
-"angle" "270"
-"origin" "1456 1664 -176"
-"classname" "monster_ogre"
-"spawnflags" "256"
-}
-{
-"targetname" "t91"
-"angle" "270"
-"origin" "1560 1944 -320"
-"classname" "monster_zombie"
-"spawnflags" "256"
-}
-{
-"targetname" "t91"
-"classname" "monster_zombie"
-"origin" "1600 1912 -320"
-"angle" "270"
-}
-{
-"angle" "225"
-"origin" "1960 1984 -320"
-"classname" "monster_zombie"
-}
-{
-"targetname" "t91"
-"classname" "monster_zombie"
-"origin" "1904 1928 -320"
-"angle" "225"
-}
-{
-"targetname" "t91"
-"angle" "270"
-"origin" "1624 1768 -320"
-"classname" "monster_zombie"
-}
-{
-"target" "t87"
-"classname" "monster_zombie"
-"origin" "1696 1912 -320"
-"angle" "0"
-}
-{
-"target" "t89"
-"angle" "270"
-"origin" "1704 1800 -320"
-"classname" "monster_zombie"
-}
-{
-"target" "t87"
-"targetname" "t88"
-"origin" "1648 1912 -336"
-"classname" "path_corner"
-}
-{
-"target" "t88"
-"targetname" "t87"
-"classname" "path_corner"
-"origin" "1848 1904 -336"
-}
-{
-"targetname" "t90"
-"target" "t89"
-"origin" "1648 1824 -336"
-"classname" "path_corner"
-}
-{
-"target" "t90"
-"targetname" "t89"
-"classname" "path_corner"
-"origin" "1768 1752 -336"
-}
-{
-"target" "t91"
-"classname" "trigger_once"
-"model" "*56"
-}
-{
-"spawnflags" "1"
-"origin" "1496 1808 -200"
-"classname" "item_health"
-}
-{
-"spawnflags" "1"
-"origin" "1184 2176 -192"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "1184 2128 -192"
-"spawnflags" "1"
-}
-{
-"spawnflags" "1"
-"origin" "1264 1680 -192"
-"classname" "item_health"
-}
-{
-"target" "t92"
-"targetname" "t93"
-"origin" "2376 2304 -216"
-"classname" "path_corner"
-}
-{
-"target" "t93"
-"targetname" "t92"
-"classname" "path_corner"
-"origin" "2376 1984 -216"
-}
-{
-"target" "t95"
-"targetname" "t94"
-"origin" "2144 1608 -216"
-"classname" "path_corner"
-}
-{
-"target" "t94"
-"targetname" "t95"
-"classname" "path_corner"
-"origin" "2376 1608 -216"
-}
-{
-"target" "t92"
-"angle" "270"
-"origin" "2376 2176 -200"
-"classname" "monster_hell_knight"
-"spawnflags" "1"
-}
-{
-"angle" "135"
-"origin" "2416 1760 -200"
-"classname" "monster_hell_knight"
-"spawnflags" "257"
-}
-{
-"target" "t94"
-"angle" "180"
-"origin" "2320 1608 -200"
-"classname" "monster_hell_knight"
-"spawnflags" "1"
-}
-{
-"angle" "90"
-"origin" "2152 1840 -200"
-"classname" "monster_ogre"
-"spawnflags" "257"
-}
-{
-"target" "t97"
-"targetname" "t96"
-"origin" "2096 2376 -216"
-"classname" "path_corner"
-"spawnflags" "256"
-}
-{
-"target" "t96"
-"targetname" "t97"
-"classname" "path_corner"
-"origin" "2232 2208 -216"
-"spawnflags" "256"
-}
-{
-"target" "t96"
-"angle" "135"
-"origin" "2200 2264 -200"
-"classname" "monster_wizard"
-"spawnflags" "257"
-}
-{
-"origin" "2104 1544 -224"
-"classname" "item_shells"
-}
-{
-"origin" "2176 1240 -32"
-"classname" "item_spikes"
-}
-{
-"classname" "item_spikes"
-"origin" "2256 1240 -32"
-}
-{
-"origin" "1928 584 -32"
-"classname" "item_shells"
-}
-{
-"spawnflags" "1"
-"origin" "2040 1072 -32"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "2040 1024 -32"
-"spawnflags" "1"
-}
-{
-"angle" "225"
-"origin" "2352 1160 -200"
-"classname" "monster_hell_knight"
-"spawnflags" "256"
-}
-{
-"angle" "180"
-"origin" "1864 1192 -216"
-"classname" "monster_zombie"
-}
-{
-"classname" "monster_zombie"
-"origin" "1776 1192 -216"
-"angle" "180"
-}
-{
-"target" "t99"
-"targetname" "t98"
-"origin" "1688 1192 -232"
-"classname" "path_corner"
-}
-{
-"target" "t98"
-"targetname" "t99"
-"classname" "path_corner"
-"origin" "1688 1048 -232"
-}
-{
-"target" "t98"
-"angle" "90"
-"origin" "1688 1112 -216"
-"classname" "monster_zombie"
-}
-{
-"origin" "536 416 32"
-"classname" "item_shells"
-}
-{
-"target" "t100"
-"classname" "trigger_once"
-"spawnflags" "256"
-"model" "*57"
-}
-{
-"origin" "1784 408 -128"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "1784 448 -128"
-}
-{
-"origin" "1736 728 -128"
-"classname" "item_rockets"
-}
-{
-"target" "t101"
-"sounds" "1"
-"wait" "-1"
-"angle" "270"
-"classname" "func_button"
-"model" "*58"
-}
-{
-"light" "250"
-"origin" "1418 234 52"
-"classname" "light_torch_small_walltorch"
-}
-{
-"targetname" "t101"
-"classname" "trigger_secret"
-"model" "*59"
-}
-{
-"targetname" "t102"
-"angle" "180"
-"classname" "trigger_monsterjump"
-"model" "*60"
-}
-{
-"target" "t102"
-"killtarget" "t102"
-"classname" "trigger_once"
-"model" "*61"
-}
-{
-"origin" "1568 1968 -352"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "1608 1968 -352"
-}
-{
-"origin" "2112 1776 -352"
-"classname" "item_shells"
-"spawnflags" "2048"
-}
-{
-"origin" "1920 2232 -352"
-"classname" "item_spikes"
-}
-{
-"classname" "item_spikes"
-"origin" "2008 2232 -352"
-}
-{
-"classname" "item_shells"
-"origin" "2176 1440 -224"
-}
-{
-"target" "t66"
-"classname" "trigger_once"
-"model" "*62"
-}
-{
-"origin" "1744 0 -128"
-"classname" "item_spikes"
-"spawnflags" "1"
-}
-{
-"target" "t103"
-"targetname" "t104"
-"origin" "-56 1432 -224"
-"classname" "path_corner"
-"spawnflags" "256"
-}
-{
-"target" "t104"
-"targetname" "t103"
-"classname" "path_corner"
-"origin" "312 1432 -224"
-"spawnflags" "256"
-}
-{
-"target" "t103"
-"origin" "40 1440 -208"
-"classname" "monster_ogre"
-"spawnflags" "257"
-}
-{
-"angle" "45"
-"origin" "56 1616 -208"
-"classname" "monster_hell_knight"
-"spawnflags" "1"
-}
-{
-"target" "t105"
-"targetname" "t106"
-"origin" "520 1816 -232"
-"classname" "path_corner"
-}
-{
-"target" "t106"
-"targetname" "t105"
-"classname" "path_corner"
-"origin" "920 1816 -232"
-}
-{
-"target" "t105"
-"origin" "624 1800 -216"
-"classname" "monster_hell_knight"
-"spawnflags" "1"
-}
-{
-"angle" "0"
-"origin" "480 1824 64"
-"classname" "monster_wizard"
-"spawnflags" "257"
-}
-{
-"targetname" "t107"
-"classname" "monster_wizard"
-"origin" "656 1816 64"
-"angle" "0"
-"spawnflags" "1"
-}
-{
-"targetname" "t107"
-"angle" "0"
-"origin" "840 1816 64"
-"classname" "monster_wizard"
-"spawnflags" "257"
-}
-{
-"target" "t107"
-"classname" "trigger_once"
-"model" "*63"
-}
-{
-"origin" "1440 2200 -192"
-"classname" "item_shells"
-}
-{
-"classname" "item_shells"
-"origin" "1440 2160 -192"
-}
-{
-"spawnflags" "1"
-"origin" "1184 1976 -192"
-"classname" "item_spikes"
-}
-{
-"target" "t109"
-"targetname" "t108"
-"origin" "1240 2000 -184"
-"classname" "path_corner"
-}
-{
-"target" "t108"
-"targetname" "t109"
-"classname" "path_corner"
-"origin" "1240 1760 -184"
-}
-{
-"target" "t108"
-"angle" "90"
-"origin" "1240 1904 -168"
-"classname" "monster_ogre"
-"spawnflags" "1"
-}
-{
-"target" "t110"
-"classname" "trigger_once"
-"spawnflags" "256"
-"model" "*64"
-}
-{
-"targetname" "t110"
-"angle" "45"
-"origin" "1216 2088 -168"
-"classname" "monster_ogre"
-"spawnflags" "1281"
-}
-{
-"classname" "item_health"
-"origin" "1496 1768 -200"
-}
-{
-"target" "t111"
-"classname" "trigger_once"
-"model" "*65"
-}
-{
-"targetname" "t111"
-"angle" "315"
-"origin" "764 -60 -208"
-"classname" "monster_zombie"
-}
-{
-"targetname" "t111"
-"angle" "45"
-"origin" "764 436 -208"
-"classname" "monster_zombie"
-}
-{
-"targetname" "t111"
-"angle" "225"
-"origin" "284 -56 -208"
-"classname" "monster_zombie"
-"spawnflags" "256"
-}
-{
-"targetname" "t119"
-"wait" "-1"
-"speed" "40"
-"angle" "90"
-"classname" "func_door"
-"model" "*66"
-}
-{
-"origin" "1280 592 -128"
-"classname" "item_shells"
-}
-{
-"classname" "item_shells"
-"origin" "576 416 32"
-}
-{
-"classname" "item_spikes"
-"origin" "904 504 -128"
-"spawnflags" "1"
-}
-{
-"origin" "904 464 -128"
-"classname" "item_spikes"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "1024 912 -152"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "720 848 -184"
-"spawnflags" "1"
-}
-{
-"classname" "path_corner"
-"origin" "1224 1192 -176"
-"targetname" "t112"
-"target" "t113"
-}
-{
-"origin" "1216 896 -176"
-"classname" "path_corner"
-"targetname" "t113"
-"target" "t112"
-}
-{
-"classname" "monster_ogre"
-"origin" "1224 992 -160"
-"angle" "90"
-"target" "t112"
-}
-{
-"classname" "item_shells"
-"origin" "968 1600 -184"
-}
-{
-"classname" "item_artifact_super_damage"
-"origin" "1444 308 -104"
-}
-{
-"classname" "light"
-"origin" "992 -128 72"
-"light" "100"
-}
-{
-"classname" "item_shells"
-"origin" "1672 1008 -240"
-}
-{
-"classname" "item_health"
-"origin" "2264 1320 -224"
-}
-{
-"classname" "monster_wizard"
-"origin" "2120 1664 -72"
-"angle" "315"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "2016 392 -32"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "360 1744 -208"
-"angle" "90"
-"targetname" "t114"
-"spawnflags" "257"
-}
-{
-"classname" "trigger_once"
-"target" "t114"
-"spawnflags" "256"
-"model" "*67"
-}
-{
-"classname" "item_health"
-"origin" "352 1464 -232"
-}
-{
-"spawnflags" "1"
-"origin" "352 1392 -232"
-"classname" "item_health"
-}
-{
-"classname" "item_armorInv"
-"origin" "744 1424 -448"
-}
-{
-"classname" "item_health"
-"origin" "-56 320 -232"
-}
-{
-"origin" "-16 320 -232"
-"classname" "item_health"
-}
-{
-"targetname" "t117"
-"classname" "trigger_teleport"
-"target" "t115"
-"spawnflags" "2"
-"model" "*68"
-}
-{
-"delay" ".5"
-"targetname" "t117"
-"classname" "trigger_teleport"
-"target" "t116"
-"spawnflags" "2"
-"model" "*69"
-}
-{
-"classname" "monster_wizard"
-"origin" "2928 1816 -152"
-"angle" "180"
-"targetname" "t117"
-}
-{
-"angle" "180"
-"origin" "2928 1768 -152"
-"classname" "monster_wizard"
-"targetname" "t117"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "1824 1920 -184"
-"angle" "225"
-"targetname" "t115"
-}
-{
-"classname" "info_teleport_destination"
-"origin" "1880 1544 -184"
-"angle" "180"
-"targetname" "t116"
-}
-{
-"classname" "trigger_once"
-"target" "t117"
-"model" "*70"
-}
-{
-"classname" "monster_zombie"
-"origin" "764 388 -208"
-"angle" "0"
-"targetname" "t111"
-}
-{
-"angle" "0"
-"origin" "764 -12 -208"
-"classname" "monster_zombie"
-"targetname" "t111"
-}
-{
-"classname" "monster_zombie"
-"origin" "408 -56 -208"
-"angle" "270"
-"targetname" "t111"
-}
-{
-"classname" "light"
-"origin" "1200 672 -240"
-"light" "125"
-}
-{
-"classname" "item_spikes"
-"origin" "72 392 -64"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "2368 920 -224"
-}
-{
-"origin" "2032 976 -224"
-"classname" "item_spikes"
-}
-{
-"classname" "light"
-"origin" "1416 2096 -112"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "1240 2096 -112"
-"classname" "light"
-}
-{
-"classname" "item_spikes"
-"origin" "464 1824 -240"
-}
-{
-"origin" "504 1824 -240"
-"classname" "item_spikes"
-}
-{
-"classname" "item_shells"
-"origin" "-96 1472 -232"
-"spawnflags" "1"
-}
-{
-"classname" "item_health"
-"origin" "528 -172 -232"
-}
-{
-"classname" "item_health"
-"origin" "40 -64 -64"
-}
-{
-"light" "225"
-"classname" "light_torch_small_walltorch"
-"origin" "122 -86 -8"
-}
-{
-"origin" "134 462 -8"
-"classname" "light_torch_small_walltorch"
-"light" "225"
-}
-{
-"light" "250"
-"origin" "678 446 92"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light_torch_small_walltorch"
-"origin" "678 -70 92"
-"light" "250"
-}
-{
-"light" "150"
-"origin" "120 -56 -16"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "136 424 -16"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "600 184 296"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "152 184 296"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "368 376 296"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "368 0 296"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "352 192 232"
-"classname" "light"
-}
-{
-"light" "200"
-"origin" "64 408 168"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "56 -48 168"
-"light" "200"
-}
-{
-"light" "125"
-"origin" "1520 1880 24"
-"classname" "light"
-}
-{
-"origin" "272 272 -232"
-"classname" "item_rockets"
-}
-{
-"targetname" "t45"
-"classname" "func_door"
-"angle" "-2"
-"sounds" "1"
-"wait" "-1"
-"model" "*71"
-}
-{
-"classname" "light"
-"origin" "416 -152 -152"
-"light" "125"
-}
-{
-"targetname" "t45"
-"angle" "90"
-"origin" "416 -120 -208"
-"classname" "monster_zombie"
-"spawnflags" "256"
-}
-{
-"origin" "400 524 -232"
-"classname" "item_health"
-}
-{
-"light" "125"
-"origin" "416 536 -152"
-"classname" "light"
-}
-{
-"targetname" "t45"
-"wait" "-1"
-"sounds" "1"
-"angle" "-2"
-"classname" "func_door"
-"model" "*72"
-}
-{
-"targetname" "t45"
-"angle" "270"
-"origin" "416 496 -208"
-"classname" "monster_zombie"
-"spawnflags" "256"
-}
-{
-"target" "t120"
-"wait" "-1"
-"angle" "270"
-"classname" "func_button"
-"model" "*73"
-}
-{
-"target" "t120"
-"wait" "-1"
-"angle" "90"
-"classname" "func_button"
-"model" "*74"
-}
-{
-"targetname" "t120"
-"target" "t119"
-"classname" "trigger_counter"
-"model" "*75"
-}
-{
-"light" "125"
-"origin" "1792 840 -112"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1584 840 -112"
-"light" "125"
-}
-{
-"light" "125"
-"origin" "1792 2280 -480"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "1792 2144 -480"
-"light" "125"
-}
-{
-"origin" "1776 2232 -508"
-"classname" "item_health"
-}
-{
-"classname" "item_health"
-"origin" "1776 2192 -508"
-}
-{
-"light" "150"
-"origin" "1016 1696 -336"
-"classname" "light"
-}
-{
-"light" "125"
-"origin" "1080 1696 -280"
-"classname" "light"
-}
-{
-"light" "125"
-"origin" "1152 1696 -200"
-"classname" "light"
-}
-{
-"light" "150"
-"origin" "1096 1696 -352"
-"classname" "light"
-}
-{
-"classname" "trigger_secret"
-"model" "*76"
-}
-{
-"target" "t116"
-"classname" "trigger_teleport"
-"model" "*77"
-}
-{
-"spawnflags" "768"
-"angle" "315"
-"origin" "1400 1856 -176"
-"classname" "monster_ogre"
-}
-{
-"target" "t121"
-"targetname" "t122"
-"spawnflags" "768"
-"origin" "1824 2280 -344"
-"classname" "path_corner"
-}
-{
-"target" "t122"
-"targetname" "t121"
-"spawnflags" "768"
-"classname" "path_corner"
-"origin" "2080 2280 -344"
-}
-{
-"target" "t121"
-"spawnflags" "769"
-"angle" "180"
-"origin" "2128 2272 -328"
-"classname" "monster_demon1"
-}
-{
-"spawnflags" "2816"
-"origin" "1824 2072 -352"
-"classname" "item_shells"
-}
-{
-"spawnflags" "769"
-"angle" "90"
-"origin" "1792 2176 -144"
-"classname" "monster_wizard"
-}
-{
-"spawnflags" "769"
-"angle" "180"
-"origin" "2600 1640 -200"
-"classname" "monster_hell_knight"
-}
-{
-"spawnflags" "2816"
-"origin" "2096 1136 -32"
-"classname" "item_shells"
-}
-{
-"classname" "monster_wizard"
-"origin" "1872 1432 -72"
-"angle" "90"
-"spawnflags" "769"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "2400 1032 -8"
-"angle" "180"
-"spawnflags" "769"
-}
-{
-"classname" "monster_demon1"
-"origin" "1000 496 -104"
-"angle" "0"
-"spawnflags" "768"
-}
-{
-"classname" "monster_demon1"
-"origin" "1240 2088 -168"
-"angle" "45"
-"spawnflags" "769"
-"targetname" "t110"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "360 1936 -208"
-"angle" "270"
-"spawnflags" "769"
-"targetname" "t114"
-}
-{
-"classname" "item_shells"
-"origin" "16 1768 -232"
-"spawnflags" "2560"
-}
-{
-"spawnflags" "2560"
-"origin" "344 1576 -232"
-"classname" "item_shells"
-}
-{
-"classname" "trigger_changelevel"
-"map" "e2m4"
-"model" "*78"
-}
-{
-"classname" "light"
-"origin" "1136 -1144 264"
-"light" "250"
-}
-{
-"light" "250"
-"origin" "1264 -552 44"
-"classname" "light_flame_small_yellow"
-}
-{
-"classname" "light_flame_small_yellow"
-"origin" "1008 -552 44"
-"light" "250"
-}
-{
-"classname" "monster_demon1"
-"origin" "888 -120 56"
-"angle" "0"
-"spawnflags" "769"
-"targetname" "t66"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "616 184 56"
-"angle" "0"
-"spawnflags" "768"
-}
-{
-"classname" "item_spikes"
-"origin" "880 216 32"
-"spawnflags" "2816"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "1944 728 -8"
-"angle" "0"
-"spawnflags" "769"
-}
-{
-"classname" "light"
-"origin" "-48 1184 -156"
-"light" "200"
-"style" "10"
-}
-{
-"style" "10"
-"light" "200"
-"origin" "0 1024 -120"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "48 800 -120"
-"light" "200"
-"style" "10"
-}
-{
-"style" "10"
-"light" "200"
-"origin" "0 600 -120"
-"classname" "light"
-}
-{
-"classname" "monster_hell_knight"
-"origin" "128 1088 -208"
-"angle" "225"
-"spawnflags" "1"
-}
-{
-"angle" "315"
-"origin" "-104 760 -208"
-"classname" "monster_hell_knight"
-"spawnflags" "1"
-}
-{
-"classname" "item_spikes"
-"origin" "-56 592 -232"
-}
-{
-"classname" "item_health"
-"origin" "-56 920 -232"
-}
-{
-"classname" "monster_demon1"
-"origin" "0 544 -208"
-"angle" "90"
-"target" "t123"
-"spawnflags" "769"
-}
-{
-"mangle" "20 315 0"
-"origin" "1568 2040 -88"
-"classname" "info_intermission"
-}
-{
-"classname" "item_shells"
-"origin" "1528 1968 -352"
-"spawnflags" "3584"
-}
-{
-"origin" "-88 1376 -232"
-"classname" "item_health"
-"spawnflags" "3585"
-}
-{
-"classname" "item_artifact_envirosuit"
-"origin" "1216 1696 -168"
-"spawnflags" "3584"
-}
-{
-"classname" "monster_demon1"
-"origin" "144 372 -208"
-"angle" "180"
-"spawnflags" "768"
-"targetname" "t123"
-}
-{
-"classname" "monster_demon1"
-"origin" "0 528 -208"
-"angle" "90"
-"spawnflags" "1025"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1128 -840 -80"
-"angle" "90"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "656 184 -208"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "-24 1440 -208"
-"angle" "0"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1240 1816 -168"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1032 1568 -168"
-"angle" "0"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*79"
-}
-{
-"classname" "weapon_rocketlauncher"
-"origin" "184 1440 -232"
-"spawnflags" "1792"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1424 608 -104"
-"angle" "270"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "2272 680 -8"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "2240 1472 -200"
-"angle" "270"
-}
-{
-"classname" "weapon_supernailgun"
-"origin" "2236 1184 -32"
-"spawnflags" "1792"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "2424 1824 -200"
-"angle" "180"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1792 2072 -328"
-"angle" "270"
-}
-{
-"classname" "weapon_supershotgun"
-"origin" "1488 1584 -200"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_grenadelauncher"
-"origin" "88 184 -64"
-"spawnflags" "1792"
-}
-{
-"classname" "info_player_deathmatch"
-"origin" "1224 840 -168"
-"angle" "90"
-}
-{
-"classname" "weapon_nailgun"
-"origin" "1024 872 -152"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_supershotgun"
-"origin" "136 1760 -232"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_nailgun"
-"origin" "1976 2288 -352"
-"spawnflags" "1792"
-}
-{
-"classname" "weapon_lightning"
-"origin" "2128 1792 -352"
-"spawnflags" "1792"
-}
-{
-"classname" "item_cells"
-"origin" "1608 728 -128"
-"spawnflags" "1792"
-}
-{
-"spawnflags" "1792"
-"classname" "item_cells"
-"origin" "72 1032 -232"
-}
-{
-"classname" "item_cells"
-"origin" "1008 1328 -192"
-"spawnflags" "1792"
-}
-{
-"classname" "item_cells"
-"origin" "1304 -1160 -96"
-"spawnflags" "1792"
-}
-{
-"origin" "2272 1440 -224"
-"classname" "item_shells"
-"spawnflags" "2816"
-}
-{
-"origin" "224 1736 -232"
-"classname" "item_health"
-}
-{
-"classname" "info_intermission"
-"origin" "1328 -1168 192"
-"mangle" "20 120 0"
-}
-{
-"classname" "info_intermission"
-"origin" "1248 680 8"
-"mangle" "20 130 0"
-}
-{
-"classname" "info_intermission"
-"origin" "1280 1824 -104"
-"mangle" "10 180 0"
-}
-{
-"classname" "light"
-"origin" "-304 888 -80"
-"light" "150"
-}
-{
-"light" "150"
-"origin" "-304 712 -80"
-"classname" "light"
-}
-{
-"classname" "light"
-"origin" "-224 872 -8"
-"light" "125"
-}
-{
-"classname" "light"
-"origin" "-224 728 -8"
-"light" "125"
-}
-{
-"light" "150"
-"origin" "-178 706 -156"
-"classname" "light_torch_small_walltorch"
-}
-{
-"classname" "light"
-"origin" "-320 838 -138"
-"light" "100"
-}
-{
-"light" "100"
-"origin" "-320 774 -138"
-"classname" "light"
-}
-{
-"classname" "info_player_coop"
-"origin" "1192 -1088 -72"
-"angle" "90"
-}
-{
-"angle" "90"
-"origin" "1080 -1088 -72"
-"classname" "info_player_coop"
-}
-{
-"classname" "info_player_coop"
-"origin" "1008 -1112 -72"
-"angle" "90"
-}
-{
-"angle" "90"
-"origin" "1264 -1112 -72"
-"classname" "info_player_coop"
-}
-{
-"classname" "item_armor1"
-"origin" "784 1816 -232"
-}
-{
-"classname" "item_spikes"
-"origin" "-56 1472 -232"
-"spawnflags" "1"
-}
-{
-"classname" "item_rockets"
-"origin" "400 -172 -232"
-}
-{
-"classname" "func_wall"
-"spawnflags" "1792"
-"model" "*80"
-}
-{
-"spawnflags" "1792"
-"classname" "func_wall"
-"model" "*81"
-}
-{
-"classname" "path_corner"
-"origin" "1954 1770 -96"
-"targetname" "t124"
-"target" "t125"
-}
-{
-"classname" "path_corner"
-"origin" "1954 1770 -320"
-"targetname" "t125"
-"target" "t124"
-}
-{
-"classname" "weapon_grenadelauncher"
-"origin" "1688 720 -128"
-"spawnflags" "2048"
-}
-{
-"wait" "-1"
-"angle" "-2"
-"classname" "func_door"
-"targetname" "t126"
-"lip" "-8"
-"model" "*82"
-}
-{
-"classname" "func_door_secret"
-"angle" "90"
-"spawnflags" "2"
-"model" "*83"
-}
-{
-"classname" "light"
-"origin" "-224 832 -152"
-"light" "125"
-}
-{
-"classname" "trigger_counter"
-"target" "t126"
-"targetname" "t127"
-"spawnflags" "1"
-"count" "7"
-"model" "*84"
-}
-{
-"classname" "trigger_once"
-"health" "1"
-"target" "t127"
-"model" "*85"
-}
-{
-"health" "1"
-"classname" "trigger_once"
-"target" "t127"
-"model" "*86"
-}
-{
-"classname" "trigger_once"
-"health" "1"
-"target" "t127"
-"model" "*87"
-}
-{
-"health" "1"
-"classname" "trigger_once"
-"target" "t127"
-"model" "*88"
-}
-{
-"classname" "trigger_once"
-"health" "1"
-"target" "t127"
-"model" "*89"
-}
-{
-"health" "1"
-"classname" "trigger_once"
-"target" "t127"
-"model" "*90"
-}
-{
-"classname" "trigger_once"
-"health" "1"
-"target" "t127"
-"model" "*91"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "1338 -854 -104"
-}
-{
-"classname" "ambient_swamp2"
-"origin" "938 -854 -104"
-}
-{
-"classname" "ambient_drip"
-"origin" "1138 -854 -176"
-}
-{
-"classname" "ambient_drip"
-"origin" "1650 -862 -192"
-}
-{
-"classname" "ambient_drip"
-"origin" "1674 -438 -192"
-}
-{
-"classname" "ambient_drip"
-"origin" "1682 2 -48"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "1674 1986 -280"
-}
-{
-"classname" "ambient_swamp2"
-"origin" "1826 2378 -280"
-}
-{
-"classname" "ambient_swamp1"
-"origin" "2258 2058 -280"
-}
-{
-"classname" "ambient_drip"
-"origin" "746 1370 -376"
-}
-{
-"classname" "ambient_drip"
-"origin" "762 906 -240"
-}
-{
-"origin" "1034 722 -240"
-"classname" "ambient_drip"
-}
-{
-"classname" "ambient_drip"
-"origin" "554 1818 -352"
-}
-{
-"origin" "1002 1810 -352"
-"classname" "ambient_drip"
-}
-{
-"speed" "35"
-"classname" "func_door"
-"wait" "-1"
-"angle" "-2"
-"sounds" "1"
-"targetname" "t101"
-"model" "*92"
-}
-{
-"classname" "light"
-"origin" "1440 296 -80"
-"light" "125"
-}
-{
-"origin" "1792 792 -240"
-"classname" "item_spikes"
-}
diff --git a/Quake/Makefile b/Quake/Makefile
index e0eabc087..bc8ad966e 100644
--- a/Quake/Makefile
+++ b/Quake/Makefile
@@ -10,6 +10,9 @@ DO_USERDIRS=0
### Enable/Disable SDL2
USE_SDL2=1
+### Enable/Disable Curl
+USE_CURL=1
+
### Enable/Disable codecs for streaming music support
USE_CODEC_WAVE=1
USE_CODEC_FLAC=0
@@ -35,9 +38,9 @@ check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/nu
# ---------------------------
-HOST_OS := $(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]')
+HOST_OS = $(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]')
-DEBUG ?= 0
+DEBUG ?= 0
# ---------------------------
# build variables
@@ -50,7 +53,7 @@ STRIP ?= strip
PKG_CONFIG ?= pkg-config
CPUFLAGS=
-LDFLAGS =
+LDFLAGS?=
DFLAGS ?=
CFLAGS ?= -Wall -Wno-trigraphs
CFLAGS += $(call check_gcc,-std=gnu11,)
@@ -76,26 +79,6 @@ ifeq ($(DO_USERDIRS),1)
CFLAGS += -DDO_USERDIRS=1
endif
-### X11BASE only gets used if its in an unusual place
-
-X11DIRS := /usr/X11R7 /usr/local/X11R7 /usr/X11R6 /usr/local/X11R6
-X11BASE_GUESS := $(shell \
- if [ -e /usr/include/X11/Xlib.h ] && \
- [ -e /usr/lib/libX11.a ]; then exit 0; fi; \
- if [ -e /usr/local/include/X11/Xlib.h ] && \
- [ -e /usr/local/lib/libX11.a ]; then exit 0; fi; \
- for DIR in $(X11DIRS); do \
- if [ -e $$DIR/include/X11/Xlib.h ] && \
- [ -e $$DIR/lib/libX11.a ]; then echo $$DIR; break; fi; \
- done )
-
-X11BASE ?= $(X11BASE_GUESS)
-
-ifneq ($(X11BASE),)
-LDFLAGS+= -L$(X11BASE)/lib
-CFLAGS += -I$(X11BASE)/include
-endif
-
ifeq ($(USE_SDL2),1)
CFLAGS += -DUSE_SDL2
endif
@@ -105,17 +88,23 @@ SDL_CONFIG ?= sdl2-config
else
SDL_CONFIG ?= sdl-config
endif
-SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
-SDL_LIBS := $(shell $(SDL_CONFIG) --libs)
+SDL_CFLAGS = $(shell $(SDL_CONFIG) --cflags)
+SDL_LIBS = $(shell $(SDL_CONFIG) --libs)
+NET_LIBS =
ifeq ($(HOST_OS),sunos)
-NET_LIBS :=-lsocket -lnsl -lresolv
-else
-NET_LIBS :=
+NET_LIBS =-lsocket -lnsl -lresolv
+endif
+ifeq ($(HOST_OS),haiku)
+NET_LIBS =-lnetwork
endif
+ifeq ($(USE_CURL),1)
NET_LIBS += -lcurl
CFLAGS += $(shell $(PKG_CONFIG) --cflags libcurl)
+else
+CFLAGS += -DWITHOUT_CURL
+endif
ifneq ($(VORBISLIB),vorbis)
ifneq ($(VORBISLIB),tremor)
@@ -144,7 +133,7 @@ cpp_vorbisdec=-DVORBIS_USE_TREMOR
lib_vorbisdec=-lvorbisidec -logg
endif
-CODECLIBS :=
+CODECLIBS =
ifeq ($(USE_CODEC_WAVE),1)
CFLAGS+= -DUSE_CODEC_WAVE
endif
@@ -184,9 +173,13 @@ ifeq ($(USE_CODEC_UMX),1)
CFLAGS+= -DUSE_CODEC_UMX
endif
-COMMON_LIBS:= -lm -lGL
+ifeq ($(HOST_OS),haiku)
+COMMON_LIBS= -lGL
+else
+COMMON_LIBS= -lGL -lm
+endif
-LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODECLIBS)
+LIBS = $(COMMON_LIBS) $(NET_LIBS) $(CODECLIBS)
# name of this makefile, so we can use it as a dependency
MAKEFILE := $(lastword $(MAKEFILE_LIST))
@@ -195,7 +188,7 @@ MAKEFILE := $(lastword $(MAKEFILE_LIST))
# objects
# ---------------------------
-MUSIC_OBJS:= bgmusic.o \
+MUSIC_OBJS= bgmusic.o \
snd_codec.o \
snd_flac.o \
snd_wave.o \
@@ -207,14 +200,14 @@ MUSIC_OBJS:= bgmusic.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
-COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
-SYSOBJ_SND := snd_sdl.o
-SYSOBJ_CDA := cd_sdl.o
-SYSOBJ_INPUT := in_sdl.o
-SYSOBJ_GL_VID:= gl_vidsdl.o
-SYSOBJ_NET := net_bsd.o net_udp.o
-SYSOBJ_SYS := pl_linux.o sys_sdl_unix.o
-SYSOBJ_MAIN:= main_sdl.o
+COMOBJ_SND = snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
+SYSOBJ_SND = snd_sdl.o
+SYSOBJ_CDA = cd_sdl.o
+SYSOBJ_INPUT = in_sdl.o
+SYSOBJ_GL_VID= gl_vidsdl.o
+SYSOBJ_NET = net_bsd.o net_udp.o
+SYSOBJ_SYS = pl_linux.o sys_sdl_unix.o
+SYSOBJ_MAIN= main_sdl.o
GLOBJS = \
gl_refrag.o \
@@ -238,7 +231,7 @@ GLOBJS = \
r_brush.o \
gl_model.o
-OBJS := strlcat.o \
+OBJS = strlcat.o \
strlcpy.o \
$(GLOBJS) \
$(SYSOBJ_INPUT) \
@@ -292,7 +285,7 @@ OBJS += $(SYSOBJ_RES)
.PHONY: clean debug release
-DEFAULT_TARGET := ironwail
+DEFAULT_TARGET = ironwail
all: $(DEFAULT_TARGET)
%.d: %.c $(MAKEFILE)
@@ -314,9 +307,17 @@ debug:
clean: $(MAKEFILE)
$(RM) *.o *.d $(DEFAULT_TARGET)
+ifeq ($(HOST_OS),haiku)
+IW_APP_DIR=$(shell finddir B_APPS_DIRECTORY)/ironwail/
+install: ironwail
+ mkdir -p $(IW_APP_DIR)
+ cp ironwail $(IW_APP_DIR)
+ cp ironwail.pak $(IW_APP_DIR)
+else
install: ironwail
cp ironwail /usr/local/games/quake
cp ironwail.pak /usr/local/games/quake
+endif
#---------------------------------------------------------------
# include dependencies (if not running 'clean' target)
diff --git a/Quake/Makefile.w32 b/Quake/Makefile.w32
index 379f2a844..7668d5082 100644
--- a/Quake/Makefile.w32
+++ b/Quake/Makefile.w32
@@ -1,4 +1,4 @@
-# GNU Makefile for compiling Win32 ironwail.exe using MinGW or MinGW-w64.
+# GNU Makefile for compiling x86-Windows ironwail.exe using MinGW or MinGW-w64.
# Usage: "make -f Makefile.w32"
# To cross-compile on Linux hosts, see the build_cross_win32*.sh scripts.
# "make DEBUG=1" to build a debug client.
@@ -8,6 +8,9 @@
### Enable/disable SDL2
USE_SDL2=1
+### Enable/Disable Curl
+USE_CURL=1
+
### Enable/disable codecs for streaming music support
USE_CODEC_WAVE=1
USE_CODEC_FLAC=1
@@ -33,8 +36,8 @@ check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/nu
# ---------------------------
-DEBUG ?= 0
-WINSOCK2?= 0
+DEBUG ?= 0
+WINSOCK2 ?= 0
# ---------------------------
# build variables
@@ -47,7 +50,7 @@ WINDRES = windres
STRIP = strip
CPUFLAGS=
-LDFLAGS = -m32 -mwindows -static-libgcc
+LDFLAGS?= -m32 -mwindows -static-libgcc
DFLAGS ?=
CFLAGS ?= -m32 -Wall -Wno-trigraphs
CFLAGS += $(call check_gcc,-std=gnu11,)
@@ -79,23 +82,27 @@ SDL_CONFIG ?=../Windows/SDL2/bin/sdl2-config --prefix=../Windows/SDL2
else
SDL_CONFIG ?=../Windows/SDL/bin/sdl-config --prefix=../Windows/SDL
endif
-SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
-SDL_LIBS := $(shell $(SDL_CONFIG) --libs)
+SDL_CFLAGS = $(shell $(SDL_CONFIG) --cflags)
+SDL_LIBS = $(shell $(SDL_CONFIG) --libs)
ifeq ($(WINSOCK2),1)
-DEFWINSOCK :=-D_USE_WINSOCK2
-LIBWINSOCK := -lws2_32
+DEFWINSOCK =-D_USE_WINSOCK2
+LIBWINSOCK = -lws2_32
else
-DEFWINSOCK :=
-LIBWINSOCK := -lwsock32
+DEFWINSOCK =
+LIBWINSOCK = -lwsock32
endif
-CFLAGS += $(DEFWINSOCK)
-NET_LIBS := $(LIBWINSOCK)
+CFLAGS += $(DEFWINSOCK)
+NET_LIBS = $(LIBWINSOCK)
+ifeq ($(USE_CURL),1)
NET_LIBS += -lcurl
CFLAGS += -I../Windows/curl/include
LDFLAGS += -L../Windows/curl/lib/x86
+else
+CFLAGS += -DWITHOUT_CURL
+endif
ifneq ($(VORBISLIB),vorbis)
ifneq ($(VORBISLIB),tremor)
@@ -124,7 +131,7 @@ cpp_vorbisdec=-DVORBIS_USE_TREMOR
lib_vorbisdec=-lvorbisidec -logg
endif
-CODECLIBS :=
+CODECLIBS =
ifeq ($(USE_CODEC_WAVE),1)
CFLAGS+= -DUSE_CODEC_WAVE
endif
@@ -175,9 +182,9 @@ CFLAGS+= -DUSE_CODEC_UMX
endif
CFLAGS+= $(CODEC_INC)
-COMMON_LIBS:= -lopengl32 -lwinmm -luuid -lole32
+COMMON_LIBS= -lopengl32 -lwinmm -luuid -lole32
-LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
+LIBS = $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
# name of this makefile, so we can use it as a dependency
MAKEFILE := $(lastword $(MAKEFILE_LIST))
@@ -186,7 +193,7 @@ MAKEFILE := $(lastword $(MAKEFILE_LIST))
# objects
# ---------------------------
-MUSIC_OBJS:= bgmusic.o \
+MUSIC_OBJS= bgmusic.o \
snd_codec.o \
snd_flac.o \
snd_wave.o \
@@ -198,15 +205,15 @@ MUSIC_OBJS:= bgmusic.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
-COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
-SYSOBJ_SND := snd_sdl.o
-SYSOBJ_CDA := cd_sdl.o
-SYSOBJ_INPUT := in_sdl.o
-SYSOBJ_GL_VID:= gl_vidsdl.o
-SYSOBJ_NET := net_win.o net_wins.o net_wipx.o
-SYSOBJ_SYS := pl_win.o sys_sdl_win.o
-SYSOBJ_MAIN:= main_sdl.o
-SYSOBJ_RES := QuakeSpasm.res
+COMOBJ_SND = snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
+SYSOBJ_SND = snd_sdl.o
+SYSOBJ_CDA = cd_sdl.o
+SYSOBJ_INPUT = in_sdl.o
+SYSOBJ_GL_VID= gl_vidsdl.o
+SYSOBJ_NET = net_win.o net_wins.o net_wipx.o
+SYSOBJ_SYS = pl_win.o sys_sdl_win.o
+SYSOBJ_MAIN= main_sdl.o
+SYSOBJ_RES = QuakeSpasm.res
GLOBJS = \
gl_refrag.o \
@@ -230,7 +237,7 @@ GLOBJS = \
r_brush.o \
gl_model.o
-OBJS := strlcat.o \
+OBJS = strlcat.o \
strlcpy.o \
$(GLOBJS) \
$(SYSOBJ_INPUT) \
@@ -284,7 +291,7 @@ OBJS += $(SYSOBJ_RES)
.PHONY: clean debug release
-DEFAULT_TARGET := ironwail.exe
+DEFAULT_TARGET = ironwail.exe
all: $(DEFAULT_TARGET)
%.d: %.c $(MAKEFILE)
diff --git a/Quake/Makefile.w64 b/Quake/Makefile.w64
index 1a4b09a53..2723244a4 100644
--- a/Quake/Makefile.w64
+++ b/Quake/Makefile.w64
@@ -1,4 +1,4 @@
-# GNU Makefile for compiling Win64 ironwail.exe using MinGW-w64.
+# GNU Makefile for compiling x64-Windows ironwail.exe using MinGW-w64.
# Usage: "make -f Makefile.w64"
# To cross-compile on Linux hosts, see the build_cross_win32*.sh scripts.
# "make DEBUG=1" to build a debug client.
@@ -7,6 +7,9 @@
### Enable/disable SDL2
USE_SDL2=1
+### Enable/Disable Curl
+USE_CURL=1
+
### Enable/disable codecs for streaming music support
USE_CODEC_WAVE=1
USE_CODEC_FLAC=1
@@ -32,7 +35,7 @@ check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/nu
# ---------------------------
-DEBUG ?= 0
+DEBUG ?= 0
# ---------------------------
# build variables
@@ -45,7 +48,7 @@ WINDRES = windres
STRIP = strip
CPUFLAGS=
-LDFLAGS = -m64 -mwindows -static-libgcc
+LDFLAGS?= -m64 -mwindows -static-libgcc
DFLAGS ?=
CFLAGS ?= -m64 -Wall -Wno-trigraphs
CFLAGS += $(call check_gcc,-std=gnu11,)
@@ -77,18 +80,22 @@ SDL_CONFIG ?=../Windows/SDL2/bin/sdl2-config --prefix=../Windows/SDL2 --lib-suff
else
SDL_CONFIG ?=../Windows/SDL/bin/sdl-config --prefix=../Windows/SDL --lib-suffix=64
endif
-SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
-SDL_LIBS := $(shell $(SDL_CONFIG) --libs)
+SDL_CFLAGS = $(shell $(SDL_CONFIG) --cflags)
+SDL_LIBS = $(shell $(SDL_CONFIG) --libs)
-DEFWINSOCK :=-D_USE_WINSOCK2
-LIBWINSOCK := -lws2_32
+DEFWINSOCK =-D_USE_WINSOCK2
+LIBWINSOCK = -lws2_32
-CFLAGS += $(DEFWINSOCK)
-NET_LIBS := $(LIBWINSOCK)
+CFLAGS += $(DEFWINSOCK)
+NET_LIBS = $(LIBWINSOCK)
+ifeq ($(USE_CURL),1)
NET_LIBS += -lcurl
CFLAGS += -I../Windows/curl/include
LDFLAGS += -L../Windows/curl/lib/x64
+else
+CFLAGS += -DWITHOUT_CURL
+endif
ifneq ($(VORBISLIB),vorbis)
ifneq ($(VORBISLIB),tremor)
@@ -117,7 +124,7 @@ cpp_vorbisdec=-DVORBIS_USE_TREMOR
lib_vorbisdec=-lvorbisidec -logg
endif
-CODECLIBS :=
+CODECLIBS =
ifeq ($(USE_CODEC_WAVE),1)
CFLAGS+= -DUSE_CODEC_WAVE
endif
@@ -168,9 +175,9 @@ CFLAGS+= -DUSE_CODEC_UMX
endif
CFLAGS+= $(CODEC_INC)
-COMMON_LIBS:= -lopengl32 -lwinmm -luuid -lole32
+COMMON_LIBS= -lopengl32 -lwinmm -luuid -lole32
-LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
+LIBS = $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
# name of this makefile, so we can use it as a dependency
MAKEFILE := $(lastword $(MAKEFILE_LIST))
@@ -179,7 +186,7 @@ MAKEFILE := $(lastword $(MAKEFILE_LIST))
# objects
# ---------------------------
-MUSIC_OBJS:= bgmusic.o \
+MUSIC_OBJS= bgmusic.o \
snd_codec.o \
snd_flac.o \
snd_wave.o \
@@ -191,15 +198,15 @@ MUSIC_OBJS:= bgmusic.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
-COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
-SYSOBJ_SND := snd_sdl.o
-SYSOBJ_CDA := cd_sdl.o
-SYSOBJ_INPUT := in_sdl.o
-SYSOBJ_GL_VID:= gl_vidsdl.o
-SYSOBJ_NET := net_win.o net_wins.o net_wipx.o
-SYSOBJ_SYS := pl_win.o sys_sdl_win.o
-SYSOBJ_MAIN:= main_sdl.o
-SYSOBJ_RES := QuakeSpasm.res
+COMOBJ_SND = snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
+SYSOBJ_SND = snd_sdl.o
+SYSOBJ_CDA = cd_sdl.o
+SYSOBJ_INPUT = in_sdl.o
+SYSOBJ_GL_VID= gl_vidsdl.o
+SYSOBJ_NET = net_win.o net_wins.o net_wipx.o
+SYSOBJ_SYS = pl_win.o sys_sdl_win.o
+SYSOBJ_MAIN= main_sdl.o
+SYSOBJ_RES = QuakeSpasm.res
GLOBJS = \
gl_refrag.o \
@@ -223,7 +230,7 @@ GLOBJS = \
r_brush.o \
gl_model.o
-OBJS := strlcat.o \
+OBJS = strlcat.o \
strlcpy.o \
$(GLOBJS) \
$(SYSOBJ_INPUT) \
@@ -277,7 +284,7 @@ OBJS += $(SYSOBJ_RES)
.PHONY: clean debug release
-DEFAULT_TARGET := ironwail.exe
+DEFAULT_TARGET = ironwail.exe
all: $(DEFAULT_TARGET)
%.d: %.c $(MAKEFILE)
diff --git a/Quake/arch_def.h b/Quake/arch_def.h
index 4a27d9ad3..8dd5b86dd 100644
--- a/Quake/arch_def.h
+++ b/Quake/arch_def.h
@@ -72,6 +72,12 @@
# define PLATFORM_RISCOS 1
# endif
+#elif defined(__HAIKU__)
+
+# if !defined(PLATFORM_HAIKU)
+# define PLATFORM_HAIKU 1
+# endif
+
#else /* here goes the unix platforms */
#if defined(__unix) || defined(__unix__) || defined(unix) || \
@@ -159,6 +165,8 @@
# define PLATFORM_STRING "RiscOS"
#elif defined(__GNU__)
# define PLATFORM_STRING "GNU/Hurd"
+#elif defined(PLATFORM_HAIKU)
+# define PLATFORM_STRING "Haiku"
#elif defined(PLATFORM_UNIX)
# define PLATFORM_STRING "Unix"
#else
diff --git a/Quake/build_cross_haiku32-sdl2.sh b/Quake/build_cross_haiku32-sdl2.sh
new file mode 100755
index 000000000..d6c5e559c
--- /dev/null
+++ b/Quake/build_cross_haiku32-sdl2.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Change this script to meet your needs and/or environment.
+
+TARGET=i586-pc-haiku
+
+MAKE_CMD=make
+
+CC="$TARGET-gcc"
+AS="$TARGET-as"
+RANLIB="$TARGET-ranlib"
+AR="$TARGET-ar"
+STRIP="$TARGET-strip"
+LDFLAGS=-L/usr/lib32 # hack
+export CC AS AR RANLIB STRIP LDFLAGS
+
+exec $MAKE_CMD HOST_OS=haiku USE_SDL2=1 LDFLAGS=$LDFLAGS CC=$CC AS=$AS RANLIB=$RANLIB AR=$AR STRIP=$STRIP -f Makefile $*
diff --git a/Quake/build_cross_haiku64-sdl2.sh b/Quake/build_cross_haiku64-sdl2.sh
new file mode 100755
index 000000000..809052833
--- /dev/null
+++ b/Quake/build_cross_haiku64-sdl2.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# Change this script to meet your needs and/or environment.
+
+TARGET=x86_64-unknown-haiku
+
+MAKE_CMD=make
+
+CC="$TARGET-gcc"
+AS="$TARGET-as"
+RANLIB="$TARGET-ranlib"
+AR="$TARGET-ar"
+STRIP="$TARGET-strip"
+export CC AS AR RANLIB STRIP
+
+exec $MAKE_CMD HOST_OS=haiku USE_SDL2=1 CC=$CC AS=$AS RANLIB=$RANLIB AR=$AR STRIP=$STRIP -f Makefile $*
diff --git a/Quake/cl_input.c b/Quake/cl_input.c
index 7fc54e8fa..5a0327bf7 100644
--- a/Quake/cl_input.c
+++ b/Quake/cl_input.c
@@ -248,6 +248,16 @@ cvar_t cl_anglespeedkey = {"cl_anglespeedkey","1.5",CVAR_NONE};
cvar_t cl_alwaysrun = {"cl_alwaysrun","1",CVAR_ARCHIVE}; // QuakeSpasm -- new always run
+/*
+================
+CL_InCutscene
+================
+*/
+qboolean CL_InCutscene (void)
+{
+ return cl.fixangle && !cl.viewent.model;
+}
+
/*
================
CL_AdjustAngles
@@ -260,7 +270,7 @@ void CL_AdjustAngles (void)
float speed;
float up, down;
- if (cl.fixangle)
+ if (CL_InCutscene ())
return;
if ((in_speed.state & 1) ^ (cl_alwaysrun.value != 0.0))
diff --git a/Quake/cl_main.c b/Quake/cl_main.c
index 313c8e8b9..ced627c9a 100644
--- a/Quake/cl_main.c
+++ b/Quake/cl_main.c
@@ -240,6 +240,7 @@ void CL_SignonReply (void)
break;
case 4:
+ cl.spawntime = cl.mtime[0];
SCR_EndLoadingPlaque (); // allow normal screen updates
break;
}
@@ -853,22 +854,22 @@ void CL_Viewpos_f (void)
//camera position
q_snprintf (buf, sizeof (buf),
"(%i %i %i) %i %i %i",
- (int)r_refdef.vieworg[0],
- (int)r_refdef.vieworg[1],
- (int)r_refdef.vieworg[2],
- (int)r_refdef.viewangles[PITCH],
- (int)r_refdef.viewangles[YAW],
- (int)r_refdef.viewangles[ROLL]);
+ Q_rint (r_refdef.vieworg[0]),
+ Q_rint (r_refdef.vieworg[1]),
+ Q_rint (r_refdef.vieworg[2]),
+ Q_rint (r_refdef.viewangles[PITCH]),
+ Q_rint (r_refdef.viewangles[YAW]),
+ Q_rint (r_refdef.viewangles[ROLL]));
#else
//player position
q_snprintf (buf, sizeof (buf),
"(%i %i %i) %i %i %i",
- (int)cl_entities[cl.viewentity].origin[0],
- (int)cl_entities[cl.viewentity].origin[1],
- (int)cl_entities[cl.viewentity].origin[2],
- (int)cl.viewangles[PITCH],
- (int)cl.viewangles[YAW],
- (int)cl.viewangles[ROLL]
+ Q_rint (cl_entities[cl.viewentity].origin[0]),
+ Q_rint (cl_entities[cl.viewentity].origin[1]),
+ Q_rint (cl_entities[cl.viewentity].origin[2]),
+ Q_rint (cl.viewangles[PITCH]),
+ Q_rint (cl.viewangles[YAW]),
+ Q_rint (cl.viewangles[ROLL])
);
#endif
Con_Printf ("Viewpos: %s\n", buf);
@@ -878,6 +879,18 @@ void CL_Viewpos_f (void)
Con_Printf ("Clipboard copy failed: %s\n", SDL_GetError ());
}
+/*
+===============
+CL_Viewpos_Completion_f -- tab completion for the viewpos command
+===============
+*/
+static void CL_Viewpos_Completion_f (const char *partial)
+{
+ if (Cmd_Argc () != 2)
+ return;
+ Con_AddToTabList ("copy", partial, NULL);
+}
+
/*
=============
CL_SetStat_f
@@ -939,6 +952,8 @@ CL_Init
*/
void CL_Init (void)
{
+ cmd_function_t *cmd;
+
SZ_Alloc (&cls.message, 1024);
CL_InitInput ();
@@ -986,7 +1001,9 @@ void CL_Init (void)
Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
Cmd_AddCommand ("tracepos", CL_Tracepos_f); //johnfitz
- Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz
+ cmd = Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz
+ if (cmd)
+ cmd->completion = CL_Viewpos_Completion_f;
Cmd_AddCommand_ServerCommand ("st", CL_SetStat_f);
Cmd_AddCommand_ServerCommand ("sts", CL_SetStatString_f);
diff --git a/Quake/cl_parse.c b/Quake/cl_parse.c
index 1be598644..171cafb77 100644
--- a/Quake/cl_parse.c
+++ b/Quake/cl_parse.c
@@ -97,7 +97,7 @@ const char *svc_strings[] =
"svc_backtolobby", // 55
"svc_localsound" // 56
};
-#define NUM_SVC_STRINGS (sizeof(svc_strings) / sizeof(svc_strings[0]))
+#define NUM_SVC_STRINGS Q_COUNTOF(svc_strings)
qboolean warn_about_nehahra_protocol; //johnfitz
diff --git a/Quake/client.h b/Quake/client.h
index 9aa0090c6..46a8d4403 100644
--- a/Quake/client.h
+++ b/Quake/client.h
@@ -204,6 +204,7 @@ typedef struct
float last_received_message; // (realtime) for net trouble icon
+ float spawntime; // time when signon 4 was received
//
// information that is static for the entire time connected to a server
@@ -341,6 +342,7 @@ void CL_SendMove (const usercmd_t *cmd);
int CL_ReadFromServer (void);
void CL_AdjustAngles (void);
void CL_BaseMove (usercmd_t *cmd);
+qboolean CL_InCutscene (void);
void CL_ParseTEnt (void);
void CL_UpdateTEnts (void);
diff --git a/Quake/cmd.c b/Quake/cmd.c
index 97f272860..05b3d1314 100644
--- a/Quake/cmd.c
+++ b/Quake/cmd.c
@@ -286,7 +286,7 @@ Cmd_Exec_f
void Cmd_Exec_f (void)
{
const char *path;
- char *f;
+ const char *f;
int mark;
if (Cmd_Argc () < 2)
@@ -303,7 +303,7 @@ void Cmd_Exec_f (void)
// "exec config.cfg pls" will execute config.cfg
if (Cmd_Argc () == 2 && !strcmp (path, "config.cfg"))
{
- f = (char *)COM_LoadHunkFile (CONFIG_NAME, NULL);
+ f = (const char *)COM_LoadHunkFile (CONFIG_NAME, NULL);
if (f)
{
path = CONFIG_NAME;
@@ -311,7 +311,7 @@ void Cmd_Exec_f (void)
}
}
- f = (char *)COM_LoadHunkFile (path, NULL);
+ f = (const char *)COM_LoadHunkFile (path, NULL);
if (!f && !strcmp(Cmd_Argv(1), "default.cfg")) {
f = default_cfg; /* see above.. */
}
diff --git a/Quake/common.c b/Quake/common.c
index d1a9e5553..dd74723db 100644
--- a/Quake/common.c
+++ b/Quake/common.c
@@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "miniz.h"
#include "unicode_translit.h"
-static char *largv[MAX_NUM_ARGVS + 1];
+static const char *largv[MAX_NUM_ARGVS + 1];
static char argvdummy[] = " ";
int safemode;
@@ -55,8 +55,8 @@ static void COM_Path_f (void);
#define PAK0_CRC_V091 28804 /* id1/pak0.pak - v0.91/0.92, not supported */
THREAD_LOCAL char com_token[1024];
-int com_argc;
-char **com_argv;
+int com_argc;
+const char **com_argv;
#define CMDLINE_LENGTH 256 /* johnfitz -- mirrored in cmd.c */
char com_cmdline[CMDLINE_LENGTH];
@@ -304,44 +304,22 @@ int q_strncasecmp(const char *s1, const char *s2, size_t n)
return (int)(c1 - c2);
}
-//spike -- grabbed this from fte, because its useful to me
char *q_strcasestr(const char *haystack, const char *needle)
{
- int c1, c2, c2f;
- int i;
- c2f = *needle;
- if (c2f >= 'a' && c2f <= 'z')
- c2f -= ('a' - 'A');
- if (!c2f)
- return (char*)haystack;
- while (1)
+ const size_t len = strlen(needle);
+
+ if (!len)
+ return (char *)haystack;
+
+ while (*haystack)
{
- c1 = *haystack;
- if (!c1)
- return NULL;
- if (c1 >= 'a' && c1 <= 'z')
- c1 -= ('a' - 'A');
- if (c1 == c2f)
- {
- for (i = 1; ; i++)
- {
- c1 = haystack[i];
- c2 = needle[i];
- if (c1 >= 'a' && c1 <= 'z')
- c1 -= ('a' - 'A');
- if (c2 >= 'a' && c2 <= 'z')
- c2 -= ('a' - 'A');
- if (!c2)
- return (char*)haystack; //end of needle means we found a complete match
- if (!c1) //end of haystack means we can't possibly find needle in it any more
- return NULL;
- if (c1 != c2) //mismatch means no match starting at haystack[0]
- break;
- }
- }
- haystack++;
+ if (!q_strncasecmp(haystack, needle, len))
+ return (char *)haystack;
+
+ ++haystack;
}
- return NULL; //didn't find it
+
+ return NULL;
}
char *q_strlwr (char *str)
@@ -1043,6 +1021,37 @@ void SZ_Print (sizebuf_t *buf, const char *data)
//============================================================================
+/*
+============
+COM_FirstPathSep
+
+Returns a pointer to the first path separator, if any, or the end of the string
+============
+*/
+const char *COM_FirstPathSep (const char *path)
+{
+ while (*path && !Sys_IsPathSep (*path))
+ path++;
+ return path;
+}
+
+/*
+============
+COM_NormalizePath
+
+Replaces all path separators with forward slashes
+============
+*/
+void COM_NormalizePath (char *path)
+{
+ while (*path)
+ {
+ if (Sys_IsPathSep (*path))
+ *path = '/';
+ path++;
+ }
+}
+
/*
============
COM_SkipPath
@@ -1314,7 +1323,7 @@ const char *COM_ParseEx (const char *data, cpe_mode mode)
com_token[len] = 0;
return data;
}
- if (len < countof (com_token) - 1)
+ if (len < Q_COUNTOF(com_token) - 1)
com_token[len++] = c;
else if (mode == CPE_NOTRUNC)
return NULL;
@@ -1324,7 +1333,7 @@ const char *COM_ParseEx (const char *data, cpe_mode mode)
// parse single characters
if (c == '{' || c == '}'|| c == '('|| c == ')' || c == '\'' || c == ':')
{
- if (len < countof (com_token) - 1)
+ if (len < Q_COUNTOF(com_token) - 1)
com_token[len++] = c;
else if (mode == CPE_NOTRUNC)
return NULL;
@@ -1335,7 +1344,7 @@ const char *COM_ParseEx (const char *data, cpe_mode mode)
// parse a regular word
do
{
- if (len < countof (com_token) - 1)
+ if (len < Q_COUNTOF(com_token) - 1)
com_token[len++] = c;
else if (mode == CPE_NOTRUNC)
return NULL;
@@ -1424,13 +1433,17 @@ static void COM_CheckRegistered (void)
return;
}
- Sys_FileRead (h, check, sizeof(check));
+ i = Sys_FileRead (h, check, sizeof(check));
COM_CloseFile (h);
+ if (i != (int) sizeof(check))
+ goto corrupt;
for (i = 0; i < 128; i++)
{
if (pop[i] != (unsigned short)BigShort (check[i]))
+ { corrupt:
Sys_Error ("Corrupted data file.");
+ }
}
for (i = 0; com_cmdline[i]; i++)
@@ -1500,6 +1513,22 @@ void COM_InitArgv (int argc, char **argv)
}
}
+/*
+================
+COM_AddArg
+
+Returns the index of the new argument or -1 on overflow
+================
+*/
+int COM_AddArg (const char *arg)
+{
+ if (com_argc >= MAX_NUM_ARGVS)
+ return -1;
+ com_argv[com_argc] = arg;
+ com_argv[com_argc + 1] = argvdummy;
+ return com_argc++;
+}
+
/*
================
COM_Init
@@ -1691,6 +1720,43 @@ char *COM_TempSuffix (unsigned seq)
return buf;
}
+/*
+============
+COM_DescribeDuration
+
+Describes the given duration, e.g. "3 minutes"
+============
+*/
+void COM_DescribeDuration (char *out, size_t outsize, double seconds)
+{
+ const double SECOND = 1;
+ const double MINUTE = 60 * SECOND;
+ const double HOUR = 60 * MINUTE;
+ const double DAY = 24 * HOUR;
+ const double WEEK = 7 * DAY;
+ const double MONTH = 30.436875 * DAY;
+ const double YEAR = 365.2425 * DAY;
+
+ seconds = fabs (seconds);
+
+ if (seconds < 1)
+ q_strlcpy (out, "moments", outsize);
+ else if (seconds < 60 * SECOND)
+ q_snprintf (out, outsize, "%i second%s", PLURAL (seconds));
+ else if (seconds < 90 * MINUTE)
+ q_snprintf (out, outsize, "%i minute%s", PLURAL (seconds / MINUTE));
+ else if (seconds < DAY)
+ q_snprintf (out, outsize, "%i hour%s", PLURAL (seconds / HOUR));
+ else if (seconds < WEEK)
+ q_snprintf (out, outsize, "%i day%s", PLURAL (seconds / DAY));
+ else if (seconds < MONTH)
+ q_snprintf (out, outsize, "%i week%s", PLURAL (seconds / WEEK));
+ else if (seconds < YEAR)
+ q_snprintf (out, outsize, "%i month%s", PLURAL (seconds / MONTH));
+ else
+ q_snprintf (out, outsize, "%i year%s", PLURAL (seconds / YEAR));
+}
+
/*
============
COM_CreatePath
@@ -1920,7 +1986,7 @@ byte *COM_LoadFile (const char *path, int usehunk, unsigned int *path_id)
int h;
byte *buf;
char base[32];
- int len;
+ int len, nread;
buf = NULL; // quiet compiler warning
@@ -1964,8 +2030,10 @@ byte *COM_LoadFile (const char *path, int usehunk, unsigned int *path_id)
((byte *)buf)[len] = 0;
- Sys_FileRead (h, buf, len);
+ nread = Sys_FileRead (h, buf, len);
COM_CloseFile (h);
+ if (nread != len)
+ Sys_Error ("COM_LoadFile: Error reading %s", path);
return buf;
}
@@ -2140,8 +2208,8 @@ static pack_t *COM_LoadPackFile (const char *packfile)
if (Sys_FileOpenRead (packfile, &packhandle) == -1)
return NULL;
- Sys_FileRead (packhandle, (void *)&header, sizeof(header));
- if (header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K')
+ if (Sys_FileRead(packhandle, &header, sizeof(header)) != (int) sizeof(header) ||
+ header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K')
Sys_Error ("%s is not a packfile", packfile);
header.dirofs = LittleLong (header.dirofs);
@@ -2169,7 +2237,8 @@ static pack_t *COM_LoadPackFile (const char *packfile)
newfiles = (packfile_t *) Z_Malloc(numpackfiles * sizeof(packfile_t));
Sys_FileSeek (packhandle, header.dirofs);
- Sys_FileRead (packhandle, (void *)info, header.dirlen);
+ if (Sys_FileRead(packhandle, info, header.dirlen) != header.dirlen)
+ Sys_Error ("Error reading %s", packfile);
// crc the directory to check for modifications
if (!com_modified)
@@ -2262,7 +2331,7 @@ static void COM_AddEnginePak (void)
COM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial
=================
*/
-static void COM_AddGameDirectory (const char *dir)
+void COM_AddGameDirectory (const char *dir)
{
const char *base;
int i, j;
@@ -2328,9 +2397,9 @@ static void COM_AddGameDirectory (const char *dir)
}
}
-void COM_ResetGameDirectories(char *newgamedirs)
+void COM_ResetGameDirectories(const char *newgamedirs)
{
- char *newpath, *path;
+ const char *newpath, *path;
searchpath_t *search;
//Kill the extra game if it is loaded
while (com_searchpaths != com_base_searchpaths)
@@ -2377,11 +2446,73 @@ void COM_ResetGameDirectories(char *newgamedirs)
//==============================================================================
//johnfitz -- dynamic gamedir stuff -- modified by QuakeSpasm team.
//==============================================================================
+
+/*
+=================
+COM_SwitchGame
+=================
+*/
+void COM_SwitchGame (const char *paths)
+{
+ extern cvar_t max_edicts;
+ if (!q_strcasecmp(paths, COM_GetGameNames(true)))
+ {
+ Con_Printf("\"game\" is already \"%s\"\n", COM_GetGameNames(true));
+ return;
+ }
+
+ Host_WaitForSaveThread ();
+
+ com_modified = true;
+
+ //Kill the server
+ CL_Disconnect ();
+ Host_ShutdownServer(true);
+
+ //Write config file
+ Host_WriteConfiguration ();
+
+ // stop parsing map files before changing file system search paths
+ ExtraMaps_Clear ();
+
+ COM_ResetGameDirectories(paths);
+
+ //clear out and reload appropriate data
+ Cache_Flush ();
+ Mod_ResetAll();
+ Sky_ClearAll();
+ if (!isDedicated)
+ {
+ TexMgr_NewGame ();
+ Draw_NewGame ();
+ R_NewGame ();
+ }
+ ExtraMaps_Init ();
+ Host_Resetdemos ();
+ DemoList_Rebuild ();
+ SaveList_Rebuild ();
+ SkyList_Rebuild ();
+ M_CheckMods ();
+ Cvar_SetQuick (&max_edicts, max_edicts.default_string);
+
+ Con_Printf("\n%s\n\"game\" changed to \"%s\"\n", Con_Quakebar (40), COM_GetGameNames(true));
+
+ VID_Lock ();
+ Cbuf_AddText ("unaliasall\n");
+ Cbuf_AddText ("exec quake.rc\n");
+ Cbuf_AddText ("vid_unlock\n");
+}
+
+
+/*
+=================
+COM_Game_f
+=================
+*/
static void COM_Game_f (void)
{
if (Cmd_Argc() > 1)
{
- extern cvar_t max_edicts;
int i, pri;
char paths[1024];
@@ -2424,52 +2555,8 @@ static void COM_Game_f (void)
}
}
- if (!q_strcasecmp(paths, COM_GetGameNames(true)))
- {
- Con_Printf("\"game\" is already \"%s\"\n", COM_GetGameNames(true));
- return;
- }
-
- Host_WaitForSaveThread ();
-
- com_modified = true;
+ COM_SwitchGame (paths);
- //Kill the server
- CL_Disconnect ();
- Host_ShutdownServer(true);
-
- //Write config file
- Host_WriteConfiguration ();
-
- // stop parsing map files before changing file system search paths
- ExtraMaps_Clear ();
-
- COM_ResetGameDirectories(paths);
-
- //clear out and reload appropriate data
- Cache_Flush ();
- Mod_ResetAll();
- Sky_ClearAll();
- if (!isDedicated)
- {
- TexMgr_NewGame ();
- Draw_NewGame ();
- R_NewGame ();
- }
- ExtraMaps_Init ();
- Host_Resetdemos ();
- DemoList_Rebuild ();
- SaveList_Rebuild ();
- SkyList_Rebuild ();
- M_CheckMods ();
- Cvar_SetQuick (&max_edicts, max_edicts.default_string);
-
- Con_Printf("\n%s\n\"game\" changed to \"%s\"\n", Con_Quakebar (40), COM_GetGameNames(true));
-
- VID_Lock ();
- Cbuf_AddText ("unaliasall\n");
- Cbuf_AddText ("exec quake.rc\n");
- Cbuf_AddText ("vid_unlock\n");
}
else //Diplay the current gamedir
Con_Printf("\"game\" is \"%s\"\n", COM_GetGameNames(true));
@@ -2649,6 +2736,206 @@ static void COM_MigrateNightdiveUserFiles (void)
VEC_FREE (subdirs);
}
+/*
+=================
+COM_SetBaseDirRec
+
+Looks for a valid basedir in all the ancestors of the supplied path
+Returns the path relative to that basedir if successful, NULL otherwise
+=================
+*/
+static const char *COM_SetBaseDirRec (const char *start)
+{
+ char buf[MAX_OSPATH];
+ size_t i, len;
+
+ q_strlcpy (buf, start, sizeof (buf));
+ len = strlen (start);
+
+ for (i = len - 1; i > 1; i--)
+ {
+ if (Sys_IsPathSep (buf[i]))
+ {
+ buf[i] = '\0';
+ if (COM_SetBaseDir (buf))
+ return start + i + 1;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+=================
+COM_MakeRelative
+=================
+*/
+static const char *COM_MakeRelative (const char *basepath, const char *fullpath)
+{
+ for (; *basepath && *fullpath; ++basepath, ++fullpath)
+ {
+ if (Sys_IsPathSep (*basepath) != Sys_IsPathSep (*fullpath))
+ return NULL;
+ if (*basepath != *fullpath)
+ return NULL;
+ }
+
+ while (Sys_IsPathSep (*fullpath))
+ ++fullpath;
+
+ return fullpath;
+}
+
+/*
+=================
+COM_PatchCmdLine
+
+Tries to initialize basedir from a single command-line argument
+(either a mod dir or a map/save/demo file)
+
+Returns true if successful, false otherwise
+=================
+*/
+static qboolean COM_PatchCmdLine (const char *fullpath)
+{
+ static char game[MAX_QPATH];
+ char qpath[MAX_QPATH];
+ char printpath[MAX_OSPATH];
+ const char *relpath;
+ const char *sep;
+ int type;
+ int i;
+
+ // The path (file or directory) must exist
+ type = Sys_FileType (fullpath);
+ if (type == FS_ENT_NONE)
+ {
+ UTF8_ToQuake (printpath, sizeof (printpath), fullpath);
+ Con_SafePrintf ("\"%s\" does not exist\n", printpath);
+ return false;
+ }
+
+ // Look for the corresponding basedir
+ relpath = NULL;
+ for (i = 0; i < com_numbasedirs; i++)
+ {
+ relpath = COM_MakeRelative (com_basedirs[i], fullpath);
+ if (relpath)
+ break;
+ }
+ if (!relpath)
+ {
+ UTF8_ToQuake (printpath, sizeof (printpath), fullpath);
+ Con_SafePrintf ("\"%s\" does not belong to an existing Quake installation\n", printpath);
+ return false;
+ }
+
+ // Game dir is the first component of the relative path
+ sep = COM_FirstPathSep (relpath);
+ if ((uintptr_t)(sep - relpath) >= sizeof (game))
+ {
+ UTF8_ToQuake (printpath, sizeof (printpath), relpath);
+ Con_SafePrintf ("\"%s\" is too long\n", printpath);
+ return false;
+ }
+
+ UTF8_ToQuake (printpath, sizeof (printpath), relpath);
+
+ // Apply game dir
+ if (*sep)
+ {
+ Q_strncpy (game, relpath, (int)(sep - relpath));
+ COM_AddArg ("-game");
+ COM_AddArg (game);
+ relpath = sep + 1;
+ }
+ else if (type == FS_ENT_DIRECTORY)
+ {
+ COM_AddArg ("-game");
+ COM_AddArg (relpath);
+ return true;
+ }
+ else
+ {
+ game[0] = '\0';
+ }
+
+ q_strlcpy (qpath, relpath, sizeof (qpath));
+ COM_NormalizePath (qpath);
+
+ // Check argument type
+ switch (type)
+ {
+ case FS_ENT_DIRECTORY:
+ if (qpath[0])
+ {
+ if (q_strcasecmp (qpath, "maps") == 0)
+ {
+ Cbuf_AddText ("menu_maps\n");
+ return true;
+ }
+ UTF8_ToQuake (printpath, sizeof (printpath), qpath);
+ Con_SafePrintf ("\x02subdir \"%s\" ignored\n", printpath);
+ }
+ return true;
+
+ case FS_ENT_FILE:
+ {
+ const char *ext = COM_FileGetExtension (qpath);
+
+ // Map file
+ if (q_strcasecmp (ext, "bsp") == 0)
+ {
+ if (!game[0])
+ {
+ Con_SafePrintf ("Map \"%s\" not in a mod dir, ignoring.\n", printpath);
+ return false;
+ }
+ if (q_strncasecmp (qpath, "maps/", 5) != 0)
+ {
+ Con_SafePrintf ("Map \"%s\" not in the \"maps\" dir, ignoring.\n", printpath);
+ return false;
+ }
+ memmove (qpath, qpath + 5, strlen (qpath + 5) + 1);
+ Cbuf_AddText (va ("menu_maps \"%s\"\n", qpath));
+ return true;
+ }
+
+ // Save file
+ if (q_strcasecmp (ext, "sav") == 0)
+ {
+ const char *kex = game[0] ? "" : "kex";
+ Cbuf_AddText (va ("load \"%s\" %s\n", qpath, kex));
+ return true;
+ }
+
+ // Demo file
+ if (q_strcasecmp (ext, "dem") == 0)
+ {
+ if (!game[0])
+ {
+ Con_SafePrintf ("Demo \"%s\" not in a mod dir, ignoring.\n", printpath);
+ return false;
+ }
+ Cbuf_AddText (va ("playdemo \"%s\"\n", qpath));
+ return true;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (!game[0])
+ Con_SafePrintf ("File \"%s\" not in a mod dir, ignoring.\n", printpath);
+ else
+ Con_SafePrintf ("Unsupported file type \"%s\", ignoring.\n", printpath);
+
+ return false;
+}
+
/*
=================
COM_InitBaseDir
@@ -2832,6 +3119,49 @@ static void COM_InitBaseDir (void)
);
}
+/*
+=================
+COM_ChooseStartArgFlavor
+
+Checks if the supplied path belongs to the user dir
+of a specific Quake flavor (original/remastered)
+and adds the corresponding command-line argument if needed
+=================
+*/
+static void COM_ChooseStartArgFlavor (const char *startarg)
+{
+ steamgame_t steamquake;
+ char steampath[MAX_OSPATH];
+ char userdir[MAX_OSPATH];
+
+ if (Sys_GetAltUserPrefDir (true, userdir, sizeof (userdir)) && COM_MakeRelative (userdir, startarg))
+ {
+ COM_AddArg ("-prefremaster");
+ return;
+ }
+
+ if (Sys_GetAltUserPrefDir (false, userdir, sizeof (userdir)) && COM_MakeRelative (userdir, startarg))
+ {
+ COM_AddArg ("-preforiginal");
+ return;
+ }
+
+ if (Steam_FindGame (&steamquake, QUAKE_STEAM_APPID) &&
+ Steam_ResolvePath (steampath, sizeof (steampath), &steamquake) &&
+ Sys_GetSteamQuakeUserDir (userdir, sizeof (userdir), steamquake.library) &&
+ COM_MakeRelative (userdir, startarg))
+ {
+ COM_AddArg ("-prefremaster");
+ return;
+ }
+
+ if (Sys_GetGOGQuakeEnhancedUserDir (userdir, sizeof (userdir)) && COM_MakeRelative (userdir, startarg))
+ {
+ COM_AddArg ("-prefremaster");
+ return;
+ }
+}
+
/*
=================
COM_InitFilesystem
@@ -2840,18 +3170,26 @@ COM_InitFilesystem
void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial
{
int i;
- const char *p;
+ const char *p, *startarg;
Cvar_RegisterVariable (®istered);
Cvar_RegisterVariable (&cmdline);
Cmd_AddCommand ("path", COM_Path_f);
Cmd_AddCommand ("game", COM_Game_f); //johnfitz
- COM_InitBaseDir ();
+ startarg = (com_argc == 2 && Sys_FileType (com_argv[1]) != FS_ENT_NONE) ? com_argv[1] : NULL;
+ if (startarg)
+ COM_ChooseStartArgFlavor (startarg);
+
+ if (!startarg || !COM_SetBaseDirRec (startarg))
+ COM_InitBaseDir ();
if (host_parms->userdir != host_parms->basedir)
COM_AddBaseDir (host_parms->userdir);
+ if (startarg)
+ COM_PatchCmdLine (startarg);
+
i = COM_CheckParm ("-basegame");
if (i)
{ //-basegame:
@@ -2883,6 +3221,8 @@ void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial
com_base_searchpaths = com_searchpaths;
COM_ResetGameDirectories("");
+ Modlist_Init ();
+
// add mission pack requests (only one should be specified)
if (COM_CheckParm ("-rogue"))
COM_AddGameDirectory ("rogue");
@@ -3713,6 +4053,31 @@ static const uint32_t qchar_to_unicode[256] =
----------------------------------------------------------------------------------------------------------------------------------
*/};
+/*
+==================
+UTF8_CodePointLength
+
+Returns the number of bytes needed to encode the codepoint
+using UTF-8 (max 4), or 0 for an invalid code point
+==================
+*/
+size_t UTF8_CodePointLength (uint32_t codepoint)
+{
+ if (codepoint < 0x80)
+ return 1;
+
+ if (codepoint < 0x800)
+ return 2;
+
+ if (codepoint < 0x10000)
+ return 3;
+
+ if (codepoint < 0x110000)
+ return 4;
+
+ return 0;
+}
+
/*
==================
UTF8_WriteCodePoint
@@ -3836,14 +4201,30 @@ uint32_t UTF8_ReadCodePoint (const char **src)
UTF8_FromQuake
Converts a string from Quake encoding to UTF-8
+
+Returns the number of written characters (including the NUL terminator)
+if a valid output buffer is provided (dst is non-NULL, maxbytes > 0),
+or the total amount of space necessary to encode the entire src string
+if dst is NULL and maxbytes is 0.
==================
*/
-void UTF8_FromQuake (char *dst, size_t maxbytes, const char *src)
+size_t UTF8_FromQuake (char *dst, size_t maxbytes, const char *src)
{
size_t i, j, written;
if (!maxbytes)
- return;
+ {
+ if (dst)
+ return 0; // error
+ for (i = 0, j = 0; src[i]; i++)
+ {
+ uint32_t codepoint = qchar_to_unicode[(unsigned char) src[i]];
+ if (codepoint)
+ j += UTF8_CodePointLength (codepoint);
+ }
+ return j + 1; // include terminator
+ }
+
--maxbytes;
for (i = 0, j = 0; j < maxbytes && src[i]; i++)
@@ -3857,7 +4238,9 @@ void UTF8_FromQuake (char *dst, size_t maxbytes, const char *src)
j += written;
}
- dst[j] = '\0';
+ dst[j++] = '\0';
+
+ return j;
}
/*
@@ -3868,11 +4251,16 @@ Transliterates a string from UTF-8 to Quake encoding
Note: only single-character transliterations are used for now,
mainly to remove diacritics
+
+Returns the number of written characters (including the NUL terminator)
+if a valid output buffer is provided (dst is non-NULL, maxbytes > 0),
+or the total amount of space necessary to encode the entire src string
+if dst is NULL and maxbytes is 0.
==================
*/
-void UTF8_ToQuake (char *dst, size_t maxbytes, const char *src)
+size_t UTF8_ToQuake (char *dst, size_t maxbytes, const char *src)
{
- size_t i;
+ size_t i, j;
if (!unicode_translit_init)
{
@@ -3896,7 +4284,32 @@ void UTF8_ToQuake (char *dst, size_t maxbytes, const char *src)
}
if (!maxbytes)
- return;
+ {
+ if (dst)
+ return 0; // error
+
+ // Determine necessary output buffer size
+ for (i = 0, j = 0; *src; i++)
+ {
+ // ASCII fast path
+ while (*src && (byte)*src < 0x80)
+ {
+ src++;
+ j++;
+ }
+
+ if (!*src)
+ break;
+
+ // Every codepoint maps to a single Quake character
+ UTF8_ReadCodePoint (&src);
+
+ j++;
+ }
+
+ return j + 1; // include terminator
+ }
+
--maxbytes;
for (i = 0; i < maxbytes && *src; i++)
@@ -3924,4 +4337,6 @@ void UTF8_ToQuake (char *dst, size_t maxbytes, const char *src)
}
dst[i++] = '\0';
+
+ return i;
}
diff --git a/Quake/common.h b/Quake/common.h
index 12ad57a39..fb65c1e1d 100644
--- a/Quake/common.h
+++ b/Quake/common.h
@@ -263,7 +263,7 @@ extern char *q_strupr (char *str);
extern int q_snprintf (char *str, size_t size, const char *format, ...) FUNC_PRINTF(3,4);
extern int q_vsnprintf(char *str, size_t size, const char *format, va_list args) FUNC_PRINTF(3,0);
-#define PLURAL(count) (&"s"[(count)==1])
+#define PLURAL(count) ((int)(count)), (&"s"[((int)(count))==1])
//============================================================================
@@ -280,8 +280,8 @@ const char *COM_Parse (const char *data);
const char *COM_ParseEx (const char *data, cpe_mode mode);
-extern int com_argc;
-extern char **com_argv;
+extern int com_argc;
+extern const char **com_argv;
extern int safemode;
/* safe mode: in true, the engine will behave as if one
@@ -296,6 +296,10 @@ void COM_Init (void);
void COM_InitArgv (int argc, char **argv);
void COM_InitFilesystem (void);
+void COM_ResetGameDirectories (const char *newgamedirs);
+void COM_AddGameDirectory (const char *dir);
+void COM_SwitchGame (const char *paths);
+
const char *COM_SkipPath (const char *pathname);
void COM_StripExtension (const char *in, char *out, size_t outsize);
void COM_FileBase (const char *in, char *out, size_t outsize);
@@ -308,6 +312,9 @@ void COM_ExtractExtension (const char *in, char *out, size_t outsize);
char *COM_TempSuffix (unsigned seq);
void COM_CreatePath (char *path);
+// Describes the given duration, e.g. "3 minutes"
+void COM_DescribeDuration (char *out, size_t outsize, double seconds);
+
char *va (const char *format, ...) FUNC_PRINTF(1,2);
// does a varargs printf into a temp buffer
@@ -328,8 +335,8 @@ size_t LOC_Format (const char *format, const char* (*getarg_fn)(int idx, void* u
// Unicode
size_t UTF8_WriteCodePoint (char *dst, size_t maxbytes, uint32_t codepoint);
uint32_t UTF8_ReadCodePoint (const char **src);
-void UTF8_FromQuake (char *dst, size_t maxbytes, const char *src);
-void UTF8_ToQuake (char *dst, size_t maxbytes, const char *src);
+size_t UTF8_FromQuake (char *dst, size_t maxbytes, const char *src);
+size_t UTF8_ToQuake (char *dst, size_t maxbytes, const char *src);
#define UNICODE_UNKNOWN 0xFFFD
#define UNICODE_MAX 0x10FFFF
diff --git a/Quake/console.c b/Quake/console.c
index 4783adf8c..5f7efe5f4 100644
--- a/Quake/console.c
+++ b/Quake/console.c
@@ -34,6 +34,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include
#endif
+extern qboolean keydown[256];
+
int con_linewidth;
float con_cursorspeed = 4;
@@ -65,9 +67,38 @@ typedef struct
conofs_t end;
} conlink_t;
+typedef struct
+{
+ conofs_t begin;
+ conofs_t end;
+} conselection_t;
+
+typedef enum
+{
+ // Used for link hover/clicking:
+ // - picks the character that contains the cursor
+ // - rejects areas outside the visible console region
+ CT_INSIDE,
+
+ // Used for text selection:
+ // - picks the closest edge horizontally, on whichever line contains the cursor vertically
+ // - clamps to the margins of the visible console region
+ CT_NEAREST,
+} contest_t; // Console hit testing mode
+
+typedef enum
+{
+ CMS_NOTPRESSED,
+ CMS_PRESSED,
+ CMS_DRAGGING,
+} conmouse_t;
+
static conlink_t **con_links = NULL;
static conlink_t *con_hotlink = NULL;
+static conmouse_t con_mousestate = CMS_NOTPRESSED;
+static conselection_t con_selection;
+
cvar_t con_notifytime = {"con_notifytime","3",CVAR_NONE}; //seconds
cvar_t con_logcenterprint = {"con_logcenterprint", "1", CVAR_NONE}; //johnfitz
cvar_t con_notifycenter = {"con_notifycenter", "0", CVAR_ARCHIVE};
@@ -82,39 +113,76 @@ double con_times[NUM_CON_TIMES]; // realtime time the line was generated
int con_vislines;
-qboolean con_debuglog = false;
-
qboolean con_initialized;
/*
================
-Con_ScreenToOffset
+Con_GetLine
+================
+*/
+static const char *Con_GetLine (int line)
+{
+ return con_text + (line%con_totallines)*con_linewidth;
+}
-Converts screen (pixel) coordinates to a console offset
-Returns true if the offset is inside the visible portion of the console
+/*
+================
+Con_StrLen
================
*/
-static qboolean Con_ScreenToOffset (int x, int y, conofs_t *ofs)
+static size_t Con_StrLen (int line)
+{
+ const char *text = Con_GetLine (line);
+ size_t len = con_linewidth;
+ while (len > 0 && (char)(text[len - 1] & 0x7f) == ' ')
+ len--;
+ return len;
+}
+
+static void Con_ScreenToCanvas (int x, int y, int *outx, int *outy)
{
drawtransform_t transform;
float px, py;
- qboolean ret = true;
-// screen space to [-1..1]
+ // screen space to [-1..1]
px = (x - glx) * 2.f / (float) glwidth - 1.f;
py = (y - gly) * 2.f / (float) glheight - 1.f;
py = -py;
-
-// [-1..1] to console canvas
+
+ // [-1..1] to console canvas
Draw_GetCanvasTransform (CANVAS_CONSOLE, &transform);
px = (px - transform.offset[0]) / transform.scale[0];
py = (py - transform.offset[1]) / transform.scale[1];
x = (int) (px + 0.5f);
y = (int) (py + 0.5f);
+ *outx = x;
+ *outy = y;
+}
+
+
+/*
+================
+Con_ScreenToOffset
+
+Converts screen (pixel) coordinates to a console offset
+Returns true if the offset is inside the visible portion of the console
+================
+*/
+static qboolean Con_ScreenToOffset (int x, int y, conofs_t *ofs, contest_t testmode)
+{
+ qboolean ret = true;
+
+ Con_ScreenToCanvas (x, y, &x, &y);
+
+// Start from the bottom of the console
y = vid.conheight - y;
+// Apply rounding
+ if (testmode == CT_NEAREST)
+ x += 4;
+
// pixels to characters
x >>= 3;
y >>= 3;
@@ -122,12 +190,36 @@ static qboolean Con_ScreenToOffset (int x, int y, conofs_t *ofs)
// apply margins and scrolling
x -= CON_MARGIN;
y -= 2;
- if (x < 0 || x >= con_linewidth)
- ret = false;
- if (y < 0 || y >= con_vislines)
- ret = false;
- if (con_backscroll && y < 2)
- ret = false;
+
+ if (testmode == CT_INSIDE)
+ {
+ if (x < 0 || x >= con_linewidth)
+ ret = false;
+ if (y < 0 || y >= con_vislines)
+ ret = false;
+ if (con_backscroll && y < 2)
+ ret = false;
+ }
+ else
+ {
+ // Allow the cursor to move one character past the end of the line
+ // by clamping to con_linewidth instead of con_linewidth - 1
+ x = CLAMP (0, x, con_linewidth);
+
+ // Enable selecting the entire bottom line by allowing the cursor
+ // to move to the beginning of the line below it (line -1)
+ y = CLAMP (-1, y, con_vislines);
+ if (y < 0)
+ x = 0;
+
+ // Enable selecting the entire line above the backscroll cutoff by
+ // allowing the cursor to move to the beginning of the line below it
+ if (con_backscroll && y < 2)
+ {
+ x = 0;
+ y = 1;
+ }
+ }
y += con_backscroll;
y = con_current - y;
@@ -164,6 +256,39 @@ static qboolean Con_OfsInRange (const conofs_t *ofs, const conofs_t *begin, cons
return Con_OfsCompare (ofs, begin) >= 0 && Con_OfsCompare (ofs, end) < 0;
}
+/*
+================
+Con_GetCurrentRange
+================
+*/
+static void Con_GetCurrentRange (conofs_t *begin, conofs_t *end)
+{
+ begin->line = con_current - con_totallines + 1;
+ begin->col = 0;
+ end->line = con_current + 1;
+ end->col = 0;
+}
+
+/*
+================
+Con_IntersectRanges
+================
+*/
+static qboolean Con_IntersectRanges (conofs_t *begin, conofs_t *end, const conofs_t *selbegin, const conofs_t *selend)
+{
+ if (Con_OfsCompare (selend, begin) <= 0)
+ return false;
+ if (Con_OfsCompare (end, selbegin) <= 0)
+ return false;
+
+ if (Con_OfsCompare (begin, selbegin) < 0)
+ *begin = *selbegin;
+ if (Con_OfsCompare (selend, end) < 0)
+ *end = *selend;
+
+ return true;
+}
+
/*
================
Con_GetLinkAtOfs
@@ -206,7 +331,7 @@ Returns the link at the given pixel coordinates, if any, or NULL otherwise
static conlink_t *Con_GetLinkAtPixel (int x, int y)
{
conofs_t ofs;
- if (!Con_ScreenToOffset (x, y, &ofs))
+ if (!Con_ScreenToOffset (x, y, &ofs, CT_INSIDE))
return NULL;
return Con_GetLinkAtOfs (&ofs);
}
@@ -223,7 +348,6 @@ static void Con_SetHotLink (conlink_t *link)
if (link == con_hotlink)
return;
con_hotlink = link;
- VID_SetMouseCursor (con_hotlink ? MOUSECURSOR_HAND : MOUSECURSOR_DEFAULT);
}
/*
@@ -234,11 +358,11 @@ Computes the console offset corresponding to the current mouse position
Returns true if the offset is inside the visible portion of the console
================
*/
-static qboolean Con_GetMousePos (conofs_t *ofs)
+static qboolean Con_GetMousePos (conofs_t *ofs, contest_t testmode)
{
int x, y;
SDL_GetMouseState (&x, &y);
- return Con_ScreenToOffset (x, y, ofs);
+ return Con_ScreenToOffset (x, y, ofs, testmode);
}
/*
@@ -251,11 +375,91 @@ Returns the link at the current mouse position, if any, or NULL otherwise
static conlink_t *Con_GetMouseLink (void)
{
conofs_t ofs;
- if (Con_GetMousePos (&ofs))
+ if (Con_GetMousePos (&ofs, CT_INSIDE))
return Con_GetLinkAtOfs (&ofs);
return NULL;
}
+/*
+================
+Con_ClearSelection
+================
+*/
+static void Con_ClearSelection (void)
+{
+ memset (&con_selection, 0, sizeof (con_selection));
+}
+
+/*
+================
+Con_HasSelection
+================
+*/
+static qboolean Con_HasSelection (void)
+{
+ return Con_OfsCompare (&con_selection.begin, &con_selection.end) != 0;
+}
+
+/*
+================
+Con_GetNormalizedSelection
+================
+*/
+static qboolean Con_GetNormalizedSelection (conofs_t *begin, conofs_t *end)
+{
+ conofs_t *selbegin = &con_selection.begin;
+ conofs_t *selend = &con_selection.end;
+ conofs_t tbegin, tend;
+
+ if (Con_OfsCompare (selbegin, selend) > 0)
+ {
+ conofs_t *tmp = selbegin;
+ selbegin = selend;
+ selend = tmp;
+ }
+ *begin = *selbegin;
+ *end = *selend;
+
+ Con_GetCurrentRange (&tbegin, &tend);
+
+ return Con_IntersectRanges (begin, end, &tbegin, &tend);
+}
+
+/*
+================
+Con_SetMouseState
+================
+*/
+static void Con_SetMouseState (conmouse_t state)
+{
+ if (con_mousestate == state)
+ return;
+
+ switch (state)
+ {
+ case CMS_PRESSED:
+ Con_GetMousePos (&con_selection.begin, CT_NEAREST);
+ con_selection.end = con_selection.begin;
+ break;
+
+ case CMS_DRAGGING:
+ Con_SetHotLink (NULL);
+ VID_SetMouseCursor (MOUSECURSOR_IBEAM);
+ break;
+
+ case CMS_NOTPRESSED:
+ if (con_mousestate != CMS_DRAGGING && con_hotlink && !Sys_Explore (con_hotlink->path))
+ S_LocalSound ("misc/menu2.wav");
+ break;
+
+ default:
+ break;
+ }
+
+ con_mousestate = state;
+ Con_ForceMouseMove ();
+}
+
/*
================
Con_Mousemove
@@ -264,21 +468,50 @@ Mouse movement callback
*/
void Con_Mousemove (int x, int y)
{
- Con_SetHotLink (Con_GetLinkAtPixel (x, y));
+ if (con_mousestate == CMS_NOTPRESSED)
+ {
+ Con_SetHotLink (Con_GetLinkAtPixel (x, y));
+ VID_SetMouseCursor (con_hotlink ? MOUSECURSOR_HAND : MOUSECURSOR_DEFAULT);
+ }
+ else
+ {
+ Con_ScreenToOffset (x, y, &con_selection.end, CT_NEAREST);
+ if (Con_OfsCompare (&con_selection.begin, &con_selection.end) != 0)
+ Con_SetMouseState (CMS_DRAGGING);
+ }
}
/*
================
-Con_Click
+Con_ForceMouseMove
+================
+*/
+void Con_ForceMouseMove (void)
+{
+ int x, y;
+ SDL_GetMouseState (&x, &y);
+ Con_Mousemove (x, y);
+}
-Mouse click callback
+/*
+================
+Con_UpdateMouseState
================
*/
-void Con_Click (void)
+static void Con_UpdateMouseState (void)
{
- conlink_t *link = Con_GetMouseLink ();
- if (link && !Sys_Explore (link->path))
- S_LocalSound ("misc/menu2.wav");
+ if (key_dest != key_console)
+ {
+ Con_SetHotLink (NULL);
+ Con_SetMouseState (CMS_NOTPRESSED);
+ Con_ClearSelection ();
+ return;
+ }
+
+ if (!keydown[K_MOUSE1])
+ Con_SetMouseState (CMS_NOTPRESSED);
+ else if (con_mousestate == CMS_NOTPRESSED)
+ Con_SetMouseState (CMS_PRESSED);
}
/*
@@ -370,6 +603,56 @@ static void Con_Clear_f (void)
VEC_CLEAR (con_links);
}
+/*
+================
+Con_CopySelectionToClipboard
+================
+*/
+qboolean Con_CopySelectionToClipboard (void)
+{
+ conofs_t selbegin, selend;
+ conofs_t cursor, eol;
+ char *qtext = NULL;
+ char *utf8 = NULL;
+ size_t maxsize;
+
+ S_LocalSound ("misc/menu2.wav");
+
+ // Get forward selection range
+ if (!Con_GetNormalizedSelection (&selbegin, &selend))
+ return false;
+
+ // Iterate through all lines in the selection
+ for (cursor = selbegin; Con_OfsCompare (&cursor, &selend) <= 0; cursor.line++, cursor.col = 0)
+ {
+ const char *text = Con_GetLine (cursor.line);
+ eol.line = cursor.line;
+ eol.col = Con_StrLen (cursor.line);
+ if (cursor.line == selend.line)
+ eol.col = q_min (eol.col, selend.col);
+ Vec_Append ((void **)&qtext, 1, text + cursor.col, eol.col - cursor.col);
+ if (eol.line != selend.line)
+ VEC_PUSH (qtext, '\n');
+ }
+ VEC_PUSH (qtext, '\0');
+
+ // Convert to UTF-8
+ maxsize = UTF8_FromQuake (NULL, 0, qtext);
+ utf8 = (char *) malloc (maxsize);
+ UTF8_FromQuake (utf8, maxsize, qtext);
+
+ // Copy the UTF-8 text to clipboard
+ SDL_SetClipboardText (utf8);
+
+ // Clean up temporary buffers
+ free (utf8);
+ VEC_FREE (qtext);
+
+ Con_ClearSelection ();
+
+ return true;
+}
+
/*
================
Con_Dump_f -- johnfitz -- adapted from quake2 source
@@ -541,6 +824,33 @@ void Con_CheckResize (void)
}
+/*
+================
+Con_Scroll
+================
+*/
+void Con_Scroll (int lines)
+{
+ if (!lines)
+ return;
+
+ con_backscroll += lines;
+
+ if (lines > 0)
+ {
+ if (con_backscroll > con_totallines - (vid.height>>3) - 1)
+ con_backscroll = con_totallines - (vid.height>>3) - 1;
+ }
+ else
+ {
+ if (con_backscroll < 0)
+ con_backscroll = 0;
+ }
+
+ Con_ForceMouseMove ();
+}
+
+
/*
================
Con_Init
@@ -716,6 +1026,10 @@ static int log_fd = -1; // log file descriptor
/*
================
Con_DebugLog
+
+Writes msg to log if -condebug was specified on the command line
+
+Note: msg is expected to be in UTF-8, not Quake charset
================
*/
void Con_DebugLog(const char *msg)
@@ -723,7 +1037,31 @@ void Con_DebugLog(const char *msg)
if (log_fd == -1)
return;
- write(log_fd, msg, strlen(msg));
+ if (write(log_fd, msg, strlen(msg)) < 0)
+ {
+ close (log_fd);
+ log_fd = -1;
+ fprintf (stderr, "Error writing to log file\n");
+ }
+}
+
+
+/*
+================
+Con_StripControlPrefixes
+================
+*/
+static const char *Con_StripControlPrefixes (const char *txt)
+{
+ // colored text
+ if (txt[0] == 1 || txt[0] == 2)
+ txt++;
+
+ // [skipnotify]
+ if (!Q_strncmp (txt, "[skipnotify]", 12))
+ txt += 12;
+
+ return txt;
}
@@ -746,11 +1084,7 @@ void Con_Printf (const char *fmt, ...)
va_end (argptr);
// also echo to debugging console
- Sys_Printf ("%s", msg);
-
-// log all messages to file
- if (con_debuglog)
- Con_DebugLog(msg);
+ Sys_Printf ("%s", Con_StripControlPrefixes (msg));
if (!con_initialized)
return;
@@ -1026,7 +1360,6 @@ typedef struct tab_s
tab_t *tablist;
//defs from elsewhere
-extern qboolean keydown[256];
extern cmd_function_t *cmd_functions;
#define MAX_ALIAS_NAME 32
typedef struct cmdalias_s
@@ -1293,8 +1626,7 @@ static const arg_completion_type_t arg_completion_types[] =
{ "unbind", CompleteUnbindKeys, NULL },
};
-static const int num_arg_completion_types =
- sizeof(arg_completion_types)/sizeof(arg_completion_types[0]);
+static const int num_arg_completion_types = Q_COUNTOF(arg_completion_types);
/*
============
@@ -1670,6 +2002,39 @@ void Con_DrawInput (void)
}
}
+/*
+================
+Con_DrawSelectionHighlight
+================
+*/
+void Con_DrawSelectionHighlight (int x, int y, int line)
+{
+ conofs_t selbegin, selend;
+ conofs_t begin, end;
+ size_t len;
+
+ if (!Con_GetNormalizedSelection (&selbegin, &selend))
+ return;
+
+ len = Con_StrLen (line);
+ begin.line = line;
+ begin.col = 0;
+ end.line = line;
+ end.col = len;
+
+ if (!Con_IntersectRanges (&begin, &end, &selbegin, &selend))
+ return;
+
+ // Highlight line ends (as in Notepad, Visual Studio etc.)
+ if (end.line != selend.line && end.col == len)
+ end.col++;
+
+ // ...unless we would end up overlapping the console margin
+ end.col = q_min (end.col, con_linewidth);
+
+ Draw_Fill (x + begin.col*8, y, (end.col-begin.col)*8, 8, 220, 1.f);
+}
+
/*
================
Con_DrawConsole -- johnfitz -- heavy revision
@@ -1683,6 +2048,8 @@ void Con_DrawConsole (int lines, qboolean drawinput)
int i, x, y, j, sb, rows;
const char *text;
+ Con_UpdateMouseState ();
+
if (lines <= 0)
return;
@@ -1698,6 +2065,16 @@ void Con_DrawConsole (int lines, qboolean drawinput)
rows -= 2; //for input and version lines
sb = (con_backscroll) ? 2 : 0;
+ for (i = con_current - rows + 1; i <= con_current - sb; i++, y += 8)
+ {
+ j = i - con_backscroll;
+ if (j < 0)
+ j = 0;
+ text = con_text + (j % con_totallines)*con_linewidth;
+ Con_DrawSelectionHighlight (8, y, j);
+ }
+
+ y = vid.conheight - (rows+2)*8; // +2 for input and version lines
for (i = con_current - rows + 1; i <= con_current - sb; i++, y += 8)
{
conofs_t ofs;
@@ -1800,7 +2177,6 @@ void LOG_Init (quakeparms_t *parms)
return;
}
- con_debuglog = true;
Con_DebugLog (va("LOG started on: %s \n", session));
}
diff --git a/Quake/console.h b/Quake/console.h
index 12d6d9e0b..acb8f4d5c 100644
--- a/Quake/console.h
+++ b/Quake/console.h
@@ -35,6 +35,7 @@ extern byte *con_chars;
extern char con_lastcenterstring[]; //johnfitz
void Con_CheckResize (void);
+void Con_Scroll (int lines);
void Con_Init (void);
void Con_DrawConsole (int lines, qboolean drawinput);
void Con_Printf (const char *fmt, ...) FUNC_PRINTF(1,2);
@@ -62,7 +63,8 @@ qboolean Con_Match (const char *str, const char *partial);
void Con_LogCenterPrint (const char *str);
void Con_Mousemove (int x, int y);
-void Con_Click (void);
+void Con_ForceMouseMove (void);
+qboolean Con_CopySelectionToClipboard (void);
//
// debuglog
diff --git a/Quake/default_cfg.h b/Quake/default_cfg.h
index 8001ca335..2984d51f8 100644
--- a/Quake/default_cfg.h
+++ b/Quake/default_cfg.h
@@ -1,6 +1,6 @@
// keep in sync with Misc/qs_pak/default.cfg
-static char default_cfg[] =
+static const char default_cfg[] =
"unbindall\n"
"bind ALT +strafe\n"
diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c
index cf328e758..553954738 100644
--- a/Quake/gl_draw.c
+++ b/Quake/gl_draw.c
@@ -911,7 +911,7 @@ Fills a box of pixels with a single color
void Draw_FillEx (float x, float y, float w, float h, const float *rgb, float alpha)
{
guivertex_t *verts;
-
+
GL_SetCanvasColor (rgb[0], rgb[1], rgb[2], alpha); //johnfitz -- added alpha
Draw_SetTexture (whitetexture);
@@ -1121,12 +1121,19 @@ void Draw_GetCanvasTransform (canvastype type, drawtransform_t *transform)
Draw_Transform (vid.guiwidth/s, vid.guiheight/s, s, CANVAS_ALIGN_CENTERX, CANVAS_ALIGN_CENTERY, transform);
break;
case CANVAS_SBAR:
- s = CLAMP (1.0f, scr_sbarscale.value, (float)vid.guiwidth / 320.0f);
- if (cl.gametype == GAME_DEATHMATCH && scr_hudstyle.value < 1)
+ if (scr_hudstyle.value > 2) // qw hud could cut off if too short
+ s = CLAMP (1.0f, scr_sbarscale.value, (float)vid.guiheight / 240.0f);
+ else
+ s = CLAMP(1.0f, scr_sbarscale.value, (float)vid.guiwidth / 320.0f);
+ if (cl.gametype == GAME_DEATHMATCH && (scr_hudstyle.value < 1 || scr_hudstyle.value > 2) )
Draw_Transform (320, 48, s, CANVAS_ALIGN_LEFT, CANVAS_ALIGN_BOTTOM, transform);
else
Draw_Transform (320, 48, s, CANVAS_ALIGN_CENTERX, CANVAS_ALIGN_BOTTOM, transform);
break;
+ case CANVAS_SBAR_QW_INV:
+ s = CLAMP(1.0f, scr_sbarscale.value, (float)vid.guiheight / 240.0f);
+ Draw_Transform (48, 48, s, CANVAS_ALIGN_RIGHT, CANVAS_ALIGN_BOTTOM, transform);
+ break;
case CANVAS_SBAR2:
s = q_min (vid.guiwidth / 400.0f, vid.guiheight / 225.0f);
s = CLAMP (1.0f, scr_sbarscale.value, s);
diff --git a/Quake/gl_fog.c b/Quake/gl_fog.c
index 4173b4282..14f801c0c 100644
--- a/Quake/gl_fog.c
+++ b/Quake/gl_fog.c
@@ -32,18 +32,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define DEFAULT_DENSITY 0.0
#define DEFAULT_GRAY 0.3
-float fog_density;
-float fog_red;
-float fog_green;
-float fog_blue;
-
-float old_density;
-float old_red;
-float old_green;
-float old_blue;
-
-float fade_time; //duration of fade
-float fade_done; //time when fade will be done
+static float fog_density;
+static float fog_red;
+static float fog_green;
+static float fog_blue;
+
+static float old_density;
+static float old_red;
+static float old_green;
+static float old_blue;
+
+static float fade_time; //duration of fade
+static float fade_done; //time when fade will be done
extern float skyfog;
diff --git a/Quake/gl_mesh.c b/Quake/gl_mesh.c
index e8b94aa15..425124696 100644
--- a/Quake/gl_mesh.c
+++ b/Quake/gl_mesh.c
@@ -122,9 +122,6 @@ void GL_MakeAliasModelDisplayLists (qmodel_t *aliasmodel, aliashdr_t *paliashdr)
GLMesh_LoadVertexBuffer (aliasmodel, pheader);
}
-#define NUMVERTEXNORMALS 162
-extern float r_avertexnormals[NUMVERTEXNORMALS][3];
-
/*
================
GLMesh_LoadVertexBuffer
diff --git a/Quake/gl_model.c b/Quake/gl_model.c
index 766299b38..036f46d5f 100644
--- a/Quake/gl_model.c
+++ b/Quake/gl_model.c
@@ -3234,7 +3234,7 @@ static void *Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int fram
Mod_LoadSpriteGroup
=================
*/
-static void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum)
+static void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum, spriteframetype_t type)
{
dspritegroup_t *pingroup;
mspritegroup_t *pspritegroup;
@@ -3246,6 +3246,8 @@ static void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int fram
pingroup = (dspritegroup_t *)pin;
numframes = LittleLong (pingroup->numframes);
+ if (type == SPR_ANGLED && numframes != 8)
+ Sys_Error ("Mod_LoadSpriteGroup: Bad # of frames: %d", numframes);
pspritegroup = (mspritegroup_t *) Hunk_AllocName (sizeof (mspritegroup_t) +
(numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
@@ -3349,7 +3351,7 @@ static void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer)
else
{
pframetype = (dspriteframetype_t *)
- Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i);
+ Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i, frametype);
}
}
diff --git a/Quake/gl_rmain.c b/Quake/gl_rmain.c
index f9c54355d..1f9e0d935 100644
--- a/Quake/gl_rmain.c
+++ b/Quake/gl_rmain.c
@@ -92,7 +92,7 @@ cvar_t r_clearcolor = {"r_clearcolor","2",CVAR_ARCHIVE};
cvar_t r_flatlightstyles = {"r_flatlightstyles", "0", CVAR_NONE};
cvar_t r_lerplightstyles = {"r_lerplightstyles", "1", CVAR_ARCHIVE}; // 0=off; 1=skip abrupt transitions; 2=always lerp
cvar_t gl_fullbrights = {"gl_fullbrights", "1", CVAR_ARCHIVE};
-cvar_t gl_farclip = {"gl_farclip", "16384", CVAR_ARCHIVE};
+cvar_t gl_farclip = {"gl_farclip", "65536", CVAR_ARCHIVE};
cvar_t gl_overbright_models = {"gl_overbright_models", "1", CVAR_ARCHIVE};
cvar_t r_oldskyleaf = {"r_oldskyleaf", "0", CVAR_NONE};
cvar_t r_drawworld = {"r_drawworld", "1", CVAR_NONE};
diff --git a/Quake/gl_rmisc.c b/Quake/gl_rmisc.c
index dad1b52e4..70ca6a326 100644
--- a/Quake/gl_rmisc.c
+++ b/Quake/gl_rmisc.c
@@ -224,8 +224,6 @@ R_Init
*/
void R_Init (void)
{
- extern cvar_t gl_finish;
-
Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
Cmd_AddCommand ("r_showbboxes_filter", R_ShowbboxesFilter_f);
@@ -310,8 +308,10 @@ void R_TranslatePlayerSkin (int playernum)
//FIXME: if gl_nocolors is on, then turned off, the textures may be out of sync with the scoreboard colors.
if (!gl_nocolors.value)
+ {
if (playertextures[playernum])
TexMgr_ReloadImage (playertextures[playernum], top, bottom);
+ }
}
/*
@@ -394,6 +394,7 @@ static void R_ParseWorldspawn (void)
return; // error
if (com_token[0] != '{')
return; // error
+
while (1)
{
data = COM_Parse(data);
@@ -652,7 +653,7 @@ This must be called if you do anything that could make the cached bindings
invalid (e.g. manually binding, destroying the context).
====================
*/
-void GL_ClearBufferBindings ()
+void GL_ClearBufferBindings (void)
{
int i;
diff --git a/Quake/gl_texmgr.c b/Quake/gl_texmgr.c
index 41a318ded..b0f2ef662 100644
--- a/Quake/gl_texmgr.c
+++ b/Quake/gl_texmgr.c
@@ -55,9 +55,10 @@ static int numgltextures;
static gltexture_t *active_gltextures, *free_gltextures;
gltexture_t *notexture, *nulltexture, *whitetexture, *greytexture, *blacktexture;
+unsigned int d_8to24table_opaque[256]; //standard palette with alpha 255 for all colors
unsigned int d_8to24table[256]; //standard palette, 255 is transparent
unsigned int d_8to24table_fbright[256]; //fullbright palette, 0-223 are black (for additive blending)
-unsigned int d_8to24table_alphabright[256]; //palette with lighting mask in alpha channel (0=fullbright, 1=lit)
+unsigned int d_8to24table_alphabright[256]; //palette with lighting mask in alpha channel (0=fullbright, 255=lit)
unsigned int d_8to24table_fbright_fence[256]; //fullbright palette, for fence textures
unsigned int d_8to24table_nobright[256]; //nobright palette, 224-255 are black (for additive blending)
unsigned int d_8to24table_nobright_fence[256]; //nobright palette, for fence textures
@@ -89,7 +90,7 @@ static const glmode_t glmodes[] = {
{GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, "GL_LINEAR_MIPMAP_NEAREST"},
{GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, "GL_LINEAR_MIPMAP_LINEAR"},
};
-#define NUM_GLMODES (int)(sizeof(glmodes)/sizeof(glmodes[0]))
+#define NUM_GLMODES (int)Q_COUNTOF(glmodes)
static int glmode_idx = 2; /* nearest with linear mips */
static GLuint gl_samplers[NUM_GLMODES * 2]; // x2: nomip + mip
@@ -148,10 +149,8 @@ TexMgr_DescribeTextureModes_f -- report available texturemodes
static void TexMgr_DescribeTextureModes_f (void)
{
int i;
-
for (i = 0; i < NUM_GLMODES; i++)
Con_SafePrintf (" %2i: %s\n", i + 1, glmodes[i].name);
-
Con_Printf ("%i modes\n", i);
}
@@ -742,7 +741,7 @@ void TexMgr_LoadPalette (void)
mark = Hunk_LowMark ();
pal = (byte *) Hunk_Alloc (768);
if (fread (pal, 768, 1, f) != 1)
- Sys_Error ("TexMgr_LoadPalette: read error");
+ Sys_Error ("Failed reading gfx/palette.lmp");
fclose(f);
COM_FOpenFile ("gfx/colormap.lmp", &f, NULL);
@@ -779,7 +778,7 @@ void TexMgr_LoadPalette (void)
src = pal;
for (i = 0; i < 256; i++, src += 3)
{
- SetColor (&d_8to24table[i], src[0], src[1], src[2], 255);
+ SetColor (&d_8to24table_opaque[i], src[0], src[1], src[2], 255);
if (GetBit (is_fullbright, i))
{
SetColor (&d_8to24table_alphabright[i], src[0], src[1], src[2], 0);
@@ -793,6 +792,8 @@ void TexMgr_LoadPalette (void)
SetColor (&d_8to24table_nobright[i], src[0], src[1], src[2], 255);
}
}
+
+ memcpy(d_8to24table, d_8to24table_opaque, 256*4);
((byte *) &d_8to24table[255]) [3] = 0; //standard palette, 255 is transparent
//fullbright palette, for fence textures
@@ -933,8 +934,7 @@ int TexMgr_PadConditional (int s)
{
if (s < TexMgr_SafeTextureSize(s))
return TexMgr_Pad(s);
- else
- return s;
+ return s;
}
/*
@@ -1436,7 +1436,7 @@ static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data)
// choose palette and padbyte
if (glt->flags & TEXPREF_ALPHABRIGHT)
{
- usepal = gl_fullbrights.value ? d_8to24table_alphabright : d_8to24table;
+ usepal = gl_fullbrights.value ? d_8to24table_alphabright : d_8to24table_opaque;
padbyte = 0;
}
else if (glt->flags & TEXPREF_FULLBRIGHT)
@@ -1643,6 +1643,7 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants)
byte translation[256];
byte *src, *dst, *data = NULL, *translated;
int mark, size, i;
+
//
// get source data
//
@@ -1651,6 +1652,7 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants)
if (glt->source_file[0] && glt->source_offset) {
//lump inside file
FILE *f;
+ int sz;
COM_FOpenFile(glt->source_file, &f, NULL);
if (!f) goto invalid;
fseek (f, glt->source_offset, SEEK_CUR);
@@ -1663,12 +1665,12 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants)
size *= lightmap_bytes;
}
data = (byte *) Hunk_Alloc (size);
- if (fread (data, size, 1, f) != 1)
- {
- fclose (f);
- goto invalid;
- }
+ sz = (int) fread (data, 1, size, f);
fclose (f);
+ if (sz != size) {
+ Hunk_FreeToLowMark(mark);
+ Host_Error("Read error for %s", glt->name);
+ }
}
else if (glt->source_file[0] && !glt->source_offset) {
data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height); //simple file
diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c
index 42c79d90e..2d57787cf 100644
--- a/Quake/gl_vidsdl.c
+++ b/Quake/gl_vidsdl.c
@@ -67,6 +67,7 @@ static SDL_Window *draw_context;
static SDL_GLContext gl_context;
static SDL_Cursor *cursor_arrow;
static SDL_Cursor *cursor_hand;
+static SDL_Cursor *cursor_ibeam;
static qboolean vid_locked = false; //johnfitz
static qboolean vid_changed = false;
@@ -181,14 +182,17 @@ static void VID_InitMouseCursors (void)
{
cursor_arrow = SDL_CreateSystemCursor (SDL_SYSTEM_CURSOR_ARROW);
cursor_hand = SDL_CreateSystemCursor (SDL_SYSTEM_CURSOR_HAND);
+ cursor_ibeam = SDL_CreateSystemCursor (SDL_SYSTEM_CURSOR_IBEAM);
}
static void VID_FreeMouseCursors (void)
{
SDL_FreeCursor (cursor_arrow);
SDL_FreeCursor (cursor_hand);
+ SDL_FreeCursor (cursor_ibeam);
cursor_arrow = NULL;
cursor_hand = NULL;
+ cursor_ibeam = NULL;
}
void VID_SetMouseCursor (mousecursor_t cursor)
@@ -203,6 +207,10 @@ void VID_SetMouseCursor (mousecursor_t cursor)
SDL_SetCursor (cursor_hand);
return;
+ case MOUSECURSOR_IBEAM:
+ SDL_SetCursor (cursor_ibeam);
+ return;
+
default:
return;
}
@@ -771,7 +779,7 @@ VID_Test -- johnfitz -- like vid_restart, but asks for confirmation after switch
*/
static void VID_Test (void)
{
- int old_width, old_height, old_refreshrate, old_bpp, old_fullscreen;
+ int old_width, old_height, old_refreshrate, old_fullscreen;
if (vid_locked || !vid_changed)
return;
@@ -781,7 +789,6 @@ static void VID_Test (void)
old_width = VID_GetCurrentWidth();
old_height = VID_GetCurrentHeight();
old_refreshrate = VID_GetCurrentRefreshRate();
- old_bpp = VID_GetCurrentBPP();
old_fullscreen = VID_GetFullscreen() ? true : false;
VID_Restart ();
@@ -1280,10 +1287,10 @@ static void GL_Init (void)
gl_version = (const char *) glGetString (GL_VERSION);
glGetIntegerv (GL_NUM_EXTENSIONS, &gl_num_extensions);
- Con_SafePrintf ("GL_VENDOR: %s\n", gl_vendor);
+ Con_SafePrintf ("GL_VENDOR: %s\n", gl_vendor);
Con_SafePrintf ("GL_RENDERER: %s\n", gl_renderer);
- Con_SafePrintf ("GL_VERSION: %s\n", gl_version);
-
+ Con_SafePrintf ("GL_VERSION: %s\n", gl_version);
+
if (gl_version == NULL || sscanf(gl_version, "%d.%d", &gl_version_major, &gl_version_minor) < 2)
{
gl_version_major = 0;
@@ -1412,6 +1419,10 @@ void VID_Shutdown (void)
if (vid_initialized)
{
VID_FreeMouseCursors();
+ SDL_GL_DeleteContext(gl_context);
+ gl_context = NULL;
+ SDL_DestroyWindow(draw_context);
+ draw_context = NULL;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
draw_context = NULL;
gl_context = NULL;
@@ -1585,7 +1596,7 @@ void VID_Init (void)
{
static char vid_center[] = "SDL_VIDEO_CENTERED=center";
int p, width, height, refreshrate;
- int display_width, display_height, display_refreshrate, display_bpp;
+ int display_width, display_height, display_refreshrate;
qboolean fullscreen;
cmd_function_t *cmd;
const char *read_vars[] =
@@ -1603,7 +1614,7 @@ void VID_Init (void)
"r_softemu_metric",
"scr_pixelaspect",
};
-#define num_readvars ( sizeof(read_vars)/sizeof(read_vars[0]) )
+#define num_readvars Q_COUNTOF(read_vars)
Con_SafePrintf ("\nVideo initialization\n");
@@ -1663,7 +1674,6 @@ void VID_Init (void)
display_width = mode.w;
display_height = mode.h;
display_refreshrate = mode.refresh_rate;
- display_bpp = SDL_BITSPERPIXEL(mode.format);
}
Cvar_SetValueQuick (&vid_width, (float)display_width);
diff --git a/Quake/glquake.h b/Quake/glquake.h
index 6e05218be..ce5c2a320 100644
--- a/Quake/glquake.h
+++ b/Quake/glquake.h
@@ -105,6 +105,7 @@ extern cvar_t r_scale;
extern cvar_t gl_clear;
extern cvar_t gl_polyblend;
extern cvar_t gl_nocolors;
+extern cvar_t gl_finish;
extern cvar_t gl_playermip;
@@ -360,6 +361,9 @@ extern qboolean r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheats
extern float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; //ericw
extern float map_fallbackalpha; //spike -- because we might want r_wateralpha to apply to teleporters while water itself wasn't watervised
+#define NUMVERTEXNORMALS 162
+extern const float r_avertexnormals[NUMVERTEXNORMALS][3];
+
//johnfitz -- fog functions called from outside gl_fog.c
void Fog_ParseServerMessage (void);
float *Fog_GetColor (void);
diff --git a/Quake/host.c b/Quake/host.c
index 926c0b4d5..bd4ce7922 100644
--- a/Quake/host.c
+++ b/Quake/host.c
@@ -629,7 +629,7 @@ void Host_ClearMemory (void)
PR_ClearProgs(&cl.qcvm);
/* host_hunklevel MUST be set at this point */
Hunk_FreeToLowMark (host_hunklevel);
- CL_ClearSignons ();
+ cls.signon = 0; // not CL_ClearSignons()
memset (&sv, 0, sizeof(sv));
CL_FreeState ();
@@ -830,6 +830,7 @@ static void Host_CheckAutosave (void)
if (cls.signon == SIGNONS)
{
+ // Track new secrets
if (pr_global_struct->found_secrets != sv.autosave.prev_secrets)
{
sv.autosave.prev_secrets = pr_global_struct->found_secrets;
@@ -839,41 +840,65 @@ static void Host_CheckAutosave (void)
sv.autosave.secret_boost = q_max (0.f, sv.autosave.secret_boost - host_frametime / 1.5f);
}
+ // Track health changes
if (!sv.autosave.prev_health)
sv.autosave.prev_health = sv_player->v.health;
health_change = sv_player->v.health - sv.autosave.prev_health;
- if (health_change < 0.f && sv_player->v.health < 100.f) // megahealth decay doesn't count as getting hurt
- sv.autosave.hurt_time = qcvm->time;
+ if (health_change < 0.f)
+ if (health_change < -3.f || sv_player->v.health < 100.f || sv_player->v.watertype == CONTENTS_SLIME || sv_player->v.watertype == CONTENTS_LAVA)
+ sv.autosave.hurt_time = qcvm->time;
sv.autosave.prev_health = sv_player->v.health;
+ // Track attacking
if (sv_player->v.button0)
sv.autosave.shoot_time = qcvm->time;
+ // Time spent with cheats active doesn't count
if (sv_player->v.movetype == MOVETYPE_NOCLIP || (int)sv_player->v.flags & (FL_GODMODE|FL_NOTARGET))
{
sv.autosave.cheat += host_frametime;
return;
}
+ // Don't save if the player has been hurt recently
if (qcvm->time - sv.autosave.hurt_time < 3.f)
return;
+
+ // Don't save if the player has fired recently
if (qcvm->time - sv.autosave.shoot_time < 3.f)
return;
+ // Only save when the player slows down a bit
speed = VectorLength (sv_player->v.velocity);
if (speed > 100.f)
return;
+ // Copper's func_void holds the player at the bottom for a bit before inflicting damage,
+ // so we can't assume it's safe to save just because we're no longer falling
+ if ((int)sv_player->v.movetype == MOVETYPE_NONE)
+ return;
+
+ // Don't save too often
elapsed = qcvm->time - sv.autosave.time - sv.autosave.cheat;
if (elapsed < 3.f)
return;
+ // Compute a normalized autosave score
+
+ // Base value is the fraction of the autosave interval already passed
score = elapsed / sv_autosave_interval.value;
+ // Scale down the score if health + armor is below 100 (save less often with lower health)
score *= q_min (100.f, (sv_player->v.health + sv_player->v.armortype * sv_player->v.armorvalue)) / 100.f;
+ // Boost the score right after picking up health
score += q_max (0.f, health_change) / 100.f;
+ // Lower score a bit based on speed (favor standing still/slowing down)
score -= (speed / 100.f) * 0.25f;
+ // Boost the score after finding a secret
score += sv.autosave.secret_boost * 0.25f;
+ // Boost the score after teleporting
score += CLAMP (0.f, 1.f - (qcvm->time - sv_player->v.teleport_time) / 1.5f, 1.f) * 0.5f;
+
+ // Only save if the score is high enough
if (score < 1.f)
return;
@@ -1308,10 +1333,8 @@ void Host_Init (void)
if (host_parms->memsize < minimum_memory)
Sys_Error ("Only %4.1f megs of memory available, can't execute game", host_parms->memsize / (float)0x100000);
- com_argc = host_parms->argc;
- com_argv = host_parms->argv;
-
Memory_Init (host_parms->membase, host_parms->memsize);
+ AsyncQueue_Init (&async_queue, 1024);
Cbuf_Init ();
Cmd_Init ();
LOG_Init (host_parms);
@@ -1329,7 +1352,6 @@ void Host_Init (void)
Mod_Init ();
NET_Init ();
SV_Init ();
- AsyncQueue_Init (&async_queue, 1024);
Con_Printf ("Exe: " __TIME__ " " __DATE__ " (%s %d-bit)\n", SDL_GetPlatform (), (int)sizeof(void*)*8);
Con_Printf ("%4.1f megabyte heap\n", host_parms->memsize/ (1024*1024.0));
@@ -1354,7 +1376,6 @@ void Host_Init (void)
BGM_Init();
Sbar_Init ();
CL_Init ();
- Modlist_Init (); //johnfitz
ExtraMaps_Init (); //johnfitz
DemoList_Init (); //ericw
SaveList_Init ();
diff --git a/Quake/host_cmd.c b/Quake/host_cmd.c
index 180bd8d3b..300446fab 100644
--- a/Quake/host_cmd.c
+++ b/Quake/host_cmd.c
@@ -24,8 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
#include "q_ctype.h"
#include "json.h"
-
+#include
+#ifndef WITHOUT_CURL
#include
+#endif
#define MAX_URL 2048
extern cvar_t pausable;
@@ -569,6 +571,10 @@ typedef struct download_s
static qboolean Download (const char *url, download_t *download)
{
+#ifdef WITHOUT_CURL
+ download->error = "download support disabled at compile time.";
+ return false;
+#else
CURL *curl;
CURLM *multi_handle;
CURLMcode mc;
@@ -647,6 +653,7 @@ static qboolean Download (const char *url, download_t *download)
curl_multi_cleanup (multi_handle);
return !download->error && !still_running && download->response == 200;
+#endif
}
typedef struct
@@ -673,7 +680,11 @@ static SDL_Thread* extramods_install_thread;
const char *Modlist_GetFullName (const filelist_item_t *item)
{
const modinfo_t *info = (const modinfo_t *) (item + 1);
- return info->full_name;
+ const char *full_name = info->full_name;
+ // 2021 rerelease episode names are localized
+ if (full_name && full_name[0] == '$')
+ full_name = LOC_GetRawString (full_name);
+ return full_name;
}
const char *Modlist_GetDescription (const filelist_item_t *item)
@@ -786,8 +797,8 @@ static void Modlist_RegisterAddons (void *param)
"Add-on server status:\n"
"%3d add-on%s available for download\n"
"%3d add-on%s already installed\n\n",
- total - installed, PLURAL (total - installed),
- installed, PLURAL (installed)
+ PLURAL (total - installed),
+ PLURAL (installed)
);
extramods_json = json;
@@ -1076,6 +1087,7 @@ static void Modlist_Add (const char *name)
filelist_item_t *item;
modinfo_t *info;
int i;
+ unsigned int path_id;
memset (&info, 0, sizeof (info));
item = FileList_AddWithData (name, NULL, sizeof (*info), &modlist);
@@ -1113,6 +1125,50 @@ static void Modlist_Add (const char *name)
}
}
+ // look for mapdb.json file
+ if (!info->full_name)
+ {
+ char *mapdb = (char *) COM_LoadMallocFile ("mapdb.json", &path_id);
+ if (mapdb)
+ {
+ qboolean is_base_mapdb = !com_searchpaths || path_id < com_searchpaths->path_id;
+ json_t *json = JSON_Parse (mapdb);
+ free (mapdb);
+ if (json)
+ {
+ const jsonentry_t *episodes = JSON_Find (json->root, "episodes", JSON_ARRAY);
+ if (episodes)
+ {
+ const jsonentry_t *entry;
+ for (entry = episodes->firstchild; entry; entry = entry->next)
+ {
+ const char *mod_name = JSON_FindString (entry, "name");
+ const char *mod_dir = JSON_FindString (entry, "dir");
+ if (!mod_name || !mod_dir)
+ continue;
+
+ // The 2021 rerelease has a single mapdb.json file in id1 with definitions
+ // for all the included episodes (id1, hipnotic, rogue, dopa & mg1).
+ // If the mapdb file comes from a base dir we only use the episode name
+ // if the local mod dir matches the episode dir.
+ // We also perform a dir check if the name of the episode is "copper"
+ // in order to avoid showing all Copper-based mods as "Underdark Overbright"
+ // if they include Copper's mapdb.json unmodified.
+ // In all other cases we skip the dir check so that players can rename mod dirs
+ // as they please without losing their descriptions in the add-on menu.
+ if (is_base_mapdb || q_strcasecmp (mod_dir, "copper") != 0)
+ if (q_strcasecmp (mod_dir, name) != 0)
+ continue;
+
+ info->full_name = strdup (mod_name);
+ break;
+ }
+ }
+ JSON_Free (json);
+ }
+ }
+ }
+
// look for mod in hard-coded list
if (!info->full_name)
{
@@ -1182,7 +1238,11 @@ static void Modlist_FindLocal (void)
continue;
#endif
if (Modlist_Check (find->name, com_basedirs[i]))
+ {
+ COM_AddGameDirectory (find->name);
Modlist_Add (find->name);
+ COM_ResetGameDirectories ("");
+ }
}
}
}
@@ -1246,6 +1306,15 @@ void Modlist_ShutDown (void)
}
}
+qboolean Modlist_IsInstalled (const char *game)
+{
+ filelist_item_t *item;
+ for (item = modlist; item; item = item->next)
+ if (q_strcasecmp (item->name, game) == 0 && Modlist_GetStatus (item) == MODSTATUS_INSTALLED)
+ return true;
+ return false;
+}
+
//==============================================================================
//ericw -- demo list management
//==============================================================================
@@ -1376,12 +1445,22 @@ static qboolean SkyList_AddFile (const char *path)
char skyname[MAX_QPATH];
size_t len;
+ // Check that the file is in the right directory
+ // We need this for pak files, which are all passed to this function
+ // without any kind of path filtering
+ len = strlen (path);
+ if (len <= sizeof (prefix) - 1 || q_strncasecmp (path, prefix, sizeof (prefix) - 1))
+ return false;
+ path += sizeof (prefix) - 1;
+ len -= sizeof (prefix) - 1;
+
+ // Only accept TGA files
ext = COM_FileGetExtension (path);
if (q_strcasecmp (ext, "tga") != 0)
return false;
+ // Check that the image has the right suffix
COM_StripExtension (path, skyname, sizeof (skyname));
- len = strlen (skyname);
if (len < sizeof (suffix) - 1)
return false;
len -= sizeof (suffix) - 1;
@@ -1389,11 +1468,7 @@ static qboolean SkyList_AddFile (const char *path)
return false;
skyname[len] = '\0';
- SDL_assert (len > sizeof (prefix) - 1);
- SDL_assert (!q_strncasecmp (skyname, prefix, sizeof (prefix) - 1));
- if (len <= sizeof (prefix) - 1)
- return false;
-
+ // All ok, add skybox to the list
FileList_Add (skyname + (sizeof (prefix) - 1), &skylist);
return true;
@@ -1714,12 +1789,12 @@ static void Host_SetPos_f(void)
SV_ClientPrintf(" setpos \n");
SV_ClientPrintf("current values:\n");
SV_ClientPrintf(" %i %i %i %i %i %i\n",
- (int)sv_player->v.origin[0],
- (int)sv_player->v.origin[1],
- (int)sv_player->v.origin[2],
- (int)sv_player->v.v_angle[0],
- (int)sv_player->v.v_angle[1],
- (int)sv_player->v.v_angle[2]);
+ Q_rint (sv_player->v.origin[0]),
+ Q_rint (sv_player->v.origin[1]),
+ Q_rint (sv_player->v.origin[2]),
+ Q_rint (sv_player->v.v_angle[0]),
+ Q_rint (sv_player->v.v_angle[1]),
+ Q_rint (sv_player->v.v_angle[2]));
return;
}
@@ -2120,38 +2195,39 @@ Host_SavegameComment
Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
===============
*/
-void Host_SavegameComment (char *text)
+void Host_SavegameComment (char text[SAVEGAME_COMMENT_LENGTH + 1])
{
int i;
char *levelname;
char kills[20];
- char *p1, *p2;
+ char *p;
for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++)
text[i] = ' ';
+ text[SAVEGAME_COMMENT_LENGTH] = '\0';
-// Remove CR/LFs from level name to avoid broken saves, e.g. with autumn_sp map:
-// https://celephais.net/board/view_thread.php?id=60452&start=3666
levelname = cl.levelname[0] ? cl.levelname : cl.mapname;
- p1 = strchr(levelname, '\n');
- p2 = strchr(levelname, '\r');
- if (p1 != NULL) *p1 = 0;
- if (p2 != NULL) *p2 = 0;
i = (int) strlen(levelname);
if (i > 22) i = 22;
memcpy (text, levelname, (size_t)i);
+
+// Remove CR/LFs from level name to avoid broken saves, e.g. with autumn_sp map:
+// https://celephais.net/board/view_thread.php?id=60452&start=3666
+ while ((p = strchr(text, '\n')) != NULL)
+ *p = ' ';
+ while ((p = strchr(text, '\r')) != NULL)
+ *p = ' ';
+
sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
memcpy (text+22, kills, strlen(kills));
+
// convert space to _ to make stdio happy
for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++)
{
if (text[i] == ' ')
text[i] = '_';
}
- if (p1 != NULL) *p1 = '\n';
- if (p2 != NULL) *p2 = '\r';
- text[SAVEGAME_COMMENT_LENGTH] = '\0';
}
static void Host_InvalidateSave (const char *relname)
@@ -2397,11 +2473,12 @@ static void Host_Loadgame_f (void)
int entnum;
int version;
float spawn_parms[NUM_SPAWN_PARMS];
+ qboolean kexonly = false;
if (cmd_source != src_command)
return;
- if (Cmd_Argc() != 2)
+ if (Cmd_Argc() < 2)
{
Con_Printf ("load : load a game\n");
return;
@@ -2413,6 +2490,10 @@ static void Host_Loadgame_f (void)
return;
}
+ // When loading a file that doesn't belong to a mod dir we only accept KEX saves
+ if (Cmd_Argc () >= 3 && q_strcasecmp (Cmd_Argv (2), "kex") == 0)
+ kexonly = true;
+
if (nomonsters.value)
{
Con_Warning ("\"%s\" disabled automatically.\n", nomonsters.name);
@@ -2425,6 +2506,21 @@ static void Host_Loadgame_f (void)
COM_AddExtension (relname, ".sav", sizeof(relname));
q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, relname);
+
+ // Look for savefile in basedirs instead of gamedir
+ if (kexonly || !Sys_FileExists (name))
+ {
+ for (i = com_numbasedirs - 1; i >= 0; i--)
+ {
+ q_snprintf (name, sizeof(name), "%s/%s", com_basedirs[i], relname);
+ if (Sys_FileExists (name))
+ {
+ kexonly = true;
+ break;
+ }
+ }
+ }
+
if (!Sys_FileExists (name))
{
Con_Printf ("ERROR: %s not found.\n", relname);
@@ -2453,14 +2549,33 @@ static void Host_Loadgame_f (void)
data = start;
data = COM_ParseIntNewline (data, &version);
- if (version != SAVEGAME_VERSION)
+ if (version == SAVEGAME_VERSION_KEX)
{
+ extern char com_gamenames[];
+ const char *game = *com_gamenames ? com_gamenames : GAMENAME;
+ data = COM_ParseStringNewline (data);
+ if (strcmp (game, com_token) != 0)
+ {
+ if (!Modlist_IsInstalled (com_token))
+ {
+ Con_Printf ("ERROR: mod \"%s\" is not installed.\n", com_token);
+ return;
+ }
+ COM_SwitchGame (com_token);
+ Cbuf_Execute ();
+ if (key_dest == key_menu)
+ M_ToggleMenu_f ();
+ }
+ }
+ else if (version != SAVEGAME_VERSION || kexonly)
+ {
+ int expected = kexonly ? SAVEGAME_VERSION_KEX : SAVEGAME_VERSION;
free (start);
start = NULL;
if (sv.autoloading)
- Con_Printf ("ERROR: Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
+ Con_Printf ("ERROR: Savegame is version %i, not %i\n", version, expected);
else
- Host_Error ("Savegame is version %i, not %i", version, SAVEGAME_VERSION);
+ Host_Error ("Savegame is version %i, not %i", version, expected);
Host_InvalidateSave (relname);
SCR_EndLoadingPlaque ();
return;
@@ -2539,6 +2654,10 @@ static void Host_Loadgame_f (void)
entnum++;
}
+ // Free edicts allocated during map loading but no longer used after restoring saved game state
+ for (i = entnum; i < qcvm->num_edicts; i++)
+ ED_Free (EDICT_NUM (i));
+
qcvm->num_edicts = entnum;
qcvm->time = time;
sv.autosave.time = time;
@@ -2558,6 +2677,9 @@ static void Host_Loadgame_f (void)
CL_EstablishConnection ("local");
Host_Reconnect_f ();
}
+
+ if (cls.state != ca_dedicated && key_dest == key_game)
+ IN_Activate(); // moved to here from M_Load_Key()
}
//============================================================================
@@ -3017,7 +3139,7 @@ static void Host_Spawn_f (void)
MSG_WriteByte (&host_client->message, svc_signonnum);
MSG_WriteByte (&host_client->message, 3);
- host_client->sendsignon = true;
+ host_client->sendsignon = PRESPAWN_FLUSH;
}
/*
diff --git a/Quake/image.c b/Quake/image.c
index a4857907d..4451b83c3 100644
--- a/Quake/image.c
+++ b/Quake/image.c
@@ -454,7 +454,7 @@ byte *Image_LoadPCX (FILE *f, int *width, int *height)
start = ftell (f); //save start of file (since we might be inside a pak file, SEEK_SET might not be the start of the pcx)
if (fread(&pcx, sizeof(pcx), 1, f) != 1)
- Sys_Error ("Image_LoadPCX: can't read header for '%s'", loadfilename);
+ Sys_Error ("Failed reading header from '%s'", loadfilename);
pcx.xmin = (unsigned short)LittleShort (pcx.xmin);
pcx.ymin = (unsigned short)LittleShort (pcx.ymin);
@@ -479,7 +479,7 @@ byte *Image_LoadPCX (FILE *f, int *width, int *height)
//load palette
fseek (f, start + com_filesize - 768, SEEK_SET);
if (fread (palette, 768, 1, f) != 1)
- Sys_Error ("'%s' has invalid palette", loadfilename);
+ Sys_Error ("Failed reading palette from '%s'", loadfilename);
//back to start of image data
fseek (f, start + sizeof(pcx), SEEK_SET);
diff --git a/Quake/in_sdl.c b/Quake/in_sdl.c
index 1c8784000..7bc917e87 100644
--- a/Quake/in_sdl.c
+++ b/Quake/in_sdl.c
@@ -19,6 +19,9 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+gyro related code is based on
+https://github.com/yquake2/yquake2/blob/master/src/client/input/sdl.c
+
*/
#include "quakedef.h"
@@ -31,7 +34,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern cvar_t ui_mouse;
extern cvar_t language;
-static qboolean textmode;
+static qboolean windowhasfocus = true; //just in case sdl fails to tell us...
+static textmode_t textmode = TEXTMODE_OFF;
static cvar_t in_debugkeys = {"in_debugkeys", "0", CVAR_NONE};
@@ -61,6 +65,16 @@ cvar_t joy_exponent_move = { "joy_exponent_move", "2", CVAR_ARCHIVE };
cvar_t joy_swapmovelook = { "joy_swapmovelook", "0", CVAR_ARCHIVE };
cvar_t joy_enable = { "joy_enable", "1", CVAR_ARCHIVE };
+cvar_t gyro_mode = {"gyro_mode", "0", CVAR_ARCHIVE};
+cvar_t gyro_turning_axis = {"gyro_turning_axis", "0", CVAR_ARCHIVE};
+
+cvar_t gyro_yawsensitivity = {"gyro_yawsensitivity", "2.5", CVAR_ARCHIVE};
+cvar_t gyro_pitchsensitivity= {"gyro_pitchsensitivity", "2.5", CVAR_ARCHIVE};
+
+cvar_t gyro_calibration_x = {"gyro_calibration_x", "0", CVAR_ARCHIVE};
+cvar_t gyro_calibration_y = {"gyro_calibration_y", "0", CVAR_ARCHIVE};
+cvar_t gyro_calibration_z = {"gyro_calibration_z", "0", CVAR_ARCHIVE};
+
static SDL_JoystickID joy_active_instaceid = -1;
static SDL_GameController *joy_active_controller = NULL;
@@ -77,6 +91,15 @@ static int buttonremap[] =
/* total accumulated mouse movement since last frame */
static int total_dx, total_dy = 0;
+static float gyro_yaw, gyro_pitch = 0;
+static float gyro_dir = 1;
+
+// used for gyro calibration
+static float gyro_accum[3];
+static unsigned int num_samples;
+static unsigned int updates_countdown = 0;
+
+static qboolean gyro_active = false;
static int SDLCALL IN_FilterMouseEvents (const SDL_Event *event)
{
@@ -292,7 +315,30 @@ void IN_StartupJoystick (void)
joy_active_instaceid = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller));
joy_active_controller = gamecontroller;
+
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+
+ if (SDL_GameControllerHasLED(joy_active_controller))
+ {
+ // orange LED, seemed fitting for Quake
+ SDL_GameControllerSetLED(joy_active_controller, 80, 20, 0);
+ }
+ if (SDL_GameControllerHasSensor(joy_active_controller, SDL_SENSOR_GYRO)
+ && !SDL_GameControllerSetSensorEnabled(joy_active_controller, SDL_SENSOR_GYRO, SDL_TRUE))
+ {
+#if SDL_VERSION_ATLEAST(2, 0, 16)
+ Con_Printf("Gyro sensor enabled at %.2f Hz\n", SDL_GameControllerGetSensorDataRate(joy_active_controller, SDL_SENSOR_GYRO));
+#else
+ Con_printf("Gyro sensor enabled.\n")
+#endif // SDL_VERSION_ATLEAST(2, 0, 16)
+ }
+ else
+ {
+ Con_Printf("Gyro sensor not found\n");
+ }
break;
+
+#endif // SDL_VERSION_ATLEAST(2, 0, 14)
}
else
{
@@ -311,11 +357,55 @@ void IN_ShutdownJoystick (void)
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
}
+void IN_GyroActionDown (void)
+{
+ switch ((int)gyro_mode.value)
+ {
+ case 1:
+ gyro_active = true;
+ return;
+ case 2:
+ gyro_active = false;
+ return;
+ case 4:
+ gyro_dir = -1;
+ }
+}
+void IN_GyroActionUp (void)
+{
+ switch ((int)gyro_mode.value)
+ {
+ case 1:
+ gyro_active = false;
+ return;
+ case 2:
+ gyro_active = true;
+ return;
+ case 4:
+ gyro_dir = 1;
+ }
+}
+
+void IN_UpdateGyroActive(cvar_t *var)
+{
+ switch ((int)var->value)
+ {
+ case 0:
+ case 1:
+ gyro_active = false;
+ return;
+ case 2:
+ case 3:
+ case 4:
+ gyro_active = true;
+ }
+}
+
void IN_Init (void)
{
textmode = Key_TextEntry();
- if (textmode)
+ if (textmode == TEXTMODE_ON)
SDL_StartTextInput();
else
SDL_StopTextInput();
@@ -344,9 +434,28 @@ void IN_Init (void)
Cvar_RegisterVariable(&joy_swapmovelook);
Cvar_RegisterVariable(&joy_enable);
+ Cvar_RegisterVariable(&gyro_mode);
+ Cvar_SetCallback(&gyro_mode, IN_UpdateGyroActive);
+ Cvar_RegisterVariable(&gyro_turning_axis);
+
+ Cvar_RegisterVariable(&gyro_yawsensitivity);
+ Cvar_RegisterVariable(&gyro_pitchsensitivity);
+
+ Cvar_RegisterVariable(&gyro_calibration_x);
+ Cvar_RegisterVariable(&gyro_calibration_y);
+ Cvar_RegisterVariable(&gyro_calibration_z);
+
+ Cmd_AddCommand ("+gyroaction", IN_GyroActionDown);
+ Cmd_AddCommand ("-gyroaction", IN_GyroActionUp);
+
IN_Activate();
IN_StartupJoystick();
Sys_ActivateKeyFilter(true);
+
+ if ((int)gyro_mode.value == 2)
+ {
+ gyro_active = true;
+ }
}
void IN_Shutdown (void)
@@ -363,7 +472,9 @@ extern cvar_t scr_fov;
void IN_MouseMotion(int dx, int dy)
{
- if (cls.state != ca_connected || cls.signon != SIGNONS || key_dest != key_game || cl.fixangle)
+ if (!windowhasfocus)
+ dx = dy = 0; //don't change view angles etc while unfocused.
+ if (cls.state != ca_connected || cls.signon != SIGNONS || key_dest != key_game || CL_InCutscene ())
{
total_dx = 0;
total_dy = 0;
@@ -507,6 +618,9 @@ Adapted from DarkPlaces by lordhavoc
*/
static void IN_JoyKeyEvent(qboolean wasdown, qboolean isdown, int key, double *timer)
{
+ static const double repeatdelay = 0.5; // time (in seconds) between initial press and first repetition
+ static const double repeatrate = 32.0; // ticks per second
+
// we can't use `realtime` for key repeats because it is not monotomic
const double currenttime = Sys_DoubleTime();
@@ -516,7 +630,7 @@ static void IN_JoyKeyEvent(qboolean wasdown, qboolean isdown, int key, double *t
{
if (currenttime >= *timer)
{
- *timer = currenttime + 0.1;
+ *timer = currenttime + 1.0 / repeatrate;
Key_Event(key, true);
}
}
@@ -530,7 +644,7 @@ static void IN_JoyKeyEvent(qboolean wasdown, qboolean isdown, int key, double *t
{
if (isdown)
{
- *timer = currenttime + 0.5;
+ *timer = currenttime + repeatdelay;
Key_Event(key, true);
}
}
@@ -576,12 +690,49 @@ void IN_Commands (void)
// emit emulated arrow keys so the analog sticks can be used in the menu
if (key_dest != key_game)
{
- IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] < -stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] < -stickthreshold, K_LEFTARROW, &joy_emulatedkeytimer[0]);
- IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] > stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTX] > stickthreshold, K_RIGHTARROW, &joy_emulatedkeytimer[1]);
- IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] < -stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] < -stickthreshold, K_UPARROW, &joy_emulatedkeytimer[2]);
- IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] > stickthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_LEFTY] > stickthreshold, K_DOWNARROW, &joy_emulatedkeytimer[3]);
+ int xaxis = joy_swapmovelook.value ? SDL_CONTROLLER_AXIS_RIGHTX : SDL_CONTROLLER_AXIS_LEFTX;
+ int yaxis = joy_swapmovelook.value ? SDL_CONTROLLER_AXIS_RIGHTY : SDL_CONTROLLER_AXIS_LEFTY;
+ IN_JoyKeyEvent(joy_axisstate.axisvalue[xaxis] < -stickthreshold, newaxisstate.axisvalue[xaxis] < -stickthreshold, K_LEFTARROW, &joy_emulatedkeytimer[0]);
+ IN_JoyKeyEvent(joy_axisstate.axisvalue[xaxis] > stickthreshold, newaxisstate.axisvalue[xaxis] > stickthreshold, K_RIGHTARROW, &joy_emulatedkeytimer[1]);
+ IN_JoyKeyEvent(joy_axisstate.axisvalue[yaxis] < -stickthreshold, newaxisstate.axisvalue[yaxis] < -stickthreshold, K_UPARROW, &joy_emulatedkeytimer[2]);
+ IN_JoyKeyEvent(joy_axisstate.axisvalue[yaxis] > stickthreshold, newaxisstate.axisvalue[yaxis] > stickthreshold, K_DOWNARROW, &joy_emulatedkeytimer[3]);
}
-
+
+ // scroll console with look stick
+ if (key_dest == key_console)
+ {
+ const float scrollthreshold = 0.1f;
+ const float maxscrollspeed = 72.f; // lines per second
+ const float scrollinterval = 1.f / maxscrollspeed;
+ static double timer = 0.0;
+ joyaxis_t raw, deadzone, eased;
+ float scale;
+
+ raw.x = newaxisstate.axisvalue[joy_swapmovelook.value ? SDL_CONTROLLER_AXIS_LEFTX : SDL_CONTROLLER_AXIS_RIGHTX];
+ raw.y = newaxisstate.axisvalue[joy_swapmovelook.value ? SDL_CONTROLLER_AXIS_LEFTY : SDL_CONTROLLER_AXIS_RIGHTY];
+ deadzone = IN_ApplyDeadzone (raw, joy_deadzone_look.value, joy_outer_threshold_look.value);
+ eased = IN_ApplyEasing (deadzone, joy_exponent.value);
+ if (joy_invert.value)
+ eased.y = -eased.y;
+
+ scale = fabs (eased.y);
+ if (scale > scrollthreshold)
+ {
+ scale = (scale - scrollthreshold) / (1.f - scrollthreshold);
+ timer -= scale * host_rawframetime;
+ if (timer < 0.0)
+ {
+ int ticks = (int) ceil (-timer / scrollinterval);
+ timer += ticks * scrollinterval;
+ Con_Scroll (eased.y < 0.0f ? ticks : -ticks);
+ }
+ }
+ else
+ {
+ timer = 0.0;
+ }
+ }
+
// emit emulated keys for the analog triggers
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERLEFT] > triggerthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERLEFT] > triggerthreshold, K_LTRIGGER, &joy_emulatedkeytimer[4]);
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > triggerthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > triggerthreshold, K_RTRIGGER, &joy_emulatedkeytimer[5]);
@@ -641,7 +792,7 @@ void IN_JoyMove (usercmd_t *cmd)
cmd->sidemove += speed * moveEased.x;
cmd->forwardmove -= speed * moveEased.y;
- if (cl.fixangle)
+ if (CL_InCutscene ())
return;
cl.viewangles[YAW] -= lookEased.x * joy_sensitivity_yaw.value * host_frametime;
@@ -657,6 +808,32 @@ void IN_JoyMove (usercmd_t *cmd)
cl.viewangles[PITCH] = cl_minpitch.value;
}
+void IN_GyroMove(usercmd_t *cmd)
+{
+ float scale;
+ if (!joy_enable.value)
+ return;
+
+ if (!joy_active_controller)
+ return;
+
+ if (cl.paused || key_dest != key_game)
+ return;
+
+ if (CL_InCutscene ())
+ return;
+
+ scale = (180.f / M_PI) * gyro_dir * host_frametime;
+ cl.viewangles[YAW] += scale * gyro_yaw * gyro_yawsensitivity.value;
+ cl.viewangles[PITCH] -= scale * gyro_pitch * gyro_pitchsensitivity.value;
+
+ /* johnfitz -- variable pitch clamping */
+ if (cl.viewangles[PITCH] > cl_maxpitch.value)
+ cl.viewangles[PITCH] = cl_maxpitch.value;
+ if (cl.viewangles[PITCH] < cl_minpitch.value)
+ cl.viewangles[PITCH] = cl_minpitch.value;
+}
+
void IN_MouseMove(usercmd_t *cmd)
{
float dmx, dmy;
@@ -704,6 +881,7 @@ void IN_MouseMove(usercmd_t *cmd)
void IN_Move(usercmd_t *cmd)
{
IN_JoyMove(cmd);
+ IN_GyroMove(cmd);
IN_MouseMove(cmd);
}
@@ -713,11 +891,11 @@ void IN_ClearStates (void)
void IN_UpdateInputMode (void)
{
- qboolean want_textmode = Key_TextEntry();
+ textmode_t want_textmode = Key_TextEntry();
if (textmode != want_textmode)
{
textmode = want_textmode;
- if (textmode)
+ if (textmode == TEXTMODE_ON)
{
SDL_StartTextInput();
if (in_debugkeys.value)
@@ -732,6 +910,11 @@ void IN_UpdateInputMode (void)
}
}
+textmode_t IN_GetTextMode (void)
+{
+ return textmode;
+}
+
static inline int IN_SDL2_ScancodeToQuakeKey(SDL_Scancode scancode)
{
switch (scancode)
@@ -873,6 +1056,45 @@ static void IN_DebugKeyEvent(SDL_Event *event)
Sys_DoubleTime());
}
+void IN_StartGyroCalibration (void)
+{
+ Con_Printf ("Calibrating, please wait...\n");
+
+ gyro_accum[0] = 0.0;
+ gyro_accum[1] = 0.0;
+ gyro_accum[2] = 0.0;
+
+ num_samples = 0;
+ updates_countdown = 300;
+}
+
+static void IN_UpdateGyroCalibration (void)
+{
+ if (!updates_countdown)
+ return;
+
+ updates_countdown--;
+ if (!updates_countdown)
+ {
+ const float inverseSamples = 1.f / num_samples;
+ Cvar_SetValue("gyro_calibration_x", gyro_accum[0] * inverseSamples);
+ Cvar_SetValue("gyro_calibration_y", gyro_accum[1] * inverseSamples);
+ Cvar_SetValue("gyro_calibration_z", gyro_accum[2] * inverseSamples);
+
+ Con_Printf("Calibration results:\n X=%f Y=%f Z=%f\n",
+ gyro_calibration_x.value,
+ gyro_calibration_y.value,
+ gyro_calibration_z.value);
+
+ Con_Printf("Calibration finished\n");
+ }
+}
+
+qboolean IN_IsCalibratingGyro (void)
+{
+ return updates_countdown != 0;
+}
+
void IN_SendKeyEvents (void)
{
SDL_Event event;
@@ -887,10 +1109,12 @@ void IN_SendKeyEvents (void)
if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
{
Sys_ActivateKeyFilter(true);
+ windowhasfocus = true;
S_UnblockSound();
}
else if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
{
+ windowhasfocus = false;
S_BlockSound();
Sys_ActivateKeyFilter(false);
}
@@ -923,13 +1147,15 @@ void IN_SendKeyEvents (void)
// SDL2: we interpret the keyboard as the US layout, so keybindings
// are based on key position, not the label on the key cap.
key = IN_SDL2_ScancodeToQuakeKey(event.key.keysym.scancode);
- Key_Event (key, down);
+
+ // also pass along the underlying keycode using the proper current layout for Y/N prompts.
+ Key_EventWithKeycode (key, down, event.key.keysym.sym);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
if (event.button.button < 1 ||
- event.button.button > sizeof(buttonremap) / sizeof(buttonremap[0]))
+ event.button.button > Q_COUNTOF(buttonremap))
{
Con_Printf ("Ignored event for mouse button %d\n",
event.button.button);
@@ -959,6 +1185,40 @@ void IN_SendKeyEvents (void)
IN_MouseMotion(event.motion.xrel, event.motion.yrel);
break;
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+ case SDL_CONTROLLERSENSORUPDATE:
+ if (event.csensor.sensor != SDL_SENSOR_GYRO)
+ {
+ break;
+ }
+ if (updates_countdown)
+ {
+ gyro_accum[0] += event.csensor.data[0];
+ gyro_accum[1] += event.csensor.data[1];
+ gyro_accum[2] += event.csensor.data[2];
+ num_samples++;
+ break;
+ }
+ if (gyro_active && gyro_mode.value)
+ {
+ if (!gyro_turning_axis.value)
+ {
+ gyro_yaw = event.csensor.data[1] - gyro_calibration_y.value; // yaw
+ }
+ else
+ {
+ gyro_yaw = -(event.csensor.data[2] - gyro_calibration_z.value); // roll
+ }
+ gyro_pitch = event.csensor.data[0] - gyro_calibration_x.value;
+ }
+ else
+ {
+ gyro_yaw = gyro_pitch = 0;
+ }
+ break;
+
+#endif // SDL_VERSION_ATLEAST(2, 0, 14)
+
case SDL_CONTROLLERDEVICEADDED:
if (joy_active_instaceid == -1)
{
@@ -970,6 +1230,11 @@ void IN_SendKeyEvents (void)
SDL_Joystick *joy;
joy = SDL_GameControllerGetJoystick(joy_active_controller);
joy_active_instaceid = SDL_JoystickInstanceID(joy);
+ if (SDL_GameControllerHasLED(joy_active_controller))
+ {
+ // orange LED, seemed fitting for Quake
+ SDL_GameControllerSetLED(joy_active_controller, 80, 20, 0);
+ }
}
}
else
@@ -1004,5 +1269,7 @@ void IN_SendKeyEvents (void)
break;
}
}
+
+ IN_UpdateGyroCalibration ();
}
diff --git a/Quake/input.h b/Quake/input.h
index f2131d495..38a1fb4a9 100644
--- a/Quake/input.h
+++ b/Quake/input.h
@@ -19,8 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifndef _QUAKE_INPUT_H
-#define _QUAKE_INPUT_H
+#ifndef QUAKE_INPUT_H
+#define QUAKE_INPUT_H
// input.h -- external (non-keyboard) input devices
@@ -34,6 +34,9 @@ void IN_Commands (void);
// mouse moved by dx and dy pixels
void IN_MouseMotion(int dx, int dy);
+void IN_StartGyroCalibration (void);
+qboolean IN_IsCalibratingGyro (void);
+
void IN_SendKeyEvents (void);
// used as a callback for Sys_SendKeyEvents() by some drivers
@@ -41,6 +44,8 @@ void IN_SendKeyEvents (void);
void IN_UpdateInputMode (void);
// do stuff if input mode (text/non-text) changes matter to the keyboard driver
+enum textmode_t IN_GetTextMode (void);
+
void IN_Move (usercmd_t *cmd);
// add additional movement on top of the keyboard move cmd
@@ -55,5 +60,4 @@ void IN_Deactivate (qboolean free_cursor);
void IN_DeactivateForConsole (void);
void IN_DeactivateForMenu (void);
-#endif /* _QUAKE_INPUT_H */
-
+#endif
diff --git a/Quake/keys.c b/Quake/keys.c
index f3cd2bcea..c18c47dff 100644
--- a/Quake/keys.c
+++ b/Quake/keys.c
@@ -52,7 +52,7 @@ typedef struct
int keynum;
} keyname_t;
-keyname_t keynames[] =
+static const keyname_t keynames[] =
{
{"TAB", K_TAB},
{"ENTER", K_ENTER},
@@ -295,6 +295,7 @@ void Key_Console (int key)
{
case K_ENTER:
case K_KP_ENTER:
+ case K_ABUTTON:
key_tabpartial[0] = 0;
Cbuf_AddText (workline + 1); // skip the prompt
Cbuf_AddText ("\n");
@@ -369,6 +370,7 @@ void Key_Console (int key)
}
else key_linepos = 1;
Con_TabComplete (TABCOMPLETE_AUTOHINT);
+ Con_ForceMouseMove ();
return;
case K_END:
@@ -376,20 +378,17 @@ void Key_Console (int key)
con_backscroll = 0;
else key_linepos = strlen(workline);
Con_TabComplete (TABCOMPLETE_AUTOHINT);
+ Con_ForceMouseMove ();
return;
case K_PGUP:
case K_MWHEELUP:
- con_backscroll += keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2;
- if (con_backscroll > con_totallines - (vid.height>>3) - 1)
- con_backscroll = con_totallines - (vid.height>>3) - 1;
+ Con_Scroll (keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2);
return;
case K_PGDN:
case K_MWHEELDOWN:
- con_backscroll -= keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2;
- if (con_backscroll < 0)
- con_backscroll = 0;
+ Con_Scroll (keydown[K_CTRL] ? -((con_vislines>>3) - 4) : -2);
return;
case K_LEFTARROW:
@@ -478,6 +477,11 @@ void Key_Console (int key)
case K_INS:
if (keydown[K_SHIFT]) /* Shift-Ins paste */
PasteToConsole();
+ else if (keydown[K_CTRL])
+ {
+ Con_CopySelectionToClipboard ();
+ return;
+ }
else key_insert ^= 1;
Con_TabComplete (TABCOMPLETE_AUTOHINT);
return;
@@ -501,6 +505,8 @@ void Key_Console (int key)
case 'c':
case 'C':
if (keydown[K_CTRL]) { /* Ctrl+C: abort the line -- S.A */
+ if (Con_CopySelectionToClipboard ())
+ return;
Con_Printf ("%s\n", workline);
workline[0] = ']';
workline[1] = 0;
@@ -619,7 +625,7 @@ the K_* names are matched up.
*/
int Key_StringToKeynum (const char *str)
{
- keyname_t *kn;
+ const keyname_t *kn;
if (!str || !str[0])
return -1;
@@ -646,7 +652,7 @@ FIXME: handle quote special (general escape sequence?)
const char *Key_KeynumToString (int keynum)
{
static char tinystr[128][2];
- keyname_t *kn;
+ const keyname_t *kn;
if (keynum == -1)
return "";
@@ -968,6 +974,7 @@ void Key_Init (void)
#endif
consolekeys[K_MWHEELUP] = true;
consolekeys[K_MWHEELDOWN] = true;
+ consolekeys[K_ABUTTON] = true;
//
// initialize menubound[]
@@ -1044,6 +1051,21 @@ Should NOT be called during an interrupt!
===================
*/
void Key_Event (int key, qboolean down)
+{
+ Key_EventWithKeycode (key, down, 0);
+}
+
+/*
+===================
+Key_EventWithKeycode
+
+Called by the system between frames for both key up and key down events
+Should NOT be called during an interrupt!
+keycode parameter should have the key's actual keycode using the current keyboard layout,
+not necessarily the US-keyboard-based scancode. Pass 0 if not applicable.
+===================
+*/
+void Key_EventWithKeycode (int key, qboolean down, int keycode)
{
char *kb;
char cmd[1024];
@@ -1085,10 +1107,19 @@ void Key_Event (int key, qboolean down)
if (key_inputgrab.active)
{
if (down)
+ {
key_inputgrab.lastkey = key;
+ if (keycode > 0)
+ key_inputgrab.lastchar = keycode;
+ }
return;
}
+// generate char events if we want text input without popping up an on-screen keyboard
+// when a physical one isn't present, e.g. when using a searchable menu on the Steam Deck
+ if (down && IN_GetTextMode () == TEXTMODE_NOPOPUP)
+ Char_Event (keycode);
+
// handle escape specialy, so the user can never unbind it
if (key == K_ESCAPE)
{
@@ -1138,11 +1169,9 @@ void Key_Event (int key, qboolean down)
kb = keybindings[key];
if (kb && kb[0] == '+')
{
- sprintf (cmd, "-%s %i\n", kb+1, key);
+ q_snprintf (cmd, sizeof (cmd), "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
- if (key_dest == key_console && key == K_MOUSE1 && !down)
- Con_Click ();
return;
}
@@ -1163,7 +1192,7 @@ void Key_Event (int key, qboolean down)
{
if (kb[0] == '+')
{ // button commands add keynum as a parm
- sprintf (cmd, "%s %i\n", kb, key);
+ q_snprintf (cmd, sizeof (cmd), "%s %i\n", kb, key);
Cbuf_AddText (cmd);
}
else
@@ -1246,25 +1275,30 @@ void Char_Event (int key)
Key_TextEntry
===================
*/
-qboolean Key_TextEntry (void)
+textmode_t Key_TextEntry (void)
{
if (key_inputgrab.active)
- return true;
+ {
+ // This path is used for simple single-letter inputs (y/n prompts) that also
+ // accept controller input, so we don't want an onscreen keyboard for this case.
+ return TEXTMODE_NOPOPUP;
+ }
switch (key_dest)
{
case key_message:
- return true;
+ return TEXTMODE_ON;
case key_menu:
return M_TextEntry();
case key_game:
- if (!con_forcedup)
- return false;
- /* fallthrough */
+ // Don't return true even during con_forcedup, because that happens while starting a
+ // game and we don't to trigger text input (and the onscreen keyboard on some devices)
+ // during this.
+ return TEXTMODE_OFF;
case key_console:
- return true;
+ return TEXTMODE_ON;
default:
- return false;
+ return TEXTMODE_OFF;
}
}
diff --git a/Quake/keys.h b/Quake/keys.h
index bf68d57fc..4ef723adc 100644
--- a/Quake/keys.h
+++ b/Quake/keys.h
@@ -163,6 +163,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAXCMDLINE 256
typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
+typedef enum textmode_t
+{
+ TEXTMODE_OFF, // no char events
+ TEXTMODE_ON, // char events, show on-screen keyboard
+ TEXTMODE_NOPOPUP, // char events, don't show on-screen keyboard
+} textmode_t;
extern keydest_t key_dest;
extern char *keybindings[MAX_KEYS];
@@ -187,8 +193,9 @@ void Key_EndInputGrab (void);
void Key_GetGrabbedInput (int *lastkey, int *lastchar);
void Key_Event (int key, qboolean down);
+void Key_EventWithKeycode (int key, qboolean down, int keycode);
void Char_Event (int key);
-qboolean Key_TextEntry (void);
+textmode_t Key_TextEntry (void);
void Key_SetBinding (int keynum, const char *binding);
int Key_GetKeysForCommand (const char *command, int *keys, int maxkeys);
diff --git a/Quake/menu.c b/Quake/menu.c
index 6fc4b3878..98718d7ea 100644
--- a/Quake/menu.c
+++ b/Quake/menu.c
@@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "bgmusic.h"
#include "q_ctype.h"
+#include
+
cvar_t ui_mouse = {"ui_mouse", "1", CVAR_ARCHIVE};
cvar_t ui_mouse_sound = {"ui_mouse_sound", "0", CVAR_ARCHIVE};
cvar_t ui_sound_throttle = {"ui_sound_throttle", "0.1", CVAR_ARCHIVE};
@@ -57,6 +59,20 @@ extern cvar_t r_oit;
extern cvar_t r_alphasort;
extern cvar_t r_lerpmodels;
extern cvar_t r_lerpmove;
+extern cvar_t joy_deadzone_look;
+extern cvar_t joy_deadzone_move;
+extern cvar_t joy_deadzone_trigger;
+extern cvar_t joy_sensitivity_yaw;
+extern cvar_t joy_sensitivity_pitch;
+extern cvar_t joy_invert;
+extern cvar_t joy_exponent;
+extern cvar_t joy_exponent_move;
+extern cvar_t joy_swapmovelook;
+extern cvar_t joy_enable;
+extern cvar_t gyro_mode;
+extern cvar_t gyro_turning_axis;
+extern cvar_t gyro_pitchsensitivity;
+extern cvar_t gyro_yawsensitivity;
extern char crosshair_char;
@@ -86,6 +102,7 @@ void M_Menu_Main_f (void);
void M_Menu_Options_f (void);
void M_Menu_Keys_f (void);
void M_Menu_Video_f (void);
+ void M_Menu_Gamepad_f (void);
void M_Menu_Mods_f (void);
void M_Menu_ModInfo_f (const filelist_item_t *item);
void M_Menu_Help_f (void);
@@ -106,7 +123,8 @@ void M_Main_Draw (void);
void M_ServerList_Draw (void);
void M_Options_Draw (void);
void M_Keys_Draw (void);
- void M_Video_Draw (void);
+ //void M_Video_Draw (void);
+ //void M_Gamepad_Draw (void);
void M_Mods_Draw (void);
void M_ModInfo_Draw (void);
void M_Help_Draw (void);
@@ -127,7 +145,8 @@ void M_Main_Key (int key);
void M_ServerList_Key (int key);
void M_Options_Key (int key);
void M_Keys_Key (int key);
- void M_Video_Key (int key);
+ //void M_Video_Key (int key);
+ //void M_Gamepad_Key (int key);
void M_Mods_Key (int key);
void M_ModInfo_Key (int key);
void M_Help_Key (int key);
@@ -148,7 +167,8 @@ void M_Main_Mousemove (int cx, int cy);
void M_ServerList_Mousemove (int cx, int cy);
void M_Options_Mousemove (int cx, int cy);
void M_Keys_Mousemove (int cx, int cy);
- void M_Video_Mousemove (int cx, int cy);
+ //void M_Video_Mousemove (int cx, int cy);
+ //void M_Gamepad_Mousemove (int cx, int cy);
void M_Mods_Mousemove (int cx, int cy);
//void M_Help_Mousemove (int cx, int cy);
//void M_Quit_Mousemove (int cx, int cy);
@@ -174,8 +194,6 @@ void M_SetSkillMenuMap (const char *name);
void M_Options_SelectMods (void);
void M_Options_Init (enum m_state_e state);
-#define DESCRIPTION_SCROLL_WAIT_TIME 1.0
-
#define SEARCH_FADE_TIMEOUT 0.5
#define SEARCH_TYPE_TIMEOUT 1.5
#define SEARCH_ERASE_TIMEOUT 1.5
@@ -334,7 +352,7 @@ static int M_WordLength (const char *text)
static int M_LineWrap (const char **text, int maxchars)
{
const char *str = *text;
- int i, lastspace = 0;
+ int i;
for (i = 0; i < maxchars && str[i]; /**/)
{
@@ -1045,6 +1063,50 @@ void M_List_Mousemove (menulist_t *list, int yrel)
}
+//=============================================================================
+/* Scrolling ticker */
+
+typedef struct
+{
+ double scroll_time;
+ double scroll_wait_time;
+} menuticker_t;
+
+static void M_Ticker_Init (menuticker_t *ticker)
+{
+ ticker->scroll_time = 0.0;
+ ticker->scroll_wait_time = 1.0;
+}
+
+static void M_Ticker_Update (menuticker_t *ticker)
+{
+ if (ticker->scroll_wait_time <= 0.0)
+ ticker->scroll_time += host_rawframetime;
+ else
+ ticker->scroll_wait_time = q_max (0.0, ticker->scroll_wait_time - host_rawframetime);
+}
+
+static qboolean M_Ticker_Key (menuticker_t *ticker, int key)
+{
+ switch (key)
+ {
+ case K_RIGHTARROW:
+ ticker->scroll_time += 0.25;
+ ticker->scroll_wait_time = 1.5;
+ M_ThrottledSound ("misc/menu3.wav");
+ return true;
+
+ case K_LEFTARROW:
+ ticker->scroll_time -= 0.25;
+ ticker->scroll_wait_time = 1.5;
+ M_ThrottledSound ("misc/menu3.wav");
+ return true;
+
+ default:
+ return false;
+ }
+}
+
//=============================================================================
int m_save_demonum;
@@ -1300,7 +1362,7 @@ void M_SinglePlayer_Key (int key)
{
case 0:
if (sv.active)
- if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n", 0.0f))
+ if (!SCR_ModalMessage("Are you sure you want to\nstart a new game? (y/n)\n", 0.0f))
break;
if (quake64)
{
@@ -1319,15 +1381,15 @@ void M_SinglePlayer_Key (int key)
break;
case 1:
- M_Menu_Load_f ();
+ Cbuf_AddText ("menu_load\n");
break;
case 2:
- M_Menu_Save_f ();
+ Cbuf_AddText ("menu_save\n");
break;
case 3:
- M_Menu_Maps_f ();
+ Cbuf_AddText ("menu_maps\n");
break;
}
}
@@ -1364,10 +1426,14 @@ void M_ScanSaves (void)
loadable[i] = false;
q_snprintf (name, sizeof(name), "%s/s%i.sav", com_gamedir, i);
f = Sys_fopen (name, "r");
- if (!f)
+ if (!f) {
continue;
- fscanf (f, "%i\n", &version);
- fscanf (f, "%79s\n", name);
+ }
+ if (fscanf(f, "%i\n", &version) != 1 ||
+ fscanf(f, "%79s\n", name) != 1) {
+ fclose(f);
+ continue;
+ }
q_strlcpy (m_filenames[i], name, SAVEGAME_COMMENT_LENGTH+1);
// change _ back to space
@@ -1460,7 +1526,6 @@ void M_Load_Key (int k)
if (!loadable[load_cursor])
return;
m_state = m_none;
- IN_Activate();
key_dest = key_game;
// issue the load command
@@ -1558,12 +1623,11 @@ typedef struct
static struct
{
menulist_t list;
+ menuticker_t ticker;
int x, y, cols;
int mapcount; // not all items represent actual maps!
qboolean scrollbar_grab;
int prev_cursor;
- double scroll_time;
- double scroll_wait_time;
mapitem_t *items;
} mapsmenu;
@@ -1664,11 +1728,11 @@ static void M_Maps_Init (void)
mapsmenu.list.cursor = -1;
mapsmenu.list.scroll = 0;
mapsmenu.list.numitems = 0;
- mapsmenu.scroll_time = 0;
- mapsmenu.scroll_wait_time = DESCRIPTION_SCROLL_WAIT_TIME;
mapsmenu.mapcount = 0;
VEC_CLEAR (mapsmenu.items);
+ M_Ticker_Init (&mapsmenu.ticker);
+
for (i = 0, active = -1, prev_type = -1; extralevels_sorted[i]; i++)
{
mapitem_t map;
@@ -1708,6 +1772,29 @@ void M_Menu_Maps_f (void)
m_state = m_maps;
m_entersound = true;
M_Maps_Init ();
+
+ // Handle optional map argument
+ if (Cmd_Argc() >= 2)
+ {
+ char mapname[MAX_QPATH];
+ size_t i;
+
+ COM_StripExtension (Cmd_Argv (1), mapname, sizeof (mapname));
+
+ for (i = 0; i < VEC_SIZE (mapsmenu.items); i++)
+ if (q_strcasecmp (mapname, mapsmenu.items[i].name) == 0)
+ break;
+
+ if (i == VEC_SIZE (mapsmenu.items))
+ {
+ Con_SafePrintf ("Couldn't find map \"%s\".\n", mapname);
+ return;
+ }
+
+ mapsmenu.list.cursor = i;
+ M_SetSkillMenuMap (mapname);
+ M_Menu_Skill_f ();
+ }
}
void M_Maps_Draw (void)
@@ -1731,16 +1818,10 @@ void M_Maps_Draw (void)
if (mapsmenu.prev_cursor != mapsmenu.list.cursor)
{
mapsmenu.prev_cursor = mapsmenu.list.cursor;
- mapsmenu.scroll_time = 0.0;
- mapsmenu.scroll_wait_time = DESCRIPTION_SCROLL_WAIT_TIME;
+ M_Ticker_Init (&mapsmenu.ticker);
}
else
- {
- if (mapsmenu.scroll_wait_time <= 0.0)
- mapsmenu.scroll_time += host_rawframetime;
- else
- mapsmenu.scroll_wait_time = q_max (0.0, mapsmenu.scroll_wait_time - host_rawframetime);
- }
+ M_Ticker_Update (&mapsmenu.ticker);
x = mapsmenu.x;
y = mapsmenu.y;
@@ -1801,7 +1882,7 @@ void M_Maps_Draw (void)
GL_SetCanvasColor (1, 1, 1, 1);
M_PrintScroll (x + namecols*8, y + i*8, desccols*8, buf,
- selected ? mapsmenu.scroll_time : 0.0, true);
+ selected ? mapsmenu.ticker.scroll_time : 0.0, true);
if (!message)
GL_SetCanvasColor (1, 1, 1, 1);
@@ -1833,9 +1914,9 @@ void M_Maps_Char (int key)
M_List_Char (&mapsmenu.list, key);
}
-qboolean M_Maps_TextEntry (void)
+textmode_t M_Maps_TextEntry (void)
{
- return !mapsmenu.scrollbar_grab;
+ return mapsmenu.scrollbar_grab ? TEXTMODE_OFF : TEXTMODE_NOPOPUP;
}
void M_Maps_Key (int key)
@@ -1859,6 +1940,12 @@ void M_Maps_Key (int key)
if (M_List_Key (&mapsmenu.list, key))
return;
+ if (M_Ticker_Key (&mapsmenu.ticker, key))
+ {
+ M_List_KeepSearchVisible (&mapsmenu.list, 1.0);
+ return;
+ }
+
switch (key)
{
case K_ESCAPE:
@@ -1869,19 +1956,6 @@ void M_Maps_Key (int key)
M_Menu_SinglePlayer_f ();
break;
- case K_RIGHTARROW:
- mapsmenu.scroll_time += 0.25;
- mapsmenu.scroll_wait_time = 1.5;
- M_List_KeepSearchVisible (&mapsmenu.list, 1.0);
- M_ThrottledSound ("misc/menu3.wav");
- break;
- case K_LEFTARROW:
- mapsmenu.scroll_time -= 0.25;
- mapsmenu.scroll_wait_time = 1.5;
- M_List_KeepSearchVisible (&mapsmenu.list, 1.0);
- M_ThrottledSound ("misc/menu3.wav");
- break;
-
case K_ENTER:
case K_KP_ENTER:
case K_ABUTTON:
@@ -1932,41 +2006,85 @@ void M_Maps_Mousemove (int cx, int cy)
//=============================================================================
/* SKILL MENU */
-int m_skill_cursor;
-qboolean m_skill_usegfx;
-qboolean m_skill_usecustomtitle;
-char m_skill_mapname[MAX_QPATH];
+int m_skill_cursor;
+qboolean m_skill_usegfx;
+qboolean m_skill_usecustomtitle;
+qboolean m_skill_canresume;
+time_t m_skill_lastplayed;
+int m_skill_numoptions;
+char m_skill_mapname[MAX_QPATH];
+char m_skill_maptitle[1024];
+menuticker_t m_skill_ticker;
+
enum m_state_e m_skill_prevmenu;
void M_SetSkillMenuMap (const char *name)
{
q_strlcpy (m_skill_mapname, name, sizeof (m_skill_mapname));
+ if (!Mod_LoadMapDescription (m_skill_maptitle, sizeof (m_skill_maptitle), name) || !m_skill_maptitle[0])
+ q_strlcpy (m_skill_maptitle, name, sizeof (m_skill_maptitle));
}
void M_Menu_Skill_f (void)
{
+ char autosave[MAX_OSPATH];
+
+ m_skill_canresume = false;
+ m_skill_lastplayed = 0;
+ q_snprintf (autosave, sizeof (autosave), "%s/autosave/%s.sav", com_gamedir, m_skill_mapname);
+ if (Sys_FileExists (autosave))
+ {
+ time_t now, lastplayed;
+ m_skill_canresume = true;
+ time (&now);
+ if (Sys_GetFileTime (autosave, &lastplayed) && lastplayed <= now)
+ m_skill_lastplayed = lastplayed;
+ }
+
IN_DeactivateForMenu();
key_dest = key_menu;
m_skill_prevmenu = m_state;
m_state = m_skill;
m_entersound = true;
- m_skill_cursor = (int)skill.value;
- m_skill_cursor = CLAMP (0, m_skill_cursor, 3);
+ M_Ticker_Init (&m_skill_ticker);
+
+ if (m_skill_canresume)
+ {
+ // Select "Resume" option initially if available
+ m_skill_cursor = 4;
+ }
+ else
+ {
+ // Select current skill level initially if there's no autosave
+ m_skill_cursor = (int)skill.value;
+ m_skill_cursor = CLAMP (0, m_skill_cursor, 3);
+ }
+ m_skill_numoptions = 4 + m_skill_canresume;
}
void M_Skill_Draw (void)
{
- int f;
+ int x, y, f;
qpic_t *p;
M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
- p = Draw_CachePic (m_skill_usecustomtitle ? "gfx/p_skill.lmp" : "gfx/ttl_sgl.lmp");
+ p = Draw_CachePic (m_skill_usecustomtitle && !m_skill_canresume ? "gfx/p_skill.lmp" : "gfx/ttl_sgl.lmp");
M_DrawPic ( (320-p->width)/2, 4, p);
+ x = 72;
+ y = 32;
+
+ M_Ticker_Update (&m_skill_ticker);
+ M_PrintScroll (x, 32, 30*8, m_skill_maptitle, m_skill_ticker.scroll_time, false);
+
+ y += 16;
+
if (m_skill_usegfx)
{
- M_DrawTransPic (72, 32, Draw_CachePic ("gfx/skillmenu.lmp") );
- M_DrawQuakeCursor (54, 32 + m_skill_cursor * 20);
+ M_DrawTransPic (x, y, Draw_CachePic ("gfx/skillmenu.lmp") );
+ if (m_skill_cursor < 4)
+ M_DrawQuakeCursor (x - 18, y + m_skill_cursor * 20);
+ y += 4 * 20;
}
else
{
@@ -1979,13 +2097,35 @@ void M_Skill_Draw (void)
};
for (f = 0; f < 4; f++)
- M_Print (88, 44+4 + f*16, skills[f]);
- M_DrawArrowCursor (72, 44+4 + m_skill_cursor*16);
+ M_PrintEx (x, y + f*16 + 2, 12, skills[f]);
+ if (m_skill_cursor < 4)
+ M_DrawArrowCursor (x - 16, y + m_skill_cursor*16 + 4);
+ y += 4 * 16;
+ }
+
+ if (m_skill_canresume)
+ {
+ y += 8;
+ M_Print (x, y, "Resume last game");
+ if (m_skill_lastplayed)
+ {
+ char duration[32];
+ time_t now;
+
+ time (&now);
+ COM_DescribeDuration (duration, sizeof (duration), difftime (m_skill_lastplayed, now));
+ M_Print (x, y + 8, va ("from %s ago", duration));
+ }
+ if (m_skill_cursor == 4)
+ M_DrawArrowCursor (x - 16, y);
}
}
void M_Skill_Key (int key)
{
+ if (M_Ticker_Key (&m_skill_ticker, key))
+ return;
+
switch (key)
{
case K_ESCAPE:
@@ -1998,14 +2138,14 @@ void M_Skill_Key (int key)
case K_DOWNARROW:
M_ThrottledSound ("misc/menu1.wav");
- if (++m_skill_cursor > 3)
+ if (++m_skill_cursor > m_skill_numoptions - 1)
m_skill_cursor = 0;
break;
case K_UPARROW:
M_ThrottledSound ("misc/menu1.wav");
if (--m_skill_cursor < 0)
- m_skill_cursor = 3;
+ m_skill_cursor = m_skill_numoptions - 1;
break;
case K_ENTER:
@@ -2016,22 +2156,35 @@ void M_Skill_Key (int key)
key_dest = key_game;
if (sv.active)
Cbuf_AddText ("disconnect\n");
- Cbuf_AddText (va ("skill %d\n", m_skill_cursor));
- Cbuf_AddText ("maxplayers 1\n");
- Cbuf_AddText ("deathmatch 0\n"); //johnfitz
- Cbuf_AddText ("coop 0\n"); //johnfitz
- Cbuf_AddText (va ("map \"%s\"\n", m_skill_mapname));
+ if (m_skill_cursor == 4)
+ {
+ // Resume autosave
+ Cbuf_AddText (va ("load \"autosave/%s\"\n", m_skill_mapname));
+ }
+ else
+ {
+ // Fresh start
+ Cbuf_AddText (va ("skill %d\n", m_skill_cursor));
+ Cbuf_AddText ("maxplayers 1\n");
+ Cbuf_AddText ("deathmatch 0\n"); //johnfitz
+ Cbuf_AddText ("coop 0\n"); //johnfitz
+ Cbuf_AddText (va ("map \"%s\"\n", m_skill_mapname));
+ }
break;
}
}
void M_Skill_Mousemove (int cx, int cy)
{
+ int ybase = 48;
+ int itemheight = m_skill_usegfx ? 20 : 16;
int prev = m_skill_cursor;
- if (m_skill_usegfx)
- M_UpdateCursor (cy, 32, 20, 4, &m_skill_cursor);
+
+ if (m_skill_numoptions > 4 && cy > ybase + 4 * itemheight + 8/2)
+ m_skill_cursor = 4;
else
- M_UpdateCursor (cy, 44, 16, 4, &m_skill_cursor);
+ M_UpdateCursor (cy, ybase, itemheight, 4, &m_skill_cursor);
+
if (m_skill_cursor != prev)
M_MouseSound ("misc/menu1.wav");
}
@@ -2311,9 +2464,9 @@ void M_Setup_Char (int k)
}
-qboolean M_Setup_TextEntry (void)
+textmode_t M_Setup_TextEntry (void)
{
- return (setup_cursor == 0 || setup_cursor == 1);
+ return (setup_cursor == 0 || setup_cursor == 1) ? TEXTMODE_ON : TEXTMODE_OFF;
}
@@ -2979,6 +3132,112 @@ void M_Menu_Video_f (void)
M_Options_Init (m_video);
}
+//=============================================================================
+/* CALIBRATION SCREEN */
+
+static enum
+{
+ CALIBRATION_INTRO_TEXT,
+ CALIBRATION_IN_ROGRESS,
+ CALIBRATION_FINISHED,
+} calibration_state;
+
+static double calibration_finished_delay;
+
+void M_Menu_Calibration_f (void)
+{
+ IN_DeactivateForMenu();
+ m_state = m_calibration;
+ calibration_state = CALIBRATION_INTRO_TEXT;
+ calibration_finished_delay = 1.0;
+}
+
+void M_Calibration_Draw (void)
+{
+ int y = 72;
+
+ switch (calibration_state)
+ {
+ case CALIBRATION_INTRO_TEXT:
+ M_PrintAligned (160, y - 8, ALIGN_CENTER, "Before calibration,");
+ M_PrintAligned (160, y, ALIGN_CENTER, "place the controller");
+ M_PrintAligned (160, y + 8, ALIGN_CENTER, "on a flat, stable surface");
+ y += 24;
+ M_DrawTextBox (160 - 5*8, y, 8, 1);
+ M_DrawArrowCursor (160 - 6*8, y + 8);
+ M_PrintAligned (160, y + 8, ALIGN_CENTER, "Continue");
+ break;
+
+ case CALIBRATION_IN_ROGRESS:
+ M_PrintAligned (160, y, ALIGN_CENTER, "Calibrating, please wait...");
+ if (!IN_IsCalibratingGyro ())
+ calibration_state = CALIBRATION_FINISHED;
+ break;
+
+ case CALIBRATION_FINISHED:
+ M_PrintAligned (160, y, ALIGN_CENTER, "Calibration complete!");
+ calibration_finished_delay -= host_rawframetime;
+ if (calibration_finished_delay < 0.0)
+ M_Menu_Gamepad_f ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void M_Calibration_Key (int key)
+{
+ if (calibration_state != CALIBRATION_INTRO_TEXT)
+ return;
+
+ switch (key)
+ {
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_ABUTTON:
+ case K_MOUSE1:
+ calibration_state = CALIBRATION_IN_ROGRESS;
+ M_ThrottledSound ("misc/menu2.wav");
+ IN_StartGyroCalibration ();
+ break;
+
+ case K_ESCAPE:
+ case K_BBUTTON:
+ case K_MOUSE4:
+ case K_MOUSE2:
+ M_Menu_Gamepad_f ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+//=============================================================================
+/* GAMEPAD MENU */
+
+#define MIN_JOY_SENS 60.f
+#define MAX_JOY_SENS 720.f
+#define MIN_JOY_EXPONENT 1.f
+#define MAX_JOY_EXPONENT 5.f
+#define MIN_STICK_DEADZONE 0.f
+#define MAX_STICK_DEADZONE 0.75f
+#define MIN_TRIGGER_DEADZONE 0.f
+#define MAX_TRIGGER_DEADZONE 0.75f
+#define MIN_GYRO_SENS 0.1f
+#define MAX_GYRO_SENS 8.f
+
+/*
+================
+M_Menu_Gamepad_f
+================
+*/
+void M_Menu_Gamepad_f (void)
+{
+ M_Options_Init (m_gamepad);
+}
+
//=============================================================================
/* OPTIONS MENU */
@@ -2986,6 +3245,7 @@ void M_Menu_Video_f (void)
#define OPTIONS_LIST(def) \
def (OPT_VIDEO, "Video Options") \
def (OPT_CUSTOMIZE, "Controls") \
+ def (OPT_GAMEPAD, "Gamepad") \
def (OPT_MODS, "Mods") \
def (OPT_CONSOLE, "Go To Console") \
def (OPT_DEFAULTS, "Reset Config") \
@@ -3044,12 +3304,42 @@ void M_Menu_Video_f (void)
def (VID_OPT_FPSLIMIT, "FPS Limit") \
def (VID_OPT_SHOWFPS, "Show FPS") \
////////////////////////////////////////////////////
+#define GPAD_OPTIONS_LIST(def) \
+ def(GPAD_OPT_ENABLE, "Gamepad") \
+ \
+ def(GPAD_OPT_SPACE1, "") \
+ \
+ def(GPAD_OPT_SENSX, "Yaw Speed") \
+ def(GPAD_OPT_SENSY, "Pitch Speed") \
+ def(GPAD_OPT_INVERT, "Invert Pitch") \
+ def(GPAD_OPT_SWAP_MOVELOOK, "Look Stick") \
+ \
+ def(GPAD_OPT_SPACE2, "") \
+ \
+ def(GPAD_OPT_EXPONENT_LOOK, "Look Accel") \
+ def(GPAD_OPT_EXPONENT_MOVE, "Move Accel") \
+ \
+ def(GPAD_OPT_SPACE3, "") \
+ \
+ def(GPAD_OPT_DEADZONE_LOOK, "Look Deadzone") \
+ def(GPAD_OPT_DEADZONE_MOVE, "Move Deadzone") \
+ def(GPAD_OPT_DEADZONE_TRIG, "Trigger Thresh") \
+ \
+ def(GPAD_OPT_SPACE4, "") \
+ \
+ def(GPAD_OPT_GYROMODE, "Gyro Mode") \
+ def(GPAD_OPT_GYROAXIS, "Gyro Axis") \
+ def(GPAD_OPT_GYROSENSX, "Gyro Yaw Speed") \
+ def(GPAD_OPT_GYROSENSY, "Gyro Pitch Speed") \
+ def(GPAD_OPT_CALIBRATE, "Calibrate") \
+////////////////////////////////////////////////////
enum
{
#define ADD_OPTION_ENUM(id, name) id,
OPTIONS_LIST (ADD_OPTION_ENUM)
VIDEO_OPTIONS_LIST(ADD_OPTION_ENUM)
+ GPAD_OPTIONS_LIST(ADD_OPTION_ENUM)
#undef ADD_OPTION_ENUM
#define COUNT_OPTION(id, name) +1
@@ -3057,6 +3347,8 @@ enum
OPTIONS_ITEMS = OPTIONS_LIST (COUNT_OPTION),
VIDEO_OPTIONS_FIRST = OPTIONS_ITEMS,
VIDEO_OPTIONS_ITEMS = VIDEO_OPTIONS_LIST (COUNT_OPTION),
+ GPAD_OPTIONS_FIRST = OPTIONS_ITEMS + VIDEO_OPTIONS_ITEMS,
+ GPAD_OPTIONS_ITEMS = GPAD_OPTIONS_LIST (COUNT_OPTION),
#undef COUNT_OPTION
};
@@ -3065,6 +3357,7 @@ static const char *const options_names[] =
#define ADD_OPTION_NAME(id, name) name,
OPTIONS_LIST (ADD_OPTION_NAME)
VIDEO_OPTIONS_LIST(ADD_OPTION_NAME)
+ GPAD_OPTIONS_LIST(ADD_OPTION_NAME)
#undef ADD_OPTION_NAME
};
@@ -3093,6 +3386,7 @@ struct
int first_item;
int options_cursor;
int video_cursor;
+ int gamepad_cursor;
int *last_cursor;
} optionsmenu;
@@ -3119,6 +3413,9 @@ static void M_Options_UpdateLayout (void)
optionsmenu.yofs = 0;
height = OPTIONS_LISTOFS + optionsmenu.yofs + optionsmenu.list.numitems * 8;
+ // Enforce a minimum height, so that if the number of items is relatively small
+ // the title pic doesn't get drawn below its usual position
+ height = q_max (height, 192);
if (height <= m_height)
{
optionsmenu.y = (m_top + (m_height - height) / 2) & ~7;
@@ -3191,6 +3488,13 @@ void M_Options_Init (enum m_state_e state)
// set up the display mode selector.
VID_Menu_InitDisplayMode ();
}
+ else if (state == m_gamepad)
+ {
+ optionsmenu.first_item = GPAD_OPTIONS_FIRST;
+ optionsmenu.list.numitems = GPAD_OPTIONS_ITEMS;
+ optionsmenu.last_cursor = &optionsmenu.gamepad_cursor;
+ optionsmenu.subtitle = "Gamepad Options";
+ }
else
{
Sys_Error ("M_Options_Init: invalid state %d", state);
@@ -3322,7 +3626,7 @@ void M_AdjustSliders (int dir)
break;
case OPT_HUDSTYLE: // hud style
- Cvar_SetValueQuick (&scr_hudstyle, ((int) q_max (scr_hudstyle.value, 0.f) + 3 + dir) % 3);
+ Cvar_SetValueQuick (&scr_hudstyle, ((int) q_max (scr_hudstyle.value, 0.f) + 4 + dir) % 4);
break;
case OPT_ALWAYRUN: // always run
@@ -3457,6 +3761,55 @@ void M_AdjustSliders (int dir)
Cbuf_AddText ("toggle scr_showfps\n");
break;
+ //
+ // Gamepad Options
+ //
+ case GPAD_OPT_ENABLE:
+ Cvar_SetValueQuick (&joy_enable, !joy_enable.value);
+ break;
+ case GPAD_OPT_SENSX:
+ Cvar_SetValueQuick (&joy_sensitivity_yaw, CLAMP (MIN_JOY_SENS, joy_sensitivity_yaw.value + dir * 10.f, MAX_JOY_SENS));
+ break;
+ case GPAD_OPT_SENSY:
+ Cvar_SetValueQuick (&joy_sensitivity_pitch, CLAMP (MIN_JOY_SENS, joy_sensitivity_pitch.value + dir * 10.f, MAX_JOY_SENS));
+ break;
+ case GPAD_OPT_INVERT:
+ Cvar_SetValueQuick (&joy_invert, !joy_invert.value);
+ break;
+ case GPAD_OPT_SWAP_MOVELOOK:
+ Cvar_SetValueQuick (&joy_swapmovelook, !joy_swapmovelook.value);
+ break;
+ case GPAD_OPT_EXPONENT_LOOK:
+ Cvar_SetValueQuick (&joy_exponent, CLAMP (MIN_JOY_EXPONENT, joy_exponent.value + dir * 0.5f, MAX_JOY_EXPONENT));
+ break;
+ case GPAD_OPT_EXPONENT_MOVE:
+ Cvar_SetValueQuick (&joy_exponent_move, CLAMP (MIN_JOY_EXPONENT, joy_exponent_move.value + dir * 0.5f, MAX_JOY_EXPONENT));
+ break;
+ case GPAD_OPT_DEADZONE_LOOK:
+ Cvar_SetValueQuick (&joy_deadzone_look, CLAMP (MIN_STICK_DEADZONE, joy_deadzone_look.value + dir * 0.05f, MAX_STICK_DEADZONE));
+ break;
+ case GPAD_OPT_DEADZONE_MOVE:
+ Cvar_SetValueQuick (&joy_deadzone_move, CLAMP (MIN_STICK_DEADZONE, joy_deadzone_move.value + dir * 0.05f, MAX_STICK_DEADZONE));
+ break;
+ case GPAD_OPT_DEADZONE_TRIG:
+ Cvar_SetValueQuick (&joy_deadzone_trigger, CLAMP (MIN_TRIGGER_DEADZONE, joy_deadzone_trigger.value + dir * 0.05f, MAX_TRIGGER_DEADZONE));
+ break;
+ case GPAD_OPT_GYROMODE:
+ Cvar_SetValueQuick (&gyro_mode, (int)(q_max (gyro_mode.value, 0.f) + 5 + dir) % 5);
+ break;
+ case GPAD_OPT_GYROAXIS:
+ Cvar_SetValueQuick (&gyro_turning_axis, !gyro_turning_axis.value);
+ break;
+ case GPAD_OPT_GYROSENSX:
+ Cvar_SetValueQuick (&gyro_yawsensitivity, CLAMP (MIN_GYRO_SENS, gyro_yawsensitivity.value + dir * .1f, MAX_GYRO_SENS));
+ break;
+ case GPAD_OPT_GYROSENSY:
+ Cvar_SetValueQuick (&gyro_pitchsensitivity, CLAMP (MIN_GYRO_SENS, gyro_pitchsensitivity.value + dir * .1f, MAX_GYRO_SENS));
+ break;
+ case GPAD_OPT_CALIBRATE:
+ M_Menu_Calibration_f ();
+ break;
+
default:
break;
}
@@ -3544,6 +3897,42 @@ qboolean M_SetSliderValue (int option, float f)
case OPT_FOVDISTORT: // FOV distortion
Cvar_SetValue ("cl_gun_fovscale", 1.f - f);
return true;
+ case GPAD_OPT_SENSX:
+ f = LERP (MIN_JOY_SENS, MAX_JOY_SENS, f);
+ Cvar_SetValueQuick (&joy_sensitivity_yaw, f);
+ return true;
+ case GPAD_OPT_SENSY:
+ f = LERP (MIN_JOY_SENS, MAX_JOY_SENS, f);
+ Cvar_SetValueQuick (&joy_sensitivity_pitch, f);
+ return true;
+ case GPAD_OPT_EXPONENT_LOOK:
+ f = LERP (MIN_JOY_EXPONENT, MAX_JOY_EXPONENT, f);
+ Cvar_SetValueQuick (&joy_exponent, f);
+ return true;
+ case GPAD_OPT_EXPONENT_MOVE:
+ f = LERP (MIN_JOY_EXPONENT, MAX_JOY_EXPONENT, f);
+ Cvar_SetValueQuick (&joy_exponent_move, f);
+ return true;
+ case GPAD_OPT_DEADZONE_LOOK:
+ f = LERP (MIN_STICK_DEADZONE, MAX_STICK_DEADZONE, f);
+ Cvar_SetValueQuick (&joy_deadzone_look, f);
+ return true;
+ case GPAD_OPT_DEADZONE_MOVE:
+ f = LERP (MIN_STICK_DEADZONE, MAX_STICK_DEADZONE, f);
+ Cvar_SetValueQuick (&joy_deadzone_move, f);
+ return true;
+ case GPAD_OPT_DEADZONE_TRIG:
+ f = LERP (MIN_TRIGGER_DEADZONE, MAX_TRIGGER_DEADZONE, f);
+ Cvar_SetValueQuick (&joy_deadzone_trigger, f);
+ return true;
+ case GPAD_OPT_GYROSENSX:
+ f = LERP (MIN_GYRO_SENS, MAX_GYRO_SENS, f);
+ Cvar_SetValueQuick (&gyro_yawsensitivity, f);
+ return true;
+ case GPAD_OPT_GYROSENSY:
+ f = LERP (MIN_GYRO_SENS, MAX_GYRO_SENS, f);
+ Cvar_SetValueQuick (&gyro_pitchsensitivity, f);
+ return true;
default:
return false;
}
@@ -3604,7 +3993,9 @@ static void M_Options_DrawItem (int y, int item)
{
case OPT_VIDEO:
case OPT_CUSTOMIZE:
+ case OPT_GAMEPAD:
case OPT_MODS:
+ case GPAD_OPT_CALIBRATE:
M_Print (x - 4, y, "...");
break;
@@ -3669,8 +4060,10 @@ static void M_Options_DrawItem (int y, int item)
M_Print (x, y, "Classic");
else if (scr_hudstyle.value < 2)
M_Print (x, y, "Modern 1");
- else
+ else if (scr_hudstyle.value < 3)
M_Print (x, y, "Modern 2");
+ else
+ M_Print(x, y, "QuakeWorld");
break;
case OPT_SNDVOL:
@@ -3803,6 +4196,68 @@ static void M_Options_DrawItem (int y, int item)
M_Print (x, y, scr_showfps.value ? "On" : "Off");
break;
+ //
+ // Gamepad Options
+ //
+ case GPAD_OPT_ENABLE:
+ M_DrawCheckbox (x, y, joy_enable.value);
+ break;
+ case GPAD_OPT_SENSX:
+ r = (joy_sensitivity_yaw.value - MIN_JOY_SENS) / (MAX_JOY_SENS - MIN_JOY_SENS);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_SENSY:
+ r = (joy_sensitivity_pitch.value - MIN_JOY_SENS) / (MAX_JOY_SENS - MIN_JOY_SENS);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_INVERT:
+ M_DrawCheckbox (x, y, joy_invert.value);
+ break;
+ case GPAD_OPT_SWAP_MOVELOOK:
+ M_Print (x, y, joy_swapmovelook.value ? "Left" : "Right");
+ break;
+ case GPAD_OPT_EXPONENT_LOOK:
+ r = (joy_exponent.value - MIN_JOY_EXPONENT) / (MAX_JOY_EXPONENT - MIN_JOY_EXPONENT);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_EXPONENT_MOVE:
+ r = (joy_exponent_move.value - MIN_JOY_EXPONENT) / (MAX_JOY_EXPONENT - MIN_JOY_EXPONENT);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_DEADZONE_LOOK:
+ r = (joy_deadzone_look.value - MIN_STICK_DEADZONE) / (MAX_STICK_DEADZONE - MIN_STICK_DEADZONE);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_DEADZONE_MOVE:
+ r = (joy_deadzone_move.value - MIN_STICK_DEADZONE) / (MAX_STICK_DEADZONE - MIN_STICK_DEADZONE);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_DEADZONE_TRIG:
+ r = (joy_deadzone_trigger.value - MIN_TRIGGER_DEADZONE) / (MAX_TRIGGER_DEADZONE - MIN_TRIGGER_DEADZONE);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_GYROMODE:
+ switch ((int)gyro_mode.value)
+ {
+ case 1: M_Print (x, y, "off, button enables"); break;
+ case 2: M_Print (x, y, "on, button disables"); break;
+ case 3: M_Print (x, y, "always on"); break;
+ case 4: M_Print (x, y, "on, button inverts direction"); break;
+ default: M_Print (x, y, "off"); break;
+ }
+ break;
+ case GPAD_OPT_GYROAXIS:
+ M_Print(x, y, gyro_turning_axis.value ? "roll (lean)" : "yaw (turn)");
+ break;
+ case GPAD_OPT_GYROSENSX:
+ r = (gyro_yawsensitivity.value - MIN_GYRO_SENS) / (MAX_GYRO_SENS - MIN_GYRO_SENS);
+ M_DrawSlider (x, y, r);
+ break;
+ case GPAD_OPT_GYROSENSY:
+ r = (gyro_pitchsensitivity.value - MIN_GYRO_SENS) / (MAX_GYRO_SENS - MIN_GYRO_SENS);
+ M_DrawSlider (x, y, r);
+ break;
+
default:
break;
}
@@ -3921,6 +4376,9 @@ void M_Options_Key (int k)
case OPT_VIDEO:
M_Menu_Video_f ();
break;
+ case OPT_GAMEPAD:
+ M_Menu_Gamepad_f ();
+ break;
case VID_OPT_TEST:
Cbuf_AddText ("vid_test\n");
@@ -3958,9 +4416,9 @@ void M_Options_Key (int k)
}
}
-qboolean M_Options_TextEntry (void)
+textmode_t M_Options_TextEntry (void)
{
- return !slider_grab;
+ return slider_grab ? TEXTMODE_OFF : TEXTMODE_NOPOPUP;
}
void M_Options_Char (int key)
@@ -4010,6 +4468,7 @@ static const char* const bindnames[][2] =
{"centerview", "Center view"},
{"zoom_in", "Toggle zoom"},
{"+zoom", "Quick zoom"},
+ {"+gyroaction", "Gyro Off / On"},
{"", ""},
{"+attack", "Attack"},
{"impulse 10", "Next weapon"},
@@ -4026,7 +4485,7 @@ static const char* const bindnames[][2] =
{"impulse 226", "Mjolnir"},
};
-#define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0]))
+#define NUMCOMMANDS Q_COUNTOF(bindnames)
#define KEYLIST_OFS 48
static struct
@@ -4259,9 +4718,9 @@ void M_Keys_Mousemove (int cx, int cy)
M_List_Mousemove (&keysmenu.list, cy - keysmenu.y - KEYLIST_OFS);
}
-qboolean M_Keys_TextEntry (void)
+textmode_t M_Keys_TextEntry (void)
{
- return !bind_grab;
+ return bind_grab ? TEXTMODE_OFF : TEXTMODE_NOPOPUP;
}
void M_Keys_Char (int key)
@@ -4397,10 +4856,12 @@ void M_Menu_Quit_f (void)
void M_Quit_Key (int key)
{
- if (key == K_ESCAPE ||
- key == K_MOUSE2 ||
- key == K_MOUSE4)
+ switch (key)
{
+ case K_ESCAPE:
+ case K_BBUTTON:
+ case K_MOUSE4:
+ case K_MOUSE2:
if (wasInMenus)
{
m_state = m_quit_prevstate;
@@ -4412,6 +4873,16 @@ void M_Quit_Key (int key)
key_dest = key_game;
m_state = m_none;
}
+ break;
+
+ case K_ABUTTON:
+ IN_DeactivateForConsole();
+ key_dest = key_console;
+ Host_Quit_f ();
+ break;
+
+ default:
+ break;
}
}
@@ -4449,9 +4920,9 @@ void M_Quit_Char (int key)
}
-qboolean M_Quit_TextEntry (void)
+textmode_t M_Quit_TextEntry (void)
{
- return true;
+ return TEXTMODE_NOPOPUP;
}
@@ -4701,9 +5172,9 @@ void M_LanConfig_Char (int key)
}
-qboolean M_LanConfig_TextEntry (void)
+textmode_t M_LanConfig_TextEntry (void)
{
- return (lanConfig_cursor == 0 || lanConfig_cursor == 2);
+ return (lanConfig_cursor == 0 || lanConfig_cursor == 2) ? TEXTMODE_ON : TEXTMODE_OFF;
}
@@ -5364,11 +5835,10 @@ typedef struct
static struct
{
menulist_t list;
+ menuticker_t ticker;
int x, y, cols;
int modcount;
int prev_cursor;
- double scroll_time;
- double scroll_wait_time;
double download_flash_time;
enum m_state_e prev;
qboolean scrollbar_grab;
@@ -5500,6 +5970,8 @@ static void M_Mods_Init (void)
modsmenu.modcount = 0;
VEC_CLEAR (modsmenu.items);
+ M_Ticker_Init (&modsmenu.ticker);
+
for (pass = 0; pass < 2; pass++)
{
count = 0;
@@ -5559,16 +6031,10 @@ void M_Mods_Draw (void)
if (modsmenu.prev_cursor != modsmenu.list.cursor)
{
modsmenu.prev_cursor = modsmenu.list.cursor;
- modsmenu.scroll_time = 0.0;
- modsmenu.scroll_wait_time = 1.0;
+ M_Ticker_Init (&modsmenu.ticker);
}
else
- {
- if (modsmenu.scroll_wait_time <= 0.0)
- modsmenu.scroll_time += host_rawframetime;
- else
- modsmenu.scroll_wait_time = q_max (0.0, modsmenu.scroll_wait_time - host_rawframetime);
- }
+ M_Ticker_Update (&modsmenu.ticker);
modsmenu.download_flash_time = q_max (0.0, modsmenu.download_flash_time - host_rawframetime);
flash = (int)(modsmenu.download_flash_time * 8.0) & 1;
@@ -5636,7 +6102,7 @@ void M_Mods_Draw (void)
GL_SetCanvasColor (1, 1, 1, 1);
M_PrintScroll (x + namecols*8, y + i*8, desccols*8, buf,
- selected ? modsmenu.scroll_time : 0.0, true);
+ selected ? modsmenu.ticker.scroll_time : 0.0, true);
if (!message)
GL_SetCanvasColor (1, 1, 1, 1);
@@ -5669,9 +6135,9 @@ void M_Mods_Char (int key)
M_List_Char (&modsmenu.list, key);
}
-qboolean M_Mods_TextEntry (void)
+textmode_t M_Mods_TextEntry (void)
{
- return !modsmenu.scrollbar_grab;
+ return modsmenu.scrollbar_grab ? TEXTMODE_OFF : TEXTMODE_NOPOPUP;
}
void M_Mods_Key (int key)
@@ -5696,6 +6162,12 @@ void M_Mods_Key (int key)
if (M_List_Key (&modsmenu.list, key))
return;
+ if (M_Ticker_Key (&modsmenu.ticker, key))
+ {
+ M_List_KeepSearchVisible (&modsmenu.list, 1.0);
+ return;
+ }
+
switch (key)
{
case K_ESCAPE:
@@ -5733,19 +6205,6 @@ void M_Mods_Key (int key)
M_Mods_Mousemove (m_mousex, m_mousey);
break;
- case K_RIGHTARROW:
- modsmenu.scroll_time += 0.25;
- modsmenu.scroll_wait_time = 1.5;
- M_List_KeepSearchVisible (&modsmenu.list, 1.0);
- M_ThrottledSound ("misc/menu3.wav");
- break;
- case K_LEFTARROW:
- modsmenu.scroll_time -= 0.25;
- modsmenu.scroll_wait_time = 1.5;
- M_List_KeepSearchVisible (&modsmenu.list, 1.0);
- M_ThrottledSound ("misc/menu3.wav");
- break;
-
default:
break;
}
@@ -6028,6 +6487,7 @@ void M_Init (void)
Cmd_AddCommand ("menu_options", M_Menu_Options_f);
Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
Cmd_AddCommand ("menu_video", M_Menu_Video_f);
+ Cmd_AddCommand ("menu_gamepad", M_Menu_Gamepad_f);
Cmd_AddCommand ("help", M_Menu_Help_f);
Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
Cmd_AddCommand ("menu_credits", M_Menu_Credits_f); // needed by the 2021 re-release
@@ -6130,8 +6590,13 @@ void M_Draw (void)
M_Net_Draw ();
break;
+ case m_calibration:
+ M_Calibration_Draw ();
+ break;
+
case m_options:
case m_video:
+ case m_gamepad:
M_Options_Draw ();
break;
@@ -6234,8 +6699,13 @@ void M_Keydown (int key)
M_Net_Key (key);
return;
+ case m_calibration:
+ M_Calibration_Key (key);
+ break;
+
case m_options:
case m_video:
+ case m_gamepad:
M_Options_Key (key);
return;
@@ -6344,6 +6814,7 @@ void M_Mousemove (int x, int y)
case m_options:
case m_video:
+ case m_gamepad:
M_Options_Mousemove (x, y);
return;
@@ -6403,6 +6874,7 @@ void M_Charinput (int key)
return;
case m_options:
case m_video:
+ case m_gamepad:
M_Options_Char (key);
return;
case m_keys:
@@ -6414,7 +6886,7 @@ void M_Charinput (int key)
}
-qboolean M_TextEntry (void)
+textmode_t M_TextEntry (void)
{
switch (m_state)
{
@@ -6430,11 +6902,12 @@ qboolean M_TextEntry (void)
return M_Mods_TextEntry ();
case m_options:
case m_video:
+ case m_gamepad:
return M_Options_TextEntry ();
case m_keys:
return M_Keys_TextEntry ();
default:
- return false;
+ return TEXTMODE_OFF;
}
}
diff --git a/Quake/menu.h b/Quake/menu.h
index b7004e2a7..795a3f912 100644
--- a/Quake/menu.h
+++ b/Quake/menu.h
@@ -37,6 +37,8 @@ enum m_state_e {
m_options,
m_video,
m_keys,
+ m_calibration,
+ m_gamepad,
m_mods,
m_modinfo,
m_help,
@@ -59,7 +61,7 @@ void M_Init (void);
void M_Keydown (int key);
void M_Charinput (int key);
void M_Mousemove (int x, int y);
-qboolean M_TextEntry (void);
+enum textmode_t M_TextEntry (void);
qboolean M_KeyBinding (void);
void M_ToggleMenu_f (void);
diff --git a/Quake/net_bsd.c b/Quake/net_bsd.c
index 59487e7e6..52d99a322 100644
--- a/Quake/net_bsd.c
+++ b/Quake/net_bsd.c
@@ -63,7 +63,7 @@ net_driver_t net_drivers[] =
}
};
-const int net_numdrivers = (sizeof(net_drivers) / sizeof(net_drivers[0]));
+const int net_numdrivers = Q_COUNTOF(net_drivers);
#include "net_udp.h"
@@ -93,5 +93,4 @@ net_landriver_t net_landrivers[] =
}
};
-const int net_numlandrivers = (sizeof(net_landrivers) / sizeof(net_landrivers[0]));
-
+const int net_numlandrivers = Q_COUNTOF(net_landrivers);
diff --git a/Quake/net_main.c b/Quake/net_main.c
index 4c7184b14..4a090399b 100644
--- a/Quake/net_main.c
+++ b/Quake/net_main.c
@@ -25,7 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "net_sys.h"
#include "net_defs.h"
+#ifndef WITHOUT_CURL
#include
+#endif
qsocket_t *net_activeSockets = NULL;
qsocket_t *net_freeSockets = NULL;
@@ -835,7 +837,9 @@ void NET_Init (void)
Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
}
+#ifndef WITHOUT_CURL
curl_global_init (CURL_GLOBAL_DEFAULT);
+#endif
}
/*
@@ -848,8 +852,9 @@ void NET_Shutdown (void)
{
qsocket_t *sock;
+#ifndef WITHOUT_CURL
curl_global_cleanup ();
-
+#endif
SetNetTime();
for (sock = net_activeSockets; sock; sock = sock->next)
diff --git a/Quake/net_sys.h b/Quake/net_sys.h
index 77727e3b8..bc334dc1c 100644
--- a/Quake/net_sys.h
+++ b/Quake/net_sys.h
@@ -31,7 +31,8 @@
#if defined(PLATFORM_BSD) || defined(PLATFORM_OSX) || \
defined(PLATFORM_AMIGA) /* bsdsocket.library */ || \
- defined(__GNU__) /* GNU/Hurd */ || defined(__riscos__)
+ defined(__GNU__) /* GNU/Hurd */ || defined(__riscos__) || \
+ defined(PLATFORM_HAIKU) /* Haiku OS */
/* struct sockaddr has unsigned char sa_len as the first member in BSD
* variants and the family member is also an unsigned char instead of an
* unsigned short. This should matter only when PLATFORM_UNIX is defined,
@@ -47,7 +48,7 @@
#endif /* BSD, sockaddr */
/* unix includes and compatibility macros */
-#if defined(PLATFORM_UNIX) || defined(PLATFORM_RISCOS)
+#if defined(PLATFORM_UNIX) || defined(PLATFORM_RISCOS) || defined(PLATFORM_HAIKU)
#include
#include
diff --git a/Quake/net_win.c b/Quake/net_win.c
index 64bf083ac..41857e26c 100644
--- a/Quake/net_win.c
+++ b/Quake/net_win.c
@@ -63,7 +63,7 @@ net_driver_t net_drivers[] =
}
};
-const int net_numdrivers = (sizeof(net_drivers) / sizeof(net_drivers[0]));
+const int net_numdrivers = Q_COUNTOF(net_drivers);
#include "net_wins.h"
@@ -118,5 +118,4 @@ net_landriver_t net_landrivers[] =
}
};
-const int net_numlandrivers = (sizeof(net_landrivers) / sizeof(net_landrivers[0]));
-
+const int net_numlandrivers = Q_COUNTOF(net_landrivers);
diff --git a/Quake/net_wipx.c b/Quake/net_wipx.c
index 31c08874c..86e17310d 100644
--- a/Quake/net_wipx.c
+++ b/Quake/net_wipx.c
@@ -36,7 +36,7 @@ static sys_socket_t net_controlsocket;
static struct sockaddr_ipx broadcastaddr;
/* externs from net_wins.c: */
-extern qboolean winsock_initialized;
+extern int winsock_initialized;
extern WSADATA winsockdata;
extern const char *__WSAE_StrError (int);
diff --git a/Quake/pl_osx.m b/Quake/pl_osx.m
index e3a5b98bb..792afd1b1 100644
--- a/Quake/pl_osx.m
+++ b/Quake/pl_osx.m
@@ -55,14 +55,22 @@ void PL_VID_Shutdown (void)
if ([types containsObject: NSPasteboardTypeString]) {
NSString* clipboardString = [pasteboard stringForType: NSPasteboardTypeString];
if (clipboardString != NULL && [clipboardString length] > 0) {
- size_t sz = [clipboardString length] + 1;
- sz = q_min((size_t)(MAX_CLIPBOARDTXT), sz);
- data = (char *) Z_Malloc((int)sz);
+ const char* srcdata = NULL;
+
#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1040) /* for ppc builds targeting 10.3 and older */
- q_strlcpy (data, [clipboardString cString], sz);
+ if ([clipboardString canBeConvertedToEncoding:NSASCIIStringEncoding])
+ srcdata = [clipboardString cString];
#else
- q_strlcpy (data, [clipboardString cStringUsingEncoding: NSASCIIStringEncoding], sz);
+ srcdata = [clipboardString cStringUsingEncoding: NSASCIIStringEncoding];
#endif
+
+ if (srcdata != NULL)
+ {
+ size_t sz = [clipboardString length] + 1;
+ sz = q_min((size_t)(MAX_CLIPBOARDTXT), sz);
+ data = (char *) Z_Malloc((int)sz);
+ q_strlcpy (data, srcdata, sz);
+ }
}
}
return data;
diff --git a/Quake/platform.h b/Quake/platform.h
index 679ecffb8..5927a0005 100644
--- a/Quake/platform.h
+++ b/Quake/platform.h
@@ -24,6 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef _QUAKE_PLATFORM_H
#define _QUAKE_PLATFORM_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* platform dependent way to set the window icon */
void PL_SetWindowIcon(void);
@@ -36,5 +40,9 @@ char *PL_GetClipboardData (void);
/* show an error dialog */
void PL_ErrorDialog(const char *text);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAKE_PLATFORM_H */
diff --git a/Quake/pr_cmds.c b/Quake/pr_cmds.c
index a896e9271..fbfde525f 100644
--- a/Quake/pr_cmds.c
+++ b/Quake/pr_cmds.c
@@ -3638,6 +3638,6 @@ builtindef_t pr_builtindefs[] =
{"sprintf", PF_BOTH(PF_sprintf), 627, DP_QC_SPRINTF}, // string(string fmt, ...)
};
-int pr_numbuiltindefs = countof (pr_builtindefs);
+int pr_numbuiltindefs = Q_COUNTOF(pr_builtindefs);
COMPILE_TIME_ASSERT (builtin_buffer_size, countof (pr_builtindefs) + 1 <= MAX_BUILTINS);
diff --git a/Quake/pr_edict.c b/Quake/pr_edict.c
index 5c7c7fae9..3f9723078 100644
--- a/Quake/pr_edict.c
+++ b/Quake/pr_edict.c
@@ -34,6 +34,8 @@ int type_size[8] = {
1 // sizeof(void *) / 4 // ev_pointer
};
+#define NUM_TYPE_SIZES (int)Q_COUNTOF(type_size)
+
static ddef_t *ED_FieldAtOfs (int ofs);
static qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s, qboolean zoned);
@@ -599,6 +601,7 @@ padded to 20 field width
const char *PR_GlobalString (int ofs)
{
static char line[512];
+ static const int lastchari = Q_COUNTOF(line) - 2;
const char *s;
int i;
ddef_t *def;
@@ -617,7 +620,11 @@ const char *PR_GlobalString (int ofs)
i = strlen(line);
for ( ; i < 20; i++)
strcat (line, " ");
- strcat (line, " ");
+
+ if (i < lastchari)
+ strcat (line, " ");
+ else
+ line[lastchari] = ' ';
return line;
}
@@ -625,6 +632,7 @@ const char *PR_GlobalString (int ofs)
const char *PR_GlobalStringNoContents (int ofs)
{
static char line[512];
+ static const int lastchari = Q_COUNTOF(line) - 2;
int i;
ddef_t *def;
@@ -637,7 +645,11 @@ const char *PR_GlobalStringNoContents (int ofs)
i = strlen(line);
for ( ; i < 20; i++)
strcat (line, " ");
- strcat (line, " ");
+
+ if (i < lastchari)
+ strcat (line, " ");
+ else
+ line[lastchari] = ' ';
return line;
}
@@ -680,6 +692,9 @@ void ED_Print (edict_t *ed)
// if the value is still all 0, skip the field
type = d->type & ~DEF_SAVEGLOBAL;
+ if (type >= NUM_TYPE_SIZES)
+ continue;
+
for (j = 0; j < type_size[type]; j++)
{
if (v[j])
@@ -734,6 +749,10 @@ void ED_Write (savedata_t *save, edict_t *ed)
// if the value is still all 0, skip the field
type = d->type & ~DEF_SAVEGLOBAL;
+
+ if (type >= NUM_TYPE_SIZES)
+ continue;
+
for (j = 0; j < type_size[type]; j++)
{
if (v[j])
@@ -1187,7 +1206,7 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
}
if (!init)
- ED_AddToFreeList (ent);
+ ED_Free (ent);
return data;
}
diff --git a/Quake/pr_exec.c b/Quake/pr_exec.c
index 8ff624e92..5b8a882ca 100644
--- a/Quake/pr_exec.c
+++ b/Quake/pr_exec.c
@@ -148,7 +148,7 @@ static void PR_PrintStatement (dstatement_t *s)
{
int i;
- if ((unsigned int)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))
+ if ((unsigned int)s->op < Q_COUNTOF(pr_opnames))
{
Con_Printf("%s ", pr_opnames[s->op]);
i = strlen(pr_opnames[s->op]);
@@ -422,7 +422,7 @@ void PR_ExecuteProgram (func_t fnum)
{
st++; /* next statement */
- if (++profile > 100000)
+ if (++profile > 0x1000000) /* was 100000 */
{
qcvm->xstatement = st - qcvm->statements;
PR_RunError("runaway loop error");
diff --git a/Quake/progs.h b/Quake/progs.h
index 9d9c2a176..dcf1e963c 100644
--- a/Quake/progs.h
+++ b/Quake/progs.h
@@ -279,7 +279,8 @@ typedef struct savedata_s
int buffersize;
} savedata_t;
-#define SAVEGAME_VERSION 5
+#define SAVEGAME_VERSION 5
+#define SAVEGAME_VERSION_KEX 6
extern THREAD_LOCAL globalvars_t *pr_global_struct;
extern THREAD_LOCAL qcvm_t *qcvm;
@@ -329,7 +330,7 @@ int SAVE_NUM_FOR_EDICT (savedata_t *save, edict_t *e);
#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + qcvm->edict_size))
-#define EDICT_TO_PROG(e) ((byte *)e - (byte *)qcvm->edicts)
+#define EDICT_TO_PROG(e) (int)((byte *)e - (byte *)qcvm->edicts)
#define PROG_TO_EDICT(e) ((edict_t *)((byte *)qcvm->edicts + e))
#define SAVE_PROG_TO_EDICT(s, e) ((edict_t *)((byte *)s->edicts + e))
diff --git a/Quake/q_stdinc.h b/Quake/q_stdinc.h
index 66090684c..0c557273a 100644
--- a/Quake/q_stdinc.h
+++ b/Quake/q_stdinc.h
@@ -117,6 +117,9 @@ typedef enum {
COMPILE_TIME_ASSERT(enum, sizeof(THE_DUMMY_ENUM) == sizeof(int));
+/* for array size: */
+#define Q_COUNTOF(x) (sizeof(x) / sizeof((x)[0]))
+
/* Provide a substitute for offsetof() if we don't have one.
* This variant works on most (but not *all*) systems...
*/
@@ -159,6 +162,10 @@ typedef int fixed4_t;
typedef int fixed8_t;
typedef int fixed16_t;
+/* natvis helpers */
+typedef struct { float data[2]; } float2_t;
+typedef struct { float data[3]; } float3_t;
+typedef struct { float data[4]; } float4_t;
/*==========================================================================*/
diff --git a/Quake/quakedef.h b/Quake/quakedef.h
index 883476bd9..3ee40bbdf 100644
--- a/Quake/quakedef.h
+++ b/Quake/quakedef.h
@@ -36,7 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define X11_VERSION 1.10
#define FITZQUAKE_VERSION 0.85 //johnfitz
-#define QUAKESPASM_VERSION 0.95
+#define QUAKESPASM_VERSION 0.96
#define QUAKESPASM_VER_PATCH 1 // helper to print a string like 0.94.7
#ifndef QUAKESPASM_VER_SUFFIX
#define QUAKESPASM_VER_SUFFIX // optional version suffix string literal like "-beta1"
@@ -115,90 +115,103 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// stats are integers communicated to the client by the server
//
-#define MAX_CL_BASE_STATS 32
-#define MAX_CL_STATS 256
-#define STAT_HEALTH 0
-#define STAT_FRAGS 1
-#define STAT_WEAPON 2
-#define STAT_AMMO 3
-#define STAT_ARMOR 4
-#define STAT_WEAPONFRAME 5
-#define STAT_SHELLS 6
-#define STAT_NAILS 7
-#define STAT_ROCKETS 8
-#define STAT_CELLS 9
-#define STAT_ACTIVEWEAPON 10
-#define STAT_NONCLIENT 11 // first stat not included in svc_clientdata
-#define STAT_TOTALSECRETS 11
-#define STAT_TOTALMONSTERS 12
-#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
-#define STAT_MONSTERS 14 // bumped by svc_killedmonster
-#define STAT_ITEMS 15 //replaces clc_clientdata info
+typedef enum
+{
+ MAX_CL_BASE_STATS = 32,
+ MAX_CL_STATS = 256,
+
+ STAT_HEALTH = 0,
+ STAT_FRAGS = 1,
+ STAT_WEAPON = 2,
+ STAT_AMMO = 3,
+ STAT_ARMOR = 4,
+ STAT_WEAPONFRAME = 5,
+ STAT_SHELLS = 6,
+ STAT_NAILS = 7,
+ STAT_ROCKETS = 8,
+ STAT_CELLS = 9,
+ STAT_ACTIVEWEAPON = 10,
+ STAT_NONCLIENT = 11, // first stat not included in svc_clientdata
+ STAT_TOTALSECRETS = 11,
+ STAT_TOTALMONSTERS = 12,
+ STAT_SECRETS = 13, // bumped on client side by svc_foundsecret
+ STAT_MONSTERS = 14, // bumped by svc_killedmonster
+ STAT_ITEMS = 15, //replaces clc_clientdata info
+} stat_t;
// stock defines
//
-#define IT_SHOTGUN 1
-#define IT_SUPER_SHOTGUN 2
-#define IT_NAILGUN 4
-#define IT_SUPER_NAILGUN 8
-#define IT_GRENADE_LAUNCHER 16
-#define IT_ROCKET_LAUNCHER 32
-#define IT_LIGHTNING 64
-#define IT_SUPER_LIGHTNING 128
-#define IT_SHELLS 256
-#define IT_NAILS 512
-#define IT_ROCKETS 1024
-#define IT_CELLS 2048
-#define IT_AXE 4096
-#define IT_ARMOR1 8192
-#define IT_ARMOR2 16384
-#define IT_ARMOR3 32768
-#define IT_SUPERHEALTH 65536
-#define IT_KEY1 131072
-#define IT_KEY2 262144
-#define IT_INVISIBILITY 524288
-#define IT_INVULNERABILITY 1048576
-#define IT_SUIT 2097152
-#define IT_QUAD 4194304
-#define IT_SIGIL1 (1<<28)
-#define IT_SIGIL2 (1<<29)
-#define IT_SIGIL3 (1<<30)
-#define IT_SIGIL4 (1<<31)
+typedef enum
+{
+ IT_SHOTGUN = 1,
+ IT_SUPER_SHOTGUN = 2,
+ IT_NAILGUN = 4,
+ IT_SUPER_NAILGUN = 8,
+ IT_GRENADE_LAUNCHER = 16,
+ IT_ROCKET_LAUNCHER = 32,
+ IT_LIGHTNING = 64,
+ IT_SUPER_LIGHTNING = 128,
+ IT_SHELLS = 256,
+ IT_NAILS = 512,
+ IT_ROCKETS = 1024,
+ IT_CELLS = 2048,
+ IT_AXE = 4096,
+ IT_ARMOR1 = 8192,
+ IT_ARMOR2 = 16384,
+ IT_ARMOR3 = 32768,
+ IT_SUPERHEALTH = 65536,
+ IT_KEY1 = 131072,
+ IT_KEY2 = 262144,
+ IT_INVISIBILITY = 524288,
+ IT_INVULNERABILITY = 1048576,
+ IT_SUIT = 2097152,
+ IT_QUAD = 4194304,
+ IT_SIGIL1 = (1<<28),
+ IT_SIGIL2 = (1<<29),
+ IT_SIGIL3 = (1<<30),
+ IT_SIGIL4 = (1<<31),
+} items_t;
//===========================================
//rogue changed and added defines
-#define RIT_SHELLS 128
-#define RIT_NAILS 256
-#define RIT_ROCKETS 512
-#define RIT_CELLS 1024
-#define RIT_AXE 2048
-#define RIT_LAVA_NAILGUN 4096
-#define RIT_LAVA_SUPER_NAILGUN 8192
-#define RIT_MULTI_GRENADE 16384
-#define RIT_MULTI_ROCKET 32768
-#define RIT_PLASMA_GUN 65536
-#define RIT_ARMOR1 8388608
-#define RIT_ARMOR2 16777216
-#define RIT_ARMOR3 33554432
-#define RIT_LAVA_NAILS 67108864
-#define RIT_PLASMA_AMMO 134217728
-#define RIT_MULTI_ROCKETS 268435456
-#define RIT_SHIELD 536870912
-#define RIT_ANTIGRAV 1073741824
-#define RIT_SUPERHEALTH 2147483648
+typedef enum
+{
+ RIT_SHELLS = 128,
+ RIT_NAILS = 256,
+ RIT_ROCKETS = 512,
+ RIT_CELLS = 1024,
+ RIT_AXE = 2048,
+ RIT_LAVA_NAILGUN = 4096,
+ RIT_LAVA_SUPER_NAILGUN = 8192,
+ RIT_MULTI_GRENADE = 16384,
+ RIT_MULTI_ROCKET = 32768,
+ RIT_PLASMA_GUN = 65536,
+ RIT_ARMOR1 = 8388608,
+ RIT_ARMOR2 = 16777216,
+ RIT_ARMOR3 = 33554432,
+ RIT_LAVA_NAILS = 67108864,
+ RIT_PLASMA_AMMO = 134217728,
+ RIT_MULTI_ROCKETS = 268435456,
+ RIT_SHIELD = 536870912,
+ RIT_ANTIGRAV = 1073741824,
+ RIT_SUPERHEALTH = 2147483648,
+} rogueitems_t;
//MED 01/04/97 added hipnotic defines
//===========================================
//hipnotic added defines
-#define HIT_PROXIMITY_GUN_BIT 16
-#define HIT_MJOLNIR_BIT 7
-#define HIT_LASER_CANNON_BIT 23
-#define HIT_PROXIMITY_GUN (1<frames[frame].frameptr;
}
+ else if (psprite->frames[frame].type == SPR_ANGLED)
+ {
+ // erysdren - angled sprites code backported from FTEQW
+ vec3_t axis[3];
+ AngleVectors(currentent->angles, axis[0], axis[1], axis[2]);
+ {
+ float f = DotProduct(vpn, axis[0]);
+ float r = DotProduct(vright, axis[0]);
+ int dir = (atan2(r, f)+1.125*M_PI)*(4/M_PI);
+ pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
+ pspriteframe = pspritegroup->frames[dir&7];
+ }
+ }
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
@@ -143,9 +156,9 @@ static void R_FlushSpriteInstances (void)
GL_UseProgram (glprogs.sprites[dither]);
if (showtris)
- GL_SetState (GLS_BLEND_OPAQUE | GLS_NO_ZWRITE | GLS_CULL_NONE | GLS_ATTRIBS(2));
+ GL_SetState (GLS_BLEND_OPAQUE | GLS_NO_ZWRITE | GLS_CULL_BACK | GLS_ATTRIBS(2));
else
- GL_SetState (GLS_BLEND_OPAQUE | GLS_CULL_NONE | GLS_ATTRIBS(2));
+ GL_SetState (GLS_BLEND_OPAQUE | GLS_CULL_BACK | GLS_ATTRIBS(2));
GL_Bind (GL_TEXTURE0, showtris ? whitetexture : batchtexture);
diff --git a/Quake/render.h b/Quake/render.h
index 963c9f45d..b2bab22f3 100644
--- a/Quake/render.h
+++ b/Quake/render.h
@@ -147,4 +147,3 @@ extern int reinit_surfcache; // if 1, surface cache is currently empty and
void D_FlushCaches (void);
#endif /* _QUAKE_RENDER_H */
-
diff --git a/Quake/sbar.c b/Quake/sbar.c
index a852ff9ae..58ec916bb 100644
--- a/Quake/sbar.c
+++ b/Quake/sbar.c
@@ -23,48 +23,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
-int sb_updates; // if >= vid.numpages, no update needed
+static int sb_updates; // if >= vid.numpages, no update needed
#define STAT_MINUS 10 // num frame for '-' stats digit
#define SBAR2_MARGIN_X 16
#define SBAR2_MARGIN_Y 10
-qpic_t *sb_nums[2][11];
-qpic_t *sb_colon, *sb_slash;
-qpic_t *sb_ibar;
-qpic_t *sb_sbar;
-qpic_t *sb_scorebar;
+static qpic_t *sb_nums[2][11];
+static qpic_t *sb_colon, *sb_slash;
+static qpic_t *sb_ibar;
+static qpic_t *sb_sbar;
+static qpic_t *sb_scorebar;
-qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes
-qpic_t *sb_ammo[4];
-qpic_t *sb_sigil[4];
-qpic_t *sb_armor[3];
-qpic_t *sb_items[32];
+static qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes
+static qpic_t *sb_ammo[4];
+static qpic_t *sb_sigil[4];
+static qpic_t *sb_armor[3];
+static qpic_t *sb_items[32];
-qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive
+static qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive
// 0 is static, 1 is temporary animation
-qpic_t *sb_face_invis;
-qpic_t *sb_face_quad;
-qpic_t *sb_face_invuln;
-qpic_t *sb_face_invis_invuln;
+static qpic_t *sb_face_invis;
+static qpic_t *sb_face_quad;
+static qpic_t *sb_face_invuln;
+static qpic_t *sb_face_invis_invuln;
-qboolean sb_showscores;
+static qboolean sb_showscores;
int sb_lines; // scan lines to draw
-qpic_t *rsb_invbar[2];
-qpic_t *rsb_weapons[5];
-qpic_t *rsb_items[2];
-qpic_t *rsb_ammo[3];
-qpic_t *rsb_teambord; // PGM 01/19/97 - team color border
+static qpic_t *rsb_invbar[2];
+static qpic_t *rsb_weapons[5];
+static qpic_t *rsb_items[2];
+static qpic_t *rsb_ammo[3];
+static qpic_t *rsb_teambord; // PGM 01/19/97 - team color border
//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
-qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
+static qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
//MED 01/04/97 added array to simplify weapon parsing
-int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
+static int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
//MED 01/04/97 added hipnotic items array
-qpic_t *hsb_items[2];
+static qpic_t *hsb_items[2];
void Sbar_MiniDeathmatchOverlay (void);
void Sbar_DeathmatchOverlay (void);
@@ -421,11 +421,6 @@ void Sbar_DrawSmallNum (int x, int y, int num)
//=============================================================================
int fragsort[MAX_SCOREBOARD];
-
-char scoreboardtext[MAX_SCOREBOARD][20];
-int scoreboardtop[MAX_SCOREBOARD];
-int scoreboardbottom[MAX_SCOREBOARD];
-int scoreboardcount[MAX_SCOREBOARD];
int scoreboardlines;
/*
@@ -467,35 +462,6 @@ int Sbar_ColorForMap (int m)
return m < 128 ? m + 8 : m + 8;
}
-/*
-===============
-Sbar_UpdateScoreboard
-===============
-*/
-void Sbar_UpdateScoreboard (void)
-{
- int i, k;
- int top, bottom;
- scoreboard_t *s;
-
- Sbar_SortFrags ();
-
-// draw the text
- memset (scoreboardtext, 0, sizeof(scoreboardtext));
-
- for (i = 0; i < scoreboardlines; i++)
- {
- k = fragsort[i];
- s = &cl.scores[k];
- sprintf (&scoreboardtext[i][1], "%3i %s", s->frags, s->name);
-
- top = s->colors & 0xf0;
- bottom = (s->colors & 15) <<4;
- scoreboardtop[i] = Sbar_ColorForMap (top);
- scoreboardbottom[i] = Sbar_ColorForMap (bottom);
- }
-}
-
/*
===============
Sbar_SoloScoreboard -- johnfitz -- new layout
@@ -508,17 +474,17 @@ void Sbar_SoloScoreboard (void)
int left, right, len;
sprintf (str,"Kills: %i/%i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
- left = 8 + strlen (str)*8;
+ left = 8 + strlen (str) * 8;
Sbar_DrawString (8, 12, str);
sprintf (str,"Secrets: %i/%i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
- right = 312 - strlen (str)*8;
+ right = 312 - strlen (str) * 8;
Sbar_DrawString (right, 12, str);
if (!fitzmode)
{ /* QuakeSpasm customization: */
q_snprintf (str, sizeof(str), "skill %i", (int)(skill.value + 0.5));
- Sbar_DrawString ((left + right)/2 - strlen(str)*4, 12, str);
+ Sbar_DrawString ((left + right) / 2 - strlen (str) * 4, 12, str);
if (cl.levelname[0])
q_snprintf (str, sizeof(str), "%s (%s)", cl.levelname, cl.mapname);
@@ -557,6 +523,24 @@ void Sbar_DrawScoreboard (void)
Sbar_DeathmatchOverlay ();
}
+/*
+===============
+Sbar_MiniScoreboardSizeCheck
+===============
+*/
+int Sbar_MiniScoreboardSizeCheck(void)
+{
+ float scale;
+
+ scale = CLAMP(1.0f, scr_sbarscale.value, (float)glwidth / 320.0f); //johnfitz
+
+ //MAX_SCOREBOARDNAME = 32, so total width for this overlay plus sbar is 632, but we can cut off some i guess
+ if (glwidth / scale < 512 || scr_viewsize.value >= 120) //johnfitz -- test should consider scr_sbarscale
+ return 0;
+
+ return 1;
+}
+
//=============================================================================
/*
@@ -773,6 +757,263 @@ void Sbar_DrawInventory (void)
}
}
+/*
+====================
+Sbar_DrawInventoryQW
+====================
+*/
+void Sbar_DrawInventoryQW (void)
+{
+ int i;
+ float time;
+ int flashon;
+ int scoreboard_y_gap = 0;
+ qpic_t *pic;
+
+ pic = Sbar_InventoryBarPic();
+
+ // handle sigil overlap w/ side scoreboard
+ if (cl.gametype == GAME_DEATHMATCH && Sbar_MiniScoreboardSizeCheck() )
+ {
+ if (rogue || hipnotic)
+ scoreboard_y_gap = 0; // no sigils so can move weps down a bit
+ else
+ scoreboard_y_gap = 24;
+ }
+
+ // draw weapons, ammo, sigils on right side if full hud
+ if(scr_viewsize.value < 110)
+ {
+ int extraguns = 2 * hipnotic;
+
+ GL_SetCanvas (CANVAS_SBAR_QW_INV);
+
+ // weapons
+ for (i = 0; i < 7; i++)
+ {
+ if (cl.items & (IT_SHOTGUN<= 10)
+ {
+ if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN< 1)
+ sb_updates = 0; // force update to remove flash
+ }
+ }
+
+ // MED 01/04/97
+ // hipnotic weapons
+ if (hipnotic)
+ {
+ int grenadeflashing = 0;
+ for (i = 0; i < 4; i++)
+ {
+ if (cl.items & (1<= 10)
+ {
+ if (cl.stats[STAT_ACTIVEWEAPON] == (1< 1)
+ sb_updates = 0; // force update to remove flash
+ }
+ }
+ }
+
+ if (rogue)
+ {
+ // check for powered up weapon.
+ if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
+ {
+ for (i=0;i<5;i++)
+ {
+ if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
+ {
+ Sbar_DrawPic (24, -69 - scoreboard_y_gap - (16 * 7) + (i+2) * 16, rsb_weapons[i]);
+ }
+ }
+ }
+ }
+
+ // ammo counts bgs
+ if (rogue) // ammo bar bg is slightly wider
+ {
+ for (i = 0; i < 4; i++)
+ {
+ Draw_SubPic(4, -45 - scoreboard_y_gap + (i * 11), 44, 11, pic, 1 / 320.f + i * (48 / 320.f), 0.f, 44 / 320.f, 11 / 24.f, NULL, scr_sbaralpha.value);
+ }
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ {
+ Draw_SubPic(6, -45 - scoreboard_y_gap + (i * 11), 42 , 11, pic, 3 / 320.f + i * (48 / 320.f), 0.f, 42 / 320.f, 11 / 24.f, NULL, scr_sbaralpha.value);
+ }
+ }
+
+ // ammo counts
+ for (i = 0; i < 4; i++)
+ {
+ Sbar_DrawSmallNum(13, -69 - scoreboard_y_gap + (i * 11), cl.stats[STAT_SHELLS + i]);
+ }
+
+ if (!rogue)
+ {
+ flashon = 0;
+
+ // sigils bg - hide if none
+ int has_a_sigil = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (cl.items & (1<<(28+i)))
+ has_a_sigil = 1;
+ }
+
+ if (has_a_sigil)
+ Draw_SubPic (16, -16 - scoreboard_y_gap + 24, 32, 16, sb_ibar, 1.f-32/320.f, 8/24.f, 32/320.f, 16/24.f, NULL, 1.f);
+
+ // sigils
+ for (i = 0; i < 4; i++)
+ {
+ if (cl.items & (1<<(28+i)))
+ {
+ time = cl.item_gettime[28+i];
+ if (time && time > cl.time - 2 && flashon)
+ { // flash frame
+ sb_updates = 0;
+ }
+ else
+ Sbar_DrawPic (16 + i*8, -16 - scoreboard_y_gap, sb_sigil[i]);
+ if (time && time > cl.time - 2)
+ sb_updates = 0;
+ }
+ }
+ }
+ }
+
+ // draw items/powerups with main hud
+ GL_SetCanvas (CANVAS_SBAR);
+
+ flashon = 0;
+ // items
+ for (i = 0; i < 6; i++)
+ {
+ if (cl.items & (1<<(17+i)))
+ {
+ time = cl.item_gettime[17+i];
+ if (time && time > cl.time - 2 && flashon)
+ { // flash frame
+ sb_updates = 0;
+ }
+ else
+ {
+ //MED 01/04/97 changed keys
+ if (!hipnotic || (i > 1))
+ {
+ Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
+ }
+ }
+ if (time && time > cl.time - 2)
+ sb_updates = 0;
+ }
+ }
+ //MED 01/04/97 added hipnotic items
+ // hipnotic items
+ if (hipnotic)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (cl.items & (1<<(24+i)))
+ {
+ time = cl.item_gettime[24+i];
+ if (time && time > cl.time - 2 && flashon )
+ { // flash frame
+ sb_updates = 0;
+ }
+ else
+ {
+ Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
+ }
+ if (time && time > cl.time - 2)
+ sb_updates = 0;
+ }
+ }
+ }
+
+ if (rogue)
+ {
+ // new rogue items
+ for (i = 0; i < 2; i++)
+ {
+ if (cl.items & (1<<(29+i)))
+ {
+ time = cl.item_gettime[29+i];
+ if (time && time > cl.time - 2 && flashon)
+ { // flash frame
+ sb_updates = 0;
+ }
+ else
+ {
+ Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
+ }
+ if (time && time > cl.time - 2)
+ sb_updates = 0;
+ }
+ }
+ }
+}
+
/*
===============
Sbar_DrawInventory2
@@ -1009,6 +1250,7 @@ static void Sbar_DrawSigils (void)
for (i = 0; i < 4; i++)
if (cl.items & (1<<(28+i)))
t = q_max (t, cl.item_gettime[28+i]);
+ t = q_max (t, cl.spawntime);
if (!sb_showscores && (cl.time - t > 3.f || scr_viewsize.value >= 120))
return;
@@ -1028,7 +1270,7 @@ static void Sbar_DrawSigils (void)
{
if (cl.items & (1<<(28+i)))
{
- t = (cl.time - cl.item_gettime[28+i]);
+ t = (cl.time - q_max (cl.item_gettime[28+i], cl.spawntime));
t = q_max (t, 0.f);
if (t >= 1.f)
t = 1.f;
@@ -1089,6 +1331,53 @@ void Sbar_DrawFrags (void)
}
}
+/*
+================
+Sbar_DrawFragsQW
+================
+*/
+void Sbar_DrawFragsQW(void)
+{
+ int numscores, i, x, color;
+ char num[12];
+ scoreboard_t *s;
+
+ Sbar_SortFrags();
+
+ // draw the text
+ numscores = q_min(scoreboardlines, 4);
+
+ for (i = 0, x = -88 + ( (4 - numscores) * 32) ; i < numscores; i++, x += 32) // fill from the right
+ {
+ s = &cl.scores[fragsort[i]];
+ if (!s->name[0])
+ continue;
+
+ // top color
+ color = s->colors & 0xf0;
+ color = Sbar_ColorForMap(color);
+ Draw_Fill(x + 10, 0, 28, 4, color, 1);
+
+ // bottom color
+ color = (s->colors & 15) << 4;
+ color = Sbar_ColorForMap(color);
+ Draw_Fill(x + 10, 4, 28, 3, color, 1);
+
+ // number
+ sprintf(num, "%3i", s->frags);
+ Sbar_DrawCharacter(x + 12, -25, num[0]);
+ Sbar_DrawCharacter(x + 20, -25, num[1]);
+ Sbar_DrawCharacter(x + 28, -25, num[2]);
+
+ // brackets
+ if (fragsort[i] == cl.viewentity - 1)
+ {
+ Sbar_DrawCharacter(x + 6, -25, 16);
+ Sbar_DrawCharacter(x + 32, -25, 17);
+ }
+ }
+}
+
/*
===============
Sbar_DrawFrags2
@@ -1397,15 +1686,34 @@ void Sbar_Draw (void)
invuln = (cl.items & IT_INVULNERABILITY) != 0;
armor = invuln ? 666 : cl.stats[STAT_ARMOR];
- if (scr_hudstyle.value < 1)
+ if (scr_hudstyle.value < 1 || scr_hudstyle.value > 2)
{
GL_SetCanvas (CANVAS_SBAR); //johnfitz
- if (scr_viewsize.value < 110) //johnfitz -- check viewsize instead of sb_lines
+ if (scr_hudstyle.value < 1) //classic hud
{
- Sbar_DrawInventory ();
- if (cl.maxclients != 1)
- Sbar_DrawFrags ();
+ if (scr_viewsize.value < 110) //johnfitz -- check viewsize instead of sb_lines
+ {
+ Sbar_DrawInventory ();
+ if (cl.maxclients != 1)
+ Sbar_DrawFrags ();
+ }
+ }
+ else //qw hud
+ {
+ if (scr_viewsize.value < 120)
+ {
+ Sbar_DrawInventoryQW();
+ }
+ if (cl.maxclients != 1 && scr_viewsize.value < 110) // qw hides frag count if MiniDeathmatchOverlay is showing
+ {
+ if (!Sbar_MiniScoreboardSizeCheck() || cl.gametype != GAME_DEATHMATCH)
+ {
+ GL_SetCanvas(CANVAS_SBAR_QW_INV);
+ Sbar_DrawFragsQW();
+ GL_SetCanvas(CANVAS_SBAR);
+ }
+ }
}
if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
@@ -1416,7 +1724,8 @@ void Sbar_Draw (void)
}
else if (scr_viewsize.value < 120) //johnfitz -- check viewsize instead of sb_lines
{
- Sbar_DrawPicAlpha (0, 0, sb_sbar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha
+ if (scr_hudstyle.value < 1)
+ Sbar_DrawPicAlpha (0, 0, sb_sbar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha
// keys (hipnotic only)
//MED 01/04/97 moved keys here so they would not be overwritten
@@ -1581,6 +1890,8 @@ void Sbar_IntermissionText (int x, int y, const char *str, int color)
while (*str)
{
qpic_t *pic = Sbar_IntermissionPicForChar (*str++, color);
+ if (!pic)
+ continue;
Draw_Pic (x, y, pic);
x += pic ? pic->width : 24;
}
@@ -1676,13 +1987,9 @@ void Sbar_MiniDeathmatchOverlay (void)
{
int i, k, top, bottom, x, y, f, numlines;
char num[12];
- float scale; //johnfitz
scoreboard_t *s;
- scale = CLAMP (1.0f, scr_sbarscale.value, (float)glwidth / 320.0f); //johnfitz
-
- //MAX_SCOREBOARDNAME = 32, so total width for this overlay plus sbar is 632, but we can cut off some i guess
- if (glwidth/scale < 512 || scr_viewsize.value >= 120) //johnfitz -- test should consider scr_sbarscale
+ if (!Sbar_MiniScoreboardSizeCheck())
return;
// scores
@@ -1790,12 +2097,12 @@ void Sbar_IntermissionOverlay (void)
GL_SetCanvas (CANVAS_MENU); //johnfitz
- q_snprintf (time, sizeof (time), "%d:%02d", cl.completed_time/60, cl.completed_time%60);
- q_snprintf (secrets, sizeof (secrets), "%d/%2d", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
- q_snprintf (monsters, sizeof (monsters), "%d/%2d", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
+ q_snprintf (time, sizeof (time), "%d:%02d", cl.completed_time / 60, cl.completed_time % 60);
+ q_snprintf (secrets, sizeof (secrets), "%d/%2d", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
+ q_snprintf (monsters, sizeof (monsters), "%d/%2d", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
- ltime = Sbar_IntermissionTextWidth (time, 0);
- lsecrets = Sbar_IntermissionTextWidth (secrets, 0);
+ ltime = Sbar_IntermissionTextWidth (time, 0);
+ lsecrets = Sbar_IntermissionTextWidth (secrets, 0);
lmonsters = Sbar_IntermissionTextWidth (monsters, 0);
total = q_max (ltime, lsecrets);
@@ -1804,14 +2111,14 @@ void Sbar_IntermissionOverlay (void)
pic = Draw_CachePic ("gfx/inter.lmp");
total += pic->width + 24;
total = q_min (320, total);
- Draw_Pic (160 - total/2, 56, pic);
+ Draw_Pic (160 - total / 2, 56, pic);
pic = Draw_CachePic ("gfx/complete.lmp");
- Draw_Pic (160 - pic->width/2, 24, pic);
+ Draw_Pic (160 - pic->width / 2, 24, pic);
- Sbar_IntermissionText (160 + total/2 - ltime, 64, time, 0);
- Sbar_IntermissionText (160 + total/2 - lsecrets, 104, secrets, 0);
- Sbar_IntermissionText (160 + total/2 - lmonsters, 144, monsters, 0);
+ Sbar_IntermissionText (160 + total / 2 - ltime, 64, time, 0);
+ Sbar_IntermissionText (160 + total / 2 - lsecrets, 104, secrets, 0);
+ Sbar_IntermissionText (160 + total / 2 - lmonsters, 144, monsters, 0);
}
diff --git a/Quake/screen.h b/Quake/screen.h
index f655f7e89..bbcde4d1c 100644
--- a/Quake/screen.h
+++ b/Quake/screen.h
@@ -58,6 +58,7 @@ typedef enum {
CANVAS_CONSOLE,
CANVAS_MENU,
CANVAS_SBAR,
+ CANVAS_SBAR_QW_INV,
CANVAS_SBAR2,
CANVAS_CROSSHAIR,
CANVAS_BOTTOMLEFT,
diff --git a/Quake/server.h b/Quake/server.h
index 4c8ebc1f0..59af5e6c4 100644
--- a/Quake/server.h
+++ b/Quake/server.h
@@ -20,8 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifndef _QUAKE_SERVER_H
-#define _QUAKE_SERVER_H
+#ifndef QUAKE_SERVER_H
+#define QUAKE_SERVER_H
// server.h
@@ -103,18 +103,20 @@ typedef struct
#define NUM_PING_TIMES 16
+enum sendsignon_e
+{
+ PRESPAWN_DONE,
+ PRESPAWN_FLUSH=1,
+ PRESPAWN_SIGNONBUFS,
+ PRESPAWN_SIGNONMSG,
+};
+
typedef struct client_s
{
qboolean active; // false = client is free
qboolean spawned; // false = don't send datagrams
qboolean dropasap; // has been told to go to another level
- enum
- {
- PRESPAWN_DONE,
- PRESPAWN_FLUSH=1,
- PRESPAWN_SIGNONBUFS,
- PRESPAWN_SIGNONMSG,
- } sendsignon; // only valid before spawned
+ enum sendsignon_e sendsignon; // only valid before spawned
int signonidx;
double last_message; // reliable messages must be sent
@@ -150,62 +152,84 @@ typedef struct client_s
//=============================================================================
// edict->movetype values
-#define MOVETYPE_NONE 0 // never moves
-#define MOVETYPE_ANGLENOCLIP 1
-#define MOVETYPE_ANGLECLIP 2
-#define MOVETYPE_WALK 3 // gravity
-#define MOVETYPE_STEP 4 // gravity, special edge handling
-#define MOVETYPE_FLY 5
-#define MOVETYPE_TOSS 6 // gravity
-#define MOVETYPE_PUSH 7 // no clip to world, push and crush
-#define MOVETYPE_NOCLIP 8
-#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
-#define MOVETYPE_BOUNCE 10
-#define MOVETYPE_GIB 11 // 2021 rerelease gibs
+typedef enum
+{
+ MOVETYPE_NONE = 0, // never moves
+ MOVETYPE_ANGLENOCLIP = 1,
+ MOVETYPE_ANGLECLIP = 2,
+ MOVETYPE_WALK = 3, // gravity
+ MOVETYPE_STEP = 4, // gravity, special edge handling
+ MOVETYPE_FLY = 5,
+ MOVETYPE_TOSS = 6, // gravity
+ MOVETYPE_PUSH = 7, // no clip to world, push and crush
+ MOVETYPE_NOCLIP = 8,
+ MOVETYPE_FLYMISSILE = 9, // extra size to monsters
+ MOVETYPE_BOUNCE = 10,
+ MOVETYPE_GIB = 11, // 2021 rerelease gibs
+} emovetype_t;
// edict->solid values
-#define SOLID_NOT 0 // no interaction with other objects
-#define SOLID_TRIGGER 1 // touch on edge, but not blocking
-#define SOLID_BBOX 2 // touch on edge, block
-#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
-#define SOLID_BSP 4 // bsp clip, touch on edge, block
+typedef enum
+{
+ SOLID_NOT = 0, // no interaction with other objects
+ SOLID_TRIGGER = 1, // touch on edge, but not blocking
+ SOLID_BBOX = 2, // touch on edge, block
+ SOLID_SLIDEBOX = 3, // touch on edge, but not an onground
+ SOLID_BSP = 4, // bsp clip, touch on edge, block
+} esolid_t;
// edict->deadflag values
-#define DEAD_NO 0
-#define DEAD_DYING 1
-#define DEAD_DEAD 2
+typedef enum
+{
+ DEAD_NO = 0,
+ DEAD_DYING = 1,
+ DEAD_DEAD = 2,
+} edeadflag_t;
-#define DAMAGE_NO 0
-#define DAMAGE_YES 1
-#define DAMAGE_AIM 2
+// edict->takedamage
+typedef enum
+{
+ DAMAGE_NO = 0,
+ DAMAGE_YES = 1,
+ DAMAGE_AIM = 2,
+} etakedamage_t;
// edict->flags
-#define FL_FLY 1
-#define FL_SWIM 2
-//#define FL_GLIMPSE 4
-#define FL_CONVEYOR 4
-#define FL_CLIENT 8
-#define FL_INWATER 16
-#define FL_MONSTER 32
-#define FL_GODMODE 64
-#define FL_NOTARGET 128
-#define FL_ITEM 256
-#define FL_ONGROUND 512
-#define FL_PARTIALGROUND 1024 // not all corners are valid
-#define FL_WATERJUMP 2048 // player jumping out of water
-#define FL_JUMPRELEASED 4096 // for jump debouncing
+typedef enum
+{
+ FL_FLY = 1,
+ FL_SWIM = 2,
+// FL_GLIMPSE = 4,
+ FL_CONVEYOR = 4,
+ FL_CLIENT = 8,
+ FL_INWATER = 16,
+ FL_MONSTER = 32,
+ FL_GODMODE = 64,
+ FL_NOTARGET = 128,
+ FL_ITEM = 256,
+ FL_ONGROUND = 512,
+ FL_PARTIALGROUND = 1024, // not all corners are valid
+ FL_WATERJUMP = 2048, // player jumping out of water
+ FL_JUMPRELEASED = 4096, // for jump debouncing
+} eflags_t;
// entity effects
-
-#define EF_BRIGHTFIELD 1
-#define EF_MUZZLEFLASH 2
-#define EF_BRIGHTLIGHT 4
-#define EF_DIMLIGHT 8
-
-#define SPAWNFLAG_NOT_EASY 256
-#define SPAWNFLAG_NOT_MEDIUM 512
-#define SPAWNFLAG_NOT_HARD 1024
-#define SPAWNFLAG_NOT_DEATHMATCH 2048
+typedef enum
+{
+ EF_BRIGHTFIELD = 1,
+ EF_MUZZLEFLASH = 2,
+ EF_BRIGHTLIGHT = 4,
+ EF_DIMLIGHT = 8,
+} efx_t;
+
+// spawnflags
+typedef enum
+{
+ SPAWNFLAG_NOT_EASY = 256,
+ SPAWNFLAG_NOT_MEDIUM = 512,
+ SPAWNFLAG_NOT_HARD = 1024,
+ SPAWNFLAG_NOT_DEATHMATCH = 2048,
+} spawnflags_t;
//============================================================================
@@ -261,8 +285,7 @@ void SV_MoveToGoal (void);
void SV_CheckForNewClients (void);
void SV_RunClients (void);
-void SV_SaveSpawnparms ();
+void SV_SaveSpawnparms (void);
void SV_SpawnServer (const char *server);
-#endif /* _QUAKE_SERVER_H */
-
+#endif /* QUAKE_SERVER_H */
diff --git a/Quake/snd_dma.c b/Quake/snd_dma.c
index e9bb7e132..2125fa722 100644
--- a/Quake/snd_dma.c
+++ b/Quake/snd_dma.c
@@ -1043,7 +1043,7 @@ static void S_SoundList (void)
int i;
sfx_t *sfx;
sfxcache_t *sc;
- int size, total;
+ int size, total;
total = 0;
for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++)
@@ -1086,12 +1086,10 @@ void S_ClearPrecache (void)
{
}
-
void S_BeginPrecaching (void)
{
}
-
void S_EndPrecaching (void)
{
}
diff --git a/Quake/snd_xmp.c b/Quake/snd_xmp.c
index d73149db8..3e9fd9b4a 100644
--- a/Quake/snd_xmp.c
+++ b/Quake/snd_xmp.c
@@ -26,7 +26,7 @@
#include "snd_codec.h"
#include "snd_codeci.h"
#include "snd_xmp.h"
-#if defined(_WIN32) && defined(XMP_NO_DLL)
+#if defined(_WIN32) && defined(LIBXMP_STATIC)
#define BUILDING_STATIC
#endif
#include
diff --git a/Quake/spritegn.h b/Quake/spritegn.h
index 1065052f0..817484286 100644
--- a/Quake/spritegn.h
+++ b/Quake/spritegn.h
@@ -104,7 +104,7 @@ typedef struct {
float interval;
} dspriteinterval_t;
-typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;
+typedef enum { SPR_SINGLE=0, SPR_GROUP, SPR_ANGLED } spriteframetype_t;
typedef struct {
spriteframetype_t type;
diff --git a/Quake/strl_fn.h b/Quake/strl_fn.h
index af7fc146f..3be2a32a1 100644
--- a/Quake/strl_fn.h
+++ b/Quake/strl_fn.h
@@ -1,11 +1,16 @@
-/* header file for BSD strlcat and strlcpy */
+/* strl_fn.h - header file for BSD strlcat and strlcpy */
#ifndef __STRLFUNCS_H
#define __STRLFUNCS_H
/* use our own copies of strlcpy and strlcat taken from OpenBSD */
+#ifdef __cplusplus
+extern "C" {
+#endif
extern size_t q_strlcpy (char *dst, const char *src, size_t size);
extern size_t q_strlcat (char *dst, const char *src, size_t size);
+#ifdef __cplusplus
+}
+#endif
#endif /* __STRLFUNCS_H */
-
diff --git a/Quake/sv_main.c b/Quake/sv_main.c
index bdd0c5a46..e4d03ec9a 100644
--- a/Quake/sv_main.c
+++ b/Quake/sv_main.c
@@ -456,7 +456,7 @@ void SV_SendServerinfo (client_t *client)
MSG_WriteByte (&client->message, svc_signonnum);
MSG_WriteByte (&client->message, 1);
- client->sendsignon = true;
+ client->sendsignon = PRESPAWN_FLUSH;
client->spawned = false; // need prespawn, spawn, etc
}
diff --git a/Quake/sys.h b/Quake/sys.h
index b5f97bb97..fa5b38210 100644
--- a/Quake/sys.h
+++ b/Quake/sys.h
@@ -126,5 +126,14 @@ void Sys_SendKeyEvents (void);
void Sys_ActivateKeyFilter (qboolean active);
+static inline qboolean Sys_IsPathSep (char c)
+{
+#ifdef _WIN32
+ return c == '/' || c == '\\';
+#else
+ return c == '/';
+#endif
+}
+
#endif /* _QUAKE_SYS_H */
diff --git a/Quake/sys_sdl_unix.c b/Quake/sys_sdl_unix.c
index cad59d92b..85d51b551 100644
--- a/Quake/sys_sdl_unix.c
+++ b/Quake/sys_sdl_unix.c
@@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include
#include
#include
-#ifdef PLATFORM_OSX
+#if defined(PLATFORM_OSX) || defined(PLATFORM_HAIKU)
#include /* dirname() and basename() */
#endif
#include
@@ -53,6 +53,7 @@ qboolean isDedicated;
#define MAX_HANDLES 32 /* johnfitz -- was 10 */
static FILE *sys_handles[MAX_HANDLES];
+static qboolean stdinIsATTY; /* from ioquake3 source */
static double rcp_counter_freq;
@@ -360,6 +361,23 @@ static char cwd[MAX_OSPATH];
#ifdef DO_USERDIRS
static char userdir[MAX_OSPATH];
+#ifdef PLATFORM_HAIKU
+#include
+#include
+
+static void Sys_GetUserdir (char *dst, size_t dstsize)
+{
+ dev_t volume = dev_for_path("/boot");
+ char buffer[B_PATH_NAME_LENGTH];
+ status_t result;
+
+ result = find_directory(B_USER_NONPACKAGED_DATA_DIRECTORY, volume, false, buffer, sizeof(buffer));
+ if (result != B_OK)
+ Sys_Error ("Couldn't determine userspace directory");
+
+ q_snprintf (dst, dstsize, "%s/%s", buffer, SYS_USERDIR);
+}
+#else
static void Sys_GetUserdir (char *dst, size_t dstsize)
{
size_t n;
@@ -386,6 +404,7 @@ static void Sys_GetUserdir (char *dst, size_t dstsize)
q_snprintf (dst, dstsize, "%s/%s", home_dir, SYS_USERDIR);
}
+#endif /* PLATFORM_HAIKU */
#endif /* DO_USERDIRS */
qboolean Sys_GetAltUserPrefDir (qboolean remastered, char *dst, size_t dstsize)
@@ -529,6 +548,21 @@ static void Sys_GetBasedir (char *argv0, char *dst, size_t dstsize)
{
char *tmp;
+ #ifdef PLATFORM_HAIKU
+ if (realpath(argv0, dst) == NULL)
+ {
+ perror("realpath");
+ if (getcwd(dst, dstsize - 1) == NULL)
+ _fail: Sys_Error ("Couldn't determine current directory");
+ }
+ else
+ {
+ /* strip off the binary name */
+ if (! (tmp = strdup (dst))) goto _fail;
+ q_strlcpy (dst, dirname(tmp), dstsize);
+ free (tmp);
+ }
+ #else
if (getcwd(dst, dstsize - 1) == NULL)
Sys_Error ("Couldn't determine current directory");
@@ -541,6 +575,7 @@ static void Sys_GetBasedir (char *argv0, char *dst, size_t dstsize)
if (tmp != dst && *tmp == '/')
*tmp = 0;
}
+ #endif
}
#endif
@@ -644,6 +679,12 @@ void Sys_FindClose (findfile_t *find)
void Sys_Init (void)
{
+ const char* term = getenv("TERM");
+ stdinIsATTY = isatty(STDIN_FILENO) &&
+ !(term && (!strcmp(term, "raw") || !strcmp(term, "dumb")));
+ if (!stdinIsATTY)
+ Sys_Printf("Terminal input not available.\n");
+
memset (cwd, 0, sizeof(cwd));
Sys_GetBasedir(host_parms->argv[0], cwd, sizeof(cwd));
host_parms->basedir = cwd;
@@ -715,6 +756,9 @@ void Sys_Printf (const char *fmt, ...)
UTF8_FromQuake (u8text, sizeof (u8text), qtext);
printf ("%s", u8text);
+
+ // log all messages to file as well if -condebug was specified
+ Con_DebugLog (u8text);
}
void Sys_Quit (void)
@@ -731,12 +775,16 @@ double Sys_DoubleTime (void)
const char *Sys_ConsoleInput (void)
{
+ static qboolean con_eof = false;
static char con_text[256];
static int textlen;
char c;
fd_set set;
struct timeval timeout;
+ if (!stdinIsATTY || con_eof)
+ return NULL;
+
FD_ZERO (&set);
FD_SET (0, &set); // stdin
timeout.tv_sec = 0;
@@ -744,7 +792,13 @@ const char *Sys_ConsoleInput (void)
while (select (1, &set, NULL, NULL, &timeout))
{
- read (0, &c, 1);
+ if (read(0, &c, 1) <= 0)
+ {
+ // Finish processing whatever is already in the
+ // buffer (if anything), then stop reading
+ con_eof = true;
+ c = '\n';
+ }
if (c == '\n' || c == '\r')
{
con_text[textlen] = '\0';
diff --git a/Quake/sys_sdl_win.c b/Quake/sys_sdl_win.c
index 4d21b3a27..caec34646 100644
--- a/Quake/sys_sdl_win.c
+++ b/Quake/sys_sdl_win.c
@@ -912,6 +912,10 @@ void Sys_Printf (const char *fmt, ...)
va_end (argptr);
UTF8_FromQuake (u8text, sizeof (u8text), qtext);
+
+ // log all messages to file as well if -condebug was specified
+ Con_DebugLog (u8text);
+
len = MultiByteToWideChar (CP_UTF8, 0, u8text, -1, wtext, countof (wtext));
if (!len)
return;
diff --git a/Quake/vid.h b/Quake/vid.h
index 5134d8208..efac76047 100644
--- a/Quake/vid.h
+++ b/Quake/vid.h
@@ -89,6 +89,7 @@ typedef enum
{
MOUSECURSOR_DEFAULT,
MOUSECURSOR_HAND,
+ MOUSECURSOR_IBEAM,
} mousecursor_t;
void *VID_GetWindow (void);
diff --git a/Quake/view.c b/Quake/view.c
index 538e647c4..1ba4e4c4e 100644
--- a/Quake/view.c
+++ b/Quake/view.c
@@ -68,10 +68,6 @@ cvar_t gl_cshiftpercent_powerup = {"gl_cshiftpercent_powerup", "100", CVAR_NONE}
cvar_t r_viewmodel_quake = {"r_viewmodel_quake", "0", CVAR_ARCHIVE};
-float v_dmg_time, v_dmg_roll, v_dmg_pitch;
-
-extern int in_forward, in_forward2, in_back;
-
vec3_t v_punchangles[2]; //johnfitz -- copied from cl.punchangle. 0 is current, 1 is previous value. never the same unless map just loaded
/*
@@ -253,10 +249,12 @@ void V_DriftPitch (void)
==============================================================================
*/
-cshift_t cshift_empty = { {130,80,50}, 0 };
-cshift_t cshift_water = { {130,80,50}, 128 };
-cshift_t cshift_slime = { {0,25,5}, 150 };
-cshift_t cshift_lava = { {255,80,0}, 150 };
+static cshift_t cshift_empty = { {130,80,50}, 0 };
+static cshift_t cshift_water = { {130,80,50}, 128 };
+static cshift_t cshift_slime = { {0,25,5}, 150 };
+static cshift_t cshift_lava = { {255,80,0}, 150 };
+
+static float v_dmg_time, v_dmg_roll, v_dmg_pitch;
float v_blend[4]; // rgba 0.0 - 1.0; see note in V_PolyBlend for more info
diff --git a/Quake/zone.h b/Quake/zone.h
index 393e322fe..74da9c741 100644
--- a/Quake/zone.h
+++ b/Quake/zone.h
@@ -91,10 +91,16 @@ Zone block
void Memory_Init (void *buf, int size);
+#ifdef __cplusplus
+extern "C" {
+#endif
void Z_Free (void *ptr);
void *Z_Malloc (int size); // returns 0 filled memory
void *Z_Realloc (void *ptr, int size);
char *Z_Strdup (const char *s);
+#ifdef __cplusplus
+}
+#endif
void *Hunk_Alloc (int size); // returns 0 filled memory
void *Hunk_AllocName (int size, const char *name);
diff --git a/Quakespasm.html b/Quakespasm.html
index e35575765..12ce9279d 100644
--- a/Quakespasm.html
+++ b/Quakespasm.html
@@ -7,8 +7,7 @@
QuakeSpasm
-
-Page last edited: October 2022.
+Page last edited: September 2023.
@@ -31,33 +30,35 @@
Buttons
@@ -164,6 +169,7 @@ Buttons
YBUTTON
+
quakespasm.pak contains a default.cfg which has been updated to give some default bindings. L/R shoulder buttons are bound to weapon switching, and L/R triggers are jump and attack.
The controller support started as Jeremiah Sypult's implementation in Quakespasm-Rift, and also uses ideas/code from LordHavoc's DarkPlaces.
@@ -206,7 +212,54 @@ 4.4 Quake '2021 re-release'
5. Changes
-5.1 Changes in 0.95.1
+5.1 Changes in 0.96.1
+
+
+
+- Fix demo recording as client-only after connection to server (was broken by signon changes in 0.96.0. Thanks to Jozsef Szalontai for issue report.)
+- Fix potential buffer overflow in COM_Parse(), e.g. with maps with oversized 'wad' fields. (Thanks to Andrei Drexler.)
+- Minor code cleanups.
+
+
+
+5.2 Changes in 0.96.0
+
+
+
+- Adjustments to joystick defaults and behaviour. See the "Controller support / Cvars" section above.
+- Fix for a mouse grabbing issue on macOS.
+- Add missing support for -ip command line option on unix / macOS.
+- Backport angled sprites code from FTEQW (spriteframetype: 2, must have 8 frames per group.)
+- Bump the progs execution runaway loop limit to 16M.
+- Add signon buffer fragmentation to fix SZ_GetSpace errors on certain maps when using protocol 999.
+- Increased MAX_DATAGRAM to 64000 to overcome packet overflows.
+- Bump the MAXALIASFRAMES limit to 1024.
+- Fix arrays to have proper sizes in gl mesh code, reflecting MAXALIASTRIS and MAXALIASVERTS correctly. (fixes SIGSEGV in mj4m4/mj4m5.)
+- Increased default value of gl_farclip to 65536.
+- Increase chase cam target trace distance to allow for chasecam to function in large open maps (useful e.g. for the func_vehicle mod.)
+- Raised default maximum number of particles to 16384 (can be set up to 32768 with -particles on the command line.)
+- Fix on-screen keyboard showing up suddenly on Steam Deck when starting a map.
+- Fix viewmodel interpolation with >10Hz animations.
+- Fix a memory leak when exiting game in SDL2 builds.
+- Fix a possible crash when handling clipboard data on macOS.
+- Fix a potential crash after loading of saved game.
+- Fix possible out-of-bound reads when handling progs type sizes.
+- Fix Dutch angle VP_PARALLEL_UPRIGHT sprites.
+- Fix an issue with lights blending by using 10 bit color depth for lightmaps. (For GLSL mode only.) Disable with "-nopackedpixels", if necessary.
+- No relative motions when the window is not focused.
+- Status bar and intermission screen tweaks.
+- Properly display monster counts > 3 digits.
+- Fix console animation with scr_conspeed <= 0.
+- Fix mouselook not working upon game quickload during a demo play.
+- Haiku operating system support.
+- Fix console when server is run noninteractively with stdin redirected from /dev/null.
+- Updated Visual Studio project files.
+- Minor code cleanups. Updated third party code, e.g. SDL, music codecs, etc.
+- Thanks to Andrei Drexler, Alexey Lysiuk, Andrey Budko, Boris I. Bendovsky, Chris Cowan, Maciej Olędzki, Simon McVittie, OscarL, Eric Wasylishen, Jaycie Ewald and Spike for patches.
+
+
+
+5.3 Changes in 0.95.1
-5.2 Changes in 0.95.0
+5.4 Changes in 0.95.0
-5.3 Changes in 0.94.7
+5.5 Changes in 0.94.7
-5.4 Changes in 0.94.6
+5.6 Changes in 0.94.6
-5.5 Changes in 0.94.5
+5.7 Changes in 0.94.5
-5.6 Changes in 0.94.4
+5.8 Changes in 0.94.4
-5.7 Changes in 0.94.3
+5.9 Changes in 0.94.3
-5.8 Changes in 0.94.2
+5.10 Changes in 0.94.2
-5.9 Changes in 0.94.1
+5.11 Changes in 0.94.1
-5.10 Changes in 0.94.0
+5.12 Changes in 0.94.0
-5.11 Changes in 0.93.2
+5.13 Changes in 0.93.2
-5.12 Changes in 0.93.1
+5.14 Changes in 0.93.1
-5.13 Changes in 0.93.0
+5.15 Changes in 0.93.0
-5.14 Changes in 0.92.1
+5.16 Changes in 0.92.1
-5.15 Changes in 0.92.0
+5.17 Changes in 0.92.0
-5.16 Changes in 0.91.0
+5.18 Changes in 0.91.0
Bugfixes
@@ -496,7 +549,7 @@
Raised limits
-5.17 Changes in 0.90.1
+5.19 Changes in 0.90.1
Bugfixes
@@ -546,7 +599,7 @@
Code cleanup
-5.18 Changes in 0.90.0
+5.20 Changes in 0.90.0
-5.19 Changes in 0.85.9
+5.21 Changes in 0.85.9
-5.20 Changes in 0.85.8
+5.22 Changes in 0.85.8
-5.21 Changes in 0.85.7
+5.23 Changes in 0.85.7
-5.22 Changes in 0.85.6
+5.24 Changes in 0.85.6
-5.23 Changes in 0.85.5
+5.25 Changes in 0.85.5
-5.24 Changes in 0.85.4
+5.26 Changes in 0.85.4
-5.25 Changes in 0.85.3
+5.27 Changes in 0.85.3
-5.26 Changes in 0.85.2
+5.28 Changes in 0.85.2
-5.27 Changes in 0.85.1
+5.29 Changes in 0.85.1
diff --git a/Quakespasm.txt b/Quakespasm.txt
index 9d00c4fbd..5780bf79b 100644
--- a/Quakespasm.txt
+++ b/Quakespasm.txt
@@ -3,7 +3,7 @@
______________________________________________________________________
- Page last edited: October 2022.
+ Page last edited: September 2023.
1. About
@@ -98,30 +98,42 @@
Controller Support - Cvars:
- - joy_deadzone - Fraction of the stick travel to be deadzone, between
- 0 and 1. Default 0.175.
+ - joy_deadzone_look - Fraction of look stick travel to be deadzone,
+ between 0 and 1. Default is 0.175.
+
+ - joy_deadzone_move - Same as above, but for the move stick. Default
+ is 0.175.
- joy_deadzone_trigger - Fraction of trigger range required to
register a button press on the analog triggers, between 0 and 1.
Default 0.2.
+ - joy_outer_threshold_look - Outer deadzone for the look stick,
+ between 0 and 1. Default 0.02.
+
+ - joy_outer_threshold_move - Outer deadzone for the move stick,
+ between 0 and 1. Default 0.02.
+
- joy_sensitivity_yaw/pitch - Max angular speed in degrees/second
- when looking. Defaults are 300 for yaw (turning left/right) and 150
+ when looking. Defaults are 240 for yaw (turning left/right) and 130
for pitch (up/down).
- joy_exponent - For the look stick, the stick displacement (between
- 0 and 1) is raised to this power. Default is 3. A value of 1 would
+ 0 and 1) is raised to this power. Default is 2. A value of 1 would
give a linear relationship between stick displacement and fraction
of the maximum angular speed.
+ - joy_exponent_move - Same as joy_exponent but for the move stick.
+ Default is 2.
+
- joy_invert - Set to 1 to invert the vertical axis of the look
stick.
- joy_swapmovelook - Set to 1 to swap the left and right analog stick
- functions. Default 0, move on the left stick, look on the right
+ functions. Default is 0, move on the left stick, look on the right
stick.
- - joy_enable - Set to 0 to disable controller support. Default 1.
+ - joy_enable - Set to 0 to disable controller support. Default is 1.
Controller Support - Buttons:
@@ -209,6 +221,95 @@
5. Changes
+ Changes in 0.96.1:
+
+ - Fix demo recording as client-only after connection to server (was
+ broken by signon changes in 0.96.0. Thanks to Jozsef Szalontai for
+ issue report.)
+
+ - Fix potential buffer overflow in COM_Parse(), e.g. with maps with
+ oversized 'wad' fields. (Thanks to Andrei Drexler.)
+
+ - Minor code cleanups.
+
+
+ Changes in 0.96.0:
+
+ - Adjustments to joystick defaults and behaviour. See the
+ "Controller support / Cvars" section above.
+
+ - Fix for a mouse grabbing issue on macOS.
+
+ - Add missing support for -ip command line option on unix / macOS.
+
+ - Backport angled sprites code from FTEQW (spriteframetype: 2, must
+ have 8 frames per group.)
+
+ - Bump the progs execution runaway loop limit to 16M.
+
+ - Add signon buffer fragmentation to fix SZ_GetSpace errors on
+ certain maps when using protocol 999.
+
+ - Increased MAX_DATAGRAM to 64000 to overcome packet overflows.
+
+ - Bump the MAXALIASFRAMES limit to 1024.
+
+ - Fix arrays to have proper sizes in gl mesh code, reflecting
+ MAXALIASTRIS and MAXALIASVERTS correctly. (fixes SIGSEGV in
+ mj4m4/mj4m5.)
+
+ - Increased default value of gl_farclip to 65536.
+
+ - Increase chase cam target trace distance to allow for chasecam to
+ function in large open maps (useful e.g. for the func_vehicle mod.)
+
+ - Raised default maximum number of particles to 16384 (can be set
+ up to 32768 with -particles on the command line.)
+
+ - Fix on-screen keyboard showing up suddenly on Steam Deck when
+ starting a map.
+
+ - Fix viewmodel interpolation with >10Hz animations.
+
+ - Fix a memory leak when exiting game in SDL2 builds.
+
+ - Fix a possible crash when handling clipboard data on macOS.
+
+ - Fix a potential crash after loading of saved game.
+
+ - Fix possible out-of-bound reads when handling progs type sizes.
+
+ - Fix Dutch angle VP_PARALLEL_UPRIGHT sprites.
+
+ - Fix an issue with lights blending by using 10 bit color depth for
+ lightmaps. (For GLSL mode only.) Disable with "-nopackedpixels",
+ if necessary.
+
+ - No relative motions when the window is not focused.
+
+ - Status bar and intermission screen tweaks.
+
+ - Properly display monster counts > 3 digits.
+
+ - Fix console animation with scr_conspeed <= 0.
+
+ - Fix mouselook not working upon game quickload during a demo play.
+
+ - Haiku operating system support.
+
+ - Fix console when server is run noninteractively with stdin
+ redirected from /dev/null.
+
+ - Updated Visual Studio project files.
+
+ - Minor code cleanups. Updated third party code, e.g. SDL, music
+ codecs, etc.
+
+ - Thanks to Andrei Drexler, Alexey Lysiuk, Andrey Budko, Boris I.
+ Bendovsky, Chris Cowan, Maciej Olędzki, Simon McVittie, OscarL,
+ Eric Wasylishen, Jaycie Ewald and Spike for patches.
+
+
Changes in 0.95.1:
- Allow mixing lit and unlit textures in the same map.
diff --git a/Windows/SDL2/WhatsNew.txt b/Windows/SDL2/WhatsNew.txt
index 1f95f0592..1d7c27e20 100644
--- a/Windows/SDL2/WhatsNew.txt
+++ b/Windows/SDL2/WhatsNew.txt
@@ -1,6 +1,23 @@
This is a list of major changes in SDL's version history.
+---------------------------------------------------------------------------
+2.28.2:
+---------------------------------------------------------------------------
+General:
+* Added the hint SDL_HINT_JOYSTICK_WGI to control whether to use Windows.Gaming.Input for controllers
+
+
+---------------------------------------------------------------------------
+2.28.0:
+---------------------------------------------------------------------------
+
+General:
+* Added SDL_HasWindowSurface() and SDL_DestroyWindowSurface() to switch between the window surface and rendering APIs
+* Added a display event SDL_DISPLAYEVENT_MOVED which is sent when the primary monitor changes or displays change position relative to each other
+* Added the hint SDL_HINT_ENABLE_SCREEN_KEYBOARD to control whether the on-screen keyboard should be shown when text input is active
+
+
---------------------------------------------------------------------------
2.26.0:
---------------------------------------------------------------------------
@@ -24,7 +41,7 @@ General:
* Added access to the individual left and right gyro sensors of the combined Joy-Cons controller
* Added a microsecond timestamp to SDL_SensorEvent and SDL_ControllerSensorEvent, when the hardware provides that information
* Added SDL_SensorGetDataWithTimestamp() and SDL_GameControllerGetSensorDataWithTimestamp() to retrieve the last sensor data with the associated microsecond timestamp
-* Added the hint SDL_HINT_HIDAPI_IGNORE_DEVICES to have the SDL HID API ignore specific devices
+* Added the hint SDL_HINT_HIDAPI_IGNORE_DEVICES to have the SDL HID API ignore specific devices
* SDL_GetRevision() now includes more information about the SDL build, including the git commit hash if available
Windows:
@@ -645,7 +662,7 @@ iOS:
tvOS:
* Added support for Apple TV
-* Added a hint SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION to control whether he Apple TV remote's joystick axes will automatically match the rotation of the remote.
+* Added a hint SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION to control whether he Apple TV remote's joystick axes will automatically match the rotation of the remote.
Android:
* Fixed SDL not resizing window when Android screen resolution changes
@@ -790,8 +807,8 @@ Linux:
* Added experimental Wayland and Mir support, disabled by default
Android:
-* Joystick support (minimum SDK version required to build SDL is now 12,
- the required runtime version remains at 10, but on such devices joystick
+* Joystick support (minimum SDK version required to build SDL is now 12,
+ the required runtime version remains at 10, but on such devices joystick
support won't be available).
* Hotplugging support for joysticks
* Added a hint SDL_HINT_ACCELEROMETER_AS_JOYSTICK to control whether the accelerometer should be listed as a 3 axis joystick, which it will by default.
@@ -844,7 +861,7 @@ iOS:
Android:
IMPORTANT: You MUST get the updated SDLActivity.java to match C code
-* Moved EGL initialization to native code
+* Moved EGL initialization to native code
* Fixed the accelerometer axis rotation relative to the device rotation
* Fixed race conditions when handling the EGL context on pause/resume
* Touch devices are available for enumeration immediately after init
diff --git a/Windows/SDL2/bin/sdl2-config b/Windows/SDL2/bin/sdl2-config
index 1b5111525..808f43569 100755
--- a/Windows/SDL2/bin/sdl2-config
+++ b/Windows/SDL2/bin/sdl2-config
@@ -40,7 +40,7 @@ while test $# -gt 0; do
lib_suffix=$optarg
;;
--version)
- echo 2.26.3
+ echo 2.28.4
;;
--cflags)
echo -I${prefix}/include -Dmain=SDL_main
diff --git a/Windows/SDL2/include/SDL_assert.h b/Windows/SDL2/include/SDL_assert.h
index ba6dcd17c..7ce823ec5 100644
--- a/Windows/SDL2/include/SDL_assert.h
+++ b/Windows/SDL2/include/SDL_assert.h
@@ -55,6 +55,8 @@ assert can have unique static variables associated with it.
#define SDL_TriggerBreakpoint() __builtin_debugtrap()
#elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
+#elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv)
+ #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "ebreak\n\t" )
#elif ( defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) ) /* this might work on other ARM targets, but this is a known quantity... */
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #22\n\t" )
#elif defined(__APPLE__) && defined(__arm__)
@@ -125,12 +127,10 @@ typedef struct SDL_AssertData
const struct SDL_AssertData *next;
} SDL_AssertData;
-#if (SDL_ASSERT_LEVEL > 0)
-
/* Never call this directly. Use the SDL_assert* macros. */
extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
- const char *,
- const char *, int)
+ const char *,
+ const char *, int)
#if defined(__clang__)
#if __has_feature(attribute_analyzer_noreturn)
/* this tells Clang's static analysis that we're a custom assert function,
@@ -151,9 +151,7 @@ extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
#define SDL_enabled_assert(condition) \
do { \
while ( !(condition) ) { \
- static struct SDL_AssertData sdl_assert_data = { \
- 0, 0, #condition, 0, 0, 0, 0 \
- }; \
+ static struct SDL_AssertData sdl_assert_data = { 0, 0, #condition, 0, 0, 0, 0 }; \
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
continue; /* go again. */ \
@@ -164,8 +162,6 @@ extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
} \
} while (SDL_NULL_WHILE_LOOP_CONDITION)
-#endif /* enabled assertions support code */
-
/* Enable various levels of assertions. */
#if SDL_ASSERT_LEVEL == 0 /* assertions disabled */
# define SDL_assert(condition) SDL_disabled_assert(condition)
diff --git a/Windows/SDL2/include/SDL_atomic.h b/Windows/SDL2/include/SDL_atomic.h
index 22ea0191a..1dd816a38 100644
--- a/Windows/SDL2/include/SDL_atomic.h
+++ b/Windows/SDL2/include/SDL_atomic.h
@@ -240,7 +240,7 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
#define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
-#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
+#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
#define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
#elif (defined(__powerpc__) || defined(__powerpc64__))
#define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
@@ -249,9 +249,8 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
#define SDL_CPUPauseInstruction() __yield()
#elif defined(__WATCOMC__) && defined(__386__)
- /* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes. */
extern __inline void SDL_CPUPauseInstruction(void);
- #pragma aux SDL_CPUPauseInstruction = "db 0f3h,90h"
+ #pragma aux SDL_CPUPauseInstruction = ".686p" ".xmm2" "pause"
#else
#define SDL_CPUPauseInstruction()
#endif
diff --git a/Windows/SDL2/include/SDL_audio.h b/Windows/SDL2/include/SDL_audio.h
index 2c0f21191..ccd35982d 100644
--- a/Windows/SDL2/include/SDL_audio.h
+++ b/Windows/SDL2/include/SDL_audio.h
@@ -169,13 +169,13 @@ typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,
* The calculated values in this structure are calculated by SDL_OpenAudio().
*
* For multi-channel audio, the default SDL channel mapping is:
- * 2: FL FR (stereo)
- * 3: FL FR LFE (2.1 surround)
- * 4: FL FR BL BR (quad)
- * 5: FL FR LFE BL BR (4.1 surround)
- * 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR)
- * 7: FL FR FC LFE BC SL SR (6.1 surround)
- * 8: FL FR FC LFE BL BR SL SR (7.1 surround)
+ * 2: FL FR (stereo)
+ * 3: FL FR LFE (2.1 surround)
+ * 4: FL FR BL BR (quad)
+ * 5: FL FR LFE BL BR (4.1 surround)
+ * 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR)
+ * 7: FL FR FC LFE BC SL SR (6.1 surround)
+ * 8: FL FR FC LFE BL BR SL SR (7.1 surround)
*/
typedef struct SDL_AudioSpec
{
diff --git a/Windows/SDL2/include/SDL_blendmode.h b/Windows/SDL2/include/SDL_blendmode.h
index b8621165d..4ecbe5078 100644
--- a/Windows/SDL2/include/SDL_blendmode.h
+++ b/Windows/SDL2/include/SDL_blendmode.h
@@ -52,7 +52,7 @@ typedef enum
dstA = dstA */
SDL_BLENDMODE_MUL = 0x00000008, /**< color multiply
dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))
- dstA = (srcA * dstA) + (dstA * (1-srcA)) */
+ dstA = dstA */
SDL_BLENDMODE_INVALID = 0x7FFFFFFF
/* Additional custom blend modes can be returned by SDL_ComposeCustomBlendMode() */
diff --git a/Windows/SDL2/include/SDL_endian.h b/Windows/SDL2/include/SDL_endian.h
index 582c3a8b8..71bc06729 100644
--- a/Windows/SDL2/include/SDL_endian.h
+++ b/Windows/SDL2/include/SDL_endian.h
@@ -140,7 +140,7 @@ extern "C" {
#if HAS_BUILTIN_BSWAP16
#define SDL_Swap16(x) __builtin_bswap16(x)
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
#pragma intrinsic(_byteswap_ushort)
#define SDL_Swap16(x) _byteswap_ushort(x)
#elif defined(__i386__) && !HAS_BROKEN_BSWAP
@@ -189,7 +189,7 @@ SDL_Swap16(Uint16 x)
#if HAS_BUILTIN_BSWAP32
#define SDL_Swap32(x) __builtin_bswap32(x)
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
#pragma intrinsic(_byteswap_ulong)
#define SDL_Swap32(x) _byteswap_ulong(x)
#elif defined(__i386__) && !HAS_BROKEN_BSWAP
@@ -241,7 +241,7 @@ SDL_Swap32(Uint32 x)
#if HAS_BUILTIN_BSWAP64
#define SDL_Swap64(x) __builtin_bswap64(x)
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
#pragma intrinsic(_byteswap_uint64)
#define SDL_Swap64(x) _byteswap_uint64(x)
#elif defined(__i386__) && !HAS_BROKEN_BSWAP
diff --git a/Windows/SDL2/include/SDL_gamecontroller.h b/Windows/SDL2/include/SDL_gamecontroller.h
index d66e1b060..140054d36 100644
--- a/Windows/SDL2/include/SDL_gamecontroller.h
+++ b/Windows/SDL2/include/SDL_gamecontroller.h
@@ -724,10 +724,10 @@ typedef enum
SDL_CONTROLLER_BUTTON_DPAD_LEFT,
SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
SDL_CONTROLLER_BUTTON_MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
- SDL_CONTROLLER_BUTTON_PADDLE1, /* Xbox Elite paddle P1 */
- SDL_CONTROLLER_BUTTON_PADDLE2, /* Xbox Elite paddle P3 */
- SDL_CONTROLLER_BUTTON_PADDLE3, /* Xbox Elite paddle P2 */
- SDL_CONTROLLER_BUTTON_PADDLE4, /* Xbox Elite paddle P4 */
+ SDL_CONTROLLER_BUTTON_PADDLE1, /* Xbox Elite paddle P1 (upper left, facing the back) */
+ SDL_CONTROLLER_BUTTON_PADDLE2, /* Xbox Elite paddle P3 (upper right, facing the back) */
+ SDL_CONTROLLER_BUTTON_PADDLE3, /* Xbox Elite paddle P2 (lower left, facing the back) */
+ SDL_CONTROLLER_BUTTON_PADDLE4, /* Xbox Elite paddle P4 (lower right, facing the back) */
SDL_CONTROLLER_BUTTON_TOUCHPAD, /* PS4/PS5 touchpad button */
SDL_CONTROLLER_BUTTON_MAX
} SDL_GameControllerButton;
diff --git a/Windows/SDL2/include/SDL_hints.h b/Windows/SDL2/include/SDL_hints.h
index 1317924ee..00beef51e 100644
--- a/Windows/SDL2/include/SDL_hints.h
+++ b/Windows/SDL2/include/SDL_hints.h
@@ -92,7 +92,7 @@ extern "C" {
* By default this hint is not set and the APK expansion files are not searched.
*/
#define SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"
-
+
/**
* \brief Android APK expansion patch file version. Should be a string number like "1", "2" etc.
*
@@ -132,13 +132,13 @@ extern "C" {
* \brief A variable to control whether we trap the Android back button to handle it manually.
* This is necessary for the right mouse button to work on some Android devices, or
* to be able to trap the back button for use in your code reliably. If set to true,
- * the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of
+ * the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of
* SDL_SCANCODE_AC_BACK.
*
* The variable can be set to the following values:
* "0" - Back button will be handled as usual for system. (default)
* "1" - Back button will be trapped, allowing you to handle the key press
- * manually. (This will also let right mouse click work on systems
+ * manually. (This will also let right mouse click work on systems
* where the right mouse button functions as back.)
*
* The value of this hint is used at runtime, so it can be changed at any time.
@@ -147,7 +147,7 @@ extern "C" {
/**
* \brief Specify an application name.
- *
+ *
* This hint lets you specify the application name sent to the OS when
* required. For example, this will often appear in volume control applets for
* audio streams, and in lists of applications which are inhibiting the
@@ -377,6 +377,17 @@ extern "C" {
*/
#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT"
+/**
+ * \brief A variable that controls whether the on-screen keyboard should be shown when text input is active
+ *
+ * The variable can be set to the following values:
+ * "0" - Do not show the on-screen keyboard
+ * "1" - Show the on-screen keyboard
+ *
+ * The default value is "1". This hint must be set before text input is activated.
+ */
+#define SDL_HINT_ENABLE_SCREEN_KEYBOARD "SDL_ENABLE_SCREEN_KEYBOARD"
+
/**
* \brief A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
*
@@ -507,7 +518,7 @@ extern "C" {
/**
* \brief If set, game controller face buttons report their values according to their labels instead of their positional layout.
- *
+ *
* For example, on Nintendo Switch controllers, normally you'd get:
*
* (Y)
@@ -569,9 +580,9 @@ extern "C" {
*
* The variable can be set to the following values:
* "0" - SDL_TEXTEDITING events are sent, and it is the application's
- * responsibility to render the text from these events and
+ * responsibility to render the text from these events and
* differentiate it somehow from committed text. (default)
- * "1" - If supported by the IME then SDL_TEXTEDITING events are not sent,
+ * "1" - If supported by the IME then SDL_TEXTEDITING events are not sent,
* and text that is being composed will be rendered in its own UI.
*/
#define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING"
@@ -996,6 +1007,15 @@ extern "C" {
*/
#define SDL_HINT_JOYSTICK_THREAD "SDL_JOYSTICK_THREAD"
+/**
+ * \brief A variable controlling whether Windows.Gaming.Input should be used for controller handling.
+ *
+ * This variable can be set to the following values:
+ * "0" - WGI is not used
+ * "1" - WGI is used (the default)
+ */
+#define SDL_HINT_JOYSTICK_WGI "SDL_JOYSTICK_WGI"
+
/**
* \brief Determines whether SDL enforces that DRM master is required in order
* to initialize the KMSDRM video backend.
@@ -1310,6 +1330,8 @@ extern "C" {
*
* This variable can be one of the following values:
* "primary" (default), "portrait", "landscape", "inverted-portrait", "inverted-landscape"
+ *
+ * Since SDL 2.0.22 this variable accepts a comma-separated list of values above.
*/
#define SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION "SDL_QTWAYLAND_CONTENT_ORIENTATION"
@@ -1452,6 +1474,17 @@ extern "C" {
*/
#define SDL_HINT_RENDER_VSYNC "SDL_RENDER_VSYNC"
+/**
+ * \brief A variable controlling whether the Metal render driver select low power device over default one
+ *
+ * This variable can be set to the following values:
+ * "0" - Use the prefered OS device
+ * "1" - Select a low power one
+ *
+ * By default the prefered OS device is used.
+ */
+#define SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE "SDL_RENDER_METAL_PREFER_LOW_POWER_DEVICE"
+
/**
* \brief A variable controlling if VSYNC is automatically disable if doesn't reach the enough FPS
*
@@ -1495,7 +1528,7 @@ extern "C" {
* disabled. You should use a string that describes what your program is doing
* (and, therefore, why the screensaver is disabled). For example, "Playing a
* game" or "Watching a video".
- *
+ *
* Setting this to "" or leaving it unset will have SDL use a reasonable
* default: "Playing a game" or something similar.
*
@@ -1509,13 +1542,13 @@ extern "C" {
* On some platforms, like Linux, a realtime priority thread may be subject to restrictions
* that require special handling by the application. This hint exists to let SDL know that
* the app is prepared to handle said restrictions.
- *
+ *
* On Linux, SDL will apply the following configuration to any thread that becomes realtime:
* * The SCHED_RESET_ON_FORK bit will be set on the scheduling policy,
* * An RLIMIT_RTTIME budget will be configured to the rtkit specified limit.
* * Exceeding this limit will result in the kernel sending SIGKILL to the app,
* * Refer to the man pages for more information.
- *
+ *
* This variable can be set to the following values:
* "0" - default platform specific behaviour
* "1" - Force SDL_THREAD_PRIORITY_TIME_CRITICAL to a realtime scheduling policy
@@ -1603,7 +1636,7 @@ extern "C" {
#define SDL_HINT_TV_REMOTE_AS_JOYSTICK "SDL_TV_REMOTE_AS_JOYSTICK"
/**
- * \brief A variable controlling whether the screensaver is enabled.
+ * \brief A variable controlling whether the screensaver is enabled.
*
* This variable can be set to the following values:
* "0" - Disable screensaver
@@ -1616,7 +1649,7 @@ extern "C" {
/**
* \brief Tell the video driver that we only want a double buffer.
*
- * By default, most lowlevel 2D APIs will use a triple buffer scheme that
+ * By default, most lowlevel 2D APIs will use a triple buffer scheme that
* wastes no CPU time on waiting for vsync after issuing a flip, but
* introduces a frame of latency. On the other hand, using a double buffer
* scheme instead is recommended for cases where low latency is an important
@@ -1747,9 +1780,9 @@ extern "C" {
/**
* \brief A variable that is the address of another SDL_Window* (as a hex string formatted with "%p").
-*
+*
* If this hint is set before SDL_CreateWindowFrom() and the SDL_Window* it is set to has
-* SDL_WINDOW_OPENGL set (and running on WGL only, currently), then two things will occur on the newly
+* SDL_WINDOW_OPENGL set (and running on WGL only, currently), then two things will occur on the newly
* created SDL_Window:
*
* 1. Its pixel format will be set to the same pixel format as this SDL_Window. This is
@@ -1815,13 +1848,13 @@ extern "C" {
/**
* \brief A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint should be used.
- *
+ *
* This variable can be set to the following values:
* "0" - Disable _NET_WM_BYPASS_COMPOSITOR
* "1" - Enable _NET_WM_BYPASS_COMPOSITOR
- *
+ *
* By default SDL will use _NET_WM_BYPASS_COMPOSITOR
- *
+ *
*/
#define SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"
@@ -1955,7 +1988,29 @@ extern "C" {
#define SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING "SDL_WINDOWS_DISABLE_THREAD_NAMING"
/**
- * \brief A variable controlling whether the windows message loop is processed by SDL
+ * \brief Controls whether menus can be opened with their keyboard shortcut (Alt+mnemonic).
+ *
+ * If the mnemonics are enabled, then menus can be opened by pressing the Alt
+ * key and the corresponding mnemonic (for example, Alt+F opens the File menu).
+ * However, in case an invalid mnemonic is pressed, Windows makes an audible
+ * beep to convey that nothing happened. This is true even if the window has
+ * no menu at all!
+ *
+ * Because most SDL applications don't have menus, and some want to use the Alt
+ * key for other purposes, SDL disables mnemonics (and the beeping) by default.
+ *
+ * Note: This also affects keyboard events: with mnemonics enabled, when a
+ * menu is opened from the keyboard, you will not receive a KEYUP event for
+ * the mnemonic key, and *might* not receive one for Alt.
+ *
+ * This variable can be set to the following values:
+ * "0" - Alt+mnemonic does nothing, no beeping. (default)
+ * "1" - Alt+mnemonic opens menus, invalid mnemonics produce a beep.
+ */
+#define SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS "SDL_WINDOWS_ENABLE_MENU_MNEMONICS"
+
+/**
+ * \brief A variable controlling whether the windows message loop is processed by SDL
*
* This variable can be set to the following values:
* "0" - The window message loop is not run
@@ -1996,7 +2051,7 @@ extern "C" {
#define SDL_HINT_WINDOWS_FORCE_SEMAPHORE_KERNEL "SDL_WINDOWS_FORCE_SEMAPHORE_KERNEL"
/**
- * \brief A variable to specify custom icon resource id from RC file on Windows platform
+ * \brief A variable to specify custom icon resource id from RC file on Windows platform
*/
#define SDL_HINT_WINDOWS_INTRESOURCE_ICON "SDL_WINDOWS_INTRESOURCE_ICON"
#define SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL "SDL_WINDOWS_INTRESOURCE_ICON_SMALL"
@@ -2035,16 +2090,16 @@ extern "C" {
*
* This hint must be set before initializing the video subsystem.
*
- * The main purpose of declaring DPI awareness is to disable OS bitmap scaling of SDL windows on monitors with
+ * The main purpose of declaring DPI awareness is to disable OS bitmap scaling of SDL windows on monitors with
* a DPI scale factor.
- *
+ *
* This hint is equivalent to requesting DPI awareness via external means (e.g. calling SetProcessDpiAwarenessContext)
* and does not cause SDL to use a virtualized coordinate system, so it will generally give you 1 SDL coordinate = 1 pixel
* even on high-DPI displays.
- *
+ *
* For more information, see:
* https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
- *
+ *
* This variable can be set to the following values:
* "" - Do not change the DPI awareness (default).
* "unaware" - Declare the process as DPI unaware. (Windows 8.1 and later).
@@ -2062,16 +2117,16 @@ extern "C" {
/**
* \brief Uses DPI-scaled points as the SDL coordinate system on Windows.
- *
+ *
* This changes the SDL coordinate system units to be DPI-scaled points, rather than pixels everywhere.
* This means windows will be appropriately sized, even when created on high-DPI displays with scaling.
- *
+ *
* e.g. requesting a 640x480 window from SDL, on a display with 125% scaling in Windows display settings,
* will create a window with an 800x600 client area (in pixels).
*
* Setting this to "1" implicitly requests process DPI awareness (setting SDL_WINDOWS_DPI_AWARENESS is unnecessary),
* and forces SDL_WINDOW_ALLOW_HIGHDPI on all windows.
- *
+ *
* This variable can be set to the following values:
* "0" - SDL coordinates equal Windows coordinates. No automatic window resizing when dragging
* between monitors with different scale factors (unless this is performed by
@@ -2082,7 +2137,7 @@ extern "C" {
#define SDL_HINT_WINDOWS_DPI_SCALING "SDL_WINDOWS_DPI_SCALING"
/**
- * \brief A variable controlling whether the window frame and title bar are interactive when the cursor is hidden
+ * \brief A variable controlling whether the window frame and title bar are interactive when the cursor is hidden
*
* This variable can be set to the following values:
* "0" - The window frame is not interactive when the cursor is hidden (no move, resize, etc)
@@ -2093,7 +2148,7 @@ extern "C" {
#define SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN "SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN"
/**
-* \brief A variable controlling whether the window is activated when the SDL_ShowWindow function is called
+* \brief A variable controlling whether the window is activated when the SDL_ShowWindow function is called
*
* This variable can be set to the following values:
* "0" - The window is activated when the SDL_ShowWindow function is called
diff --git a/Windows/SDL2/include/SDL_joystick.h b/Windows/SDL2/include/SDL_joystick.h
index 07d6a2e0a..b9b4f6228 100644
--- a/Windows/SDL2/include/SDL_joystick.h
+++ b/Windows/SDL2/include/SDL_joystick.h
@@ -44,6 +44,7 @@
#include "SDL_stdinc.h"
#include "SDL_error.h"
#include "SDL_guid.h"
+#include "SDL_mutex.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
@@ -66,6 +67,9 @@ extern "C" {
/**
* The joystick structure used to identify an SDL joystick
*/
+#ifdef SDL_THREAD_SAFETY_ANALYSIS
+extern SDL_mutex *SDL_joystick_lock;
+#endif
struct _SDL_Joystick;
typedef struct _SDL_Joystick SDL_Joystick;
@@ -131,7 +135,7 @@ typedef enum
*
* \since This function is available since SDL 2.0.7.
*/
-extern DECLSPEC void SDLCALL SDL_LockJoysticks(void);
+extern DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lock);
/**
@@ -146,7 +150,7 @@ extern DECLSPEC void SDLCALL SDL_LockJoysticks(void);
*
* \since This function is available since SDL 2.0.7.
*/
-extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void);
+extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_lock);
/**
* Count the number of joysticks attached to the system.
@@ -284,13 +288,12 @@ extern DECLSPEC SDL_JoystickType SDLCALL SDL_JoystickGetDeviceType(int device_in
/**
* Get the instance ID of a joystick.
*
- * This can be called before any joysticks are opened. If the index is out of
- * range, this function will return -1.
+ * This can be called before any joysticks are opened.
*
* \param device_index the index of the joystick to query (the N'th joystick
* on the system
* \returns the instance id of the selected joystick. If called on an invalid
- * index, this function returns zero
+ * index, this function returns -1.
*
* \since This function is available since SDL 2.0.6.
*/
diff --git a/Windows/SDL2/include/SDL_keycode.h b/Windows/SDL2/include/SDL_keycode.h
index 2523506d7..710622302 100644
--- a/Windows/SDL2/include/SDL_keycode.h
+++ b/Windows/SDL2/include/SDL_keycode.h
@@ -40,7 +40,7 @@
* an SDLK_* constant for those keys that do not generate characters.
*
* A special exception is the number keys at the top of the keyboard which
- * always map to SDLK_0...SDLK_9, regardless of layout.
+ * map to SDLK_0...SDLK_9 on AZERTY layouts.
*/
typedef Sint32 SDL_Keycode;
diff --git a/Windows/SDL2/include/SDL_main.h b/Windows/SDL2/include/SDL_main.h
index 14d39f1ec..5cc8e5913 100644
--- a/Windows/SDL2/include/SDL_main.h
+++ b/Windows/SDL2/include/SDL_main.h
@@ -263,6 +263,13 @@ extern DECLSPEC int SDLCALL SDL_UIKitRunApp(int argc, char *argv[], SDL_main_fun
*/
extern DECLSPEC int SDLCALL SDL_GDKRunApp(SDL_main_func mainFunction, void *reserved);
+/**
+ * Callback from the application to let the suspend continue.
+ *
+ * \since This function is available since SDL 2.28.0.
+ */
+extern DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
+
#endif /* __GDK__ */
#ifdef __cplusplus
diff --git a/Windows/SDL2/include/SDL_mouse.h b/Windows/SDL2/include/SDL_mouse.h
index c5712efc5..aa0757573 100644
--- a/Windows/SDL2/include/SDL_mouse.h
+++ b/Windows/SDL2/include/SDL_mouse.h
@@ -198,13 +198,9 @@ extern DECLSPEC int SDLCALL SDL_WarpMouseGlobal(int x, int y);
/**
* Set relative mouse mode.
*
- * While the mouse is in relative mode, the cursor is hidden, and the driver
- * will try to report continuous motion in the current window. Only relative
- * motion events will be delivered, the mouse position will not change.
- *
- * Note that this function will not be able to provide continuous relative
- * motion when used over Microsoft Remote Desktop, instead motion is limited
- * to the bounds of the screen.
+ * While the mouse is in relative mode, the cursor is hidden, the mouse
+ * position is constrained to the window, and SDL will report continuous
+ * relative mouse motion even if the mouse is at the edge of the window.
*
* This function will flush any pending mouse motion.
*
@@ -389,6 +385,9 @@ extern DECLSPEC SDL_Cursor *SDLCALL SDL_GetCursor(void);
/**
* Get the default cursor.
*
+ * You do not have to call SDL_FreeCursor() on the return value, but it is
+ * safe to do so.
+ *
* \returns the default cursor on success or NULL on failure.
*
* \since This function is available since SDL 2.0.0.
diff --git a/Windows/SDL2/include/SDL_mutex.h b/Windows/SDL2/include/SDL_mutex.h
index 54b6a53a3..e679d3808 100644
--- a/Windows/SDL2/include/SDL_mutex.h
+++ b/Windows/SDL2/include/SDL_mutex.h
@@ -31,6 +31,80 @@
#include "SDL_stdinc.h"
#include "SDL_error.h"
+/******************************************************************************/
+/* Enable thread safety attributes only with clang.
+ * The attributes can be safely erased when compiling with other compilers.
+ */
+#if defined(SDL_THREAD_SAFETY_ANALYSIS) && \
+ defined(__clang__) && (!defined(SWIG))
+#define SDL_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define SDL_THREAD_ANNOTATION_ATTRIBUTE__(x) /* no-op */
+#endif
+
+#define SDL_CAPABILITY(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SDL_SCOPED_CAPABILITY \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define SDL_GUARDED_BY(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define SDL_PT_GUARDED_BY(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define SDL_ACQUIRED_BEFORE(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))
+
+#define SDL_ACQUIRED_AFTER(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
+
+#define SDL_REQUIRES(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(x))
+
+#define SDL_REQUIRES_SHARED(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(x))
+
+#define SDL_ACQUIRE(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(x))
+
+#define SDL_ACQUIRE_SHARED(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(x))
+
+#define SDL_RELEASE(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(x))
+
+#define SDL_RELEASE_SHARED(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(x))
+
+#define SDL_RELEASE_GENERIC(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(x))
+
+#define SDL_TRY_ACQUIRE(x, y) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(x, y))
+
+#define SDL_TRY_ACQUIRE_SHARED(x, y) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(x, y))
+
+#define SDL_EXCLUDES(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x))
+
+#define SDL_ASSERT_CAPABILITY(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define SDL_ASSERT_SHARED_CAPABILITY(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define SDL_RETURN_CAPABILITY(x) \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define SDL_NO_THREAD_SAFETY_ANALYSIS \
+ SDL_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+/******************************************************************************/
+
+
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
@@ -96,7 +170,7 @@ extern DECLSPEC SDL_mutex *SDLCALL SDL_CreateMutex(void);
*
* \since This function is available since SDL 2.0.0.
*/
-extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex);
+extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex) SDL_ACQUIRE(mutex);
#define SDL_mutexP(m) SDL_LockMutex(m)
/**
@@ -119,7 +193,7 @@ extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex);
* \sa SDL_LockMutex
* \sa SDL_UnlockMutex
*/
-extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex);
+extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex) SDL_TRY_ACQUIRE(0, mutex);
/**
* Unlock the mutex.
@@ -138,7 +212,7 @@ extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex);
*
* \since This function is available since SDL 2.0.0.
*/
-extern DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex * mutex);
+extern DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex * mutex) SDL_RELEASE(mutex);
#define SDL_mutexV(m) SDL_UnlockMutex(m)
/**
@@ -276,7 +350,7 @@ extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem * sem);
* successful it will atomically decrement the semaphore value.
*
* \param sem the semaphore to wait on
- * \param ms the length of the timeout, in milliseconds
+ * \param timeout the length of the timeout, in milliseconds
* \returns 0 if the wait succeeds, `SDL_MUTEX_TIMEDOUT` if the wait does not
* succeed in the allotted time, or a negative error code on failure;
* call SDL_GetError() for more information.
@@ -290,7 +364,7 @@ extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem * sem);
* \sa SDL_SemValue
* \sa SDL_SemWait
*/
-extern DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem * sem, Uint32 ms);
+extern DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout);
/**
* Atomically increment a semaphore's value and wake waiting threads.
diff --git a/Windows/SDL2/include/SDL_opengl_glext.h b/Windows/SDL2/include/SDL_opengl_glext.h
index 8527e1744..ff6ad12ce 100644
--- a/Windows/SDL2/include/SDL_opengl_glext.h
+++ b/Windows/SDL2/include/SDL_opengl_glext.h
@@ -1,4 +1,8 @@
-#ifndef __gl_glext_h_
+/* SDL modified the include guard to be compatible with Mesa and Apple include guards:
+ * - Mesa uses: __gl_glext_h_
+ * - Apple uses: __glext_h_ */
+#if !defined(__glext_h_) && !defined(__gl_glext_h_)
+#define __glext_h_ 1
#define __gl_glext_h_ 1
#ifdef __cplusplus
diff --git a/Windows/SDL2/include/SDL_power.h b/Windows/SDL2/include/SDL_power.h
index be06c8b4f..1d75704c4 100644
--- a/Windows/SDL2/include/SDL_power.h
+++ b/Windows/SDL2/include/SDL_power.h
@@ -48,7 +48,6 @@ typedef enum
SDL_POWERSTATE_CHARGED /**< Plugged in, battery charged */
} SDL_PowerState;
-
/**
* Get the current power supply details.
*
@@ -65,17 +64,17 @@ typedef enum
* It's possible a platform can only report battery percentage or time left
* but not both.
*
- * \param secs seconds of battery life left, you can pass a NULL here if you
- * don't care, will return -1 if we can't determine a value, or
- * we're not running on a battery
- * \param pct percentage of battery life left, between 0 and 100, you can pass
- * a NULL here if you don't care, will return -1 if we can't
- * determine a value, or we're not running on a battery
+ * \param seconds seconds of battery life left, you can pass a NULL here if
+ * you don't care, will return -1 if we can't determine a
+ * value, or we're not running on a battery
+ * \param percent percentage of battery life left, between 0 and 100, you can
+ * pass a NULL here if you don't care, will return -1 if we
+ * can't determine a value, or we're not running on a battery
* \returns an SDL_PowerState enum representing the current battery state.
*
* \since This function is available since SDL 2.0.0.
*/
-extern DECLSPEC SDL_PowerState SDLCALL SDL_GetPowerInfo(int *secs, int *pct);
+extern DECLSPEC SDL_PowerState SDLCALL SDL_GetPowerInfo(int *seconds, int *percent);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
diff --git a/Windows/SDL2/include/SDL_render.h b/Windows/SDL2/include/SDL_render.h
index c72950142..2d3f07366 100644
--- a/Windows/SDL2/include/SDL_render.h
+++ b/Windows/SDL2/include/SDL_render.h
@@ -1731,6 +1731,11 @@ extern DECLSPEC int SDLCALL SDL_RenderReadPixels(SDL_Renderer * renderer,
*
* \param renderer the rendering context
*
+ * \threadsafety You may only call this function on the main thread. If this
+ * happens to work on a background thread on any given platform
+ * or backend, it's purely by luck and you should not rely on it
+ * to work next time.
+ *
* \since This function is available since SDL 2.0.0.
*
* \sa SDL_RenderClear
@@ -1885,7 +1890,7 @@ extern DECLSPEC void *SDLCALL SDL_RenderGetMetalLayer(SDL_Renderer * renderer);
* Note that as of SDL 2.0.18, this will return NULL if Metal refuses to give
* SDL a drawable to render to, which might happen if the window is
* hidden/minimized/offscreen. This doesn't apply to command encoders for
- * render targets, just the window's backbacker. Check your return values!
+ * render targets, just the window's backbuffer. Check your return values!
*
* \param renderer The renderer to query
* \returns an `id` on success, or NULL if the
diff --git a/Windows/SDL2/include/SDL_revision.h b/Windows/SDL2/include/SDL_revision.h
index 99af2a5b0..453ccb3d2 100644
--- a/Windows/SDL2/include/SDL_revision.h
+++ b/Windows/SDL2/include/SDL_revision.h
@@ -1,7 +1,7 @@
/* Generated by updaterev.sh, do not edit */
#ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.26.3-0-gadf31f6ec (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.28.4-0-gcc016b004 (" SDL_VENDOR_INFO ")"
#else
-#define SDL_REVISION "SDL-release-2.26.3-0-gadf31f6ec"
+#define SDL_REVISION "SDL-release-2.28.4-0-gcc016b004"
#endif
#define SDL_REVISION_NUMBER 0
diff --git a/Windows/SDL2/include/SDL_sensor.h b/Windows/SDL2/include/SDL_sensor.h
index 3010e497e..9ecce44b1 100644
--- a/Windows/SDL2/include/SDL_sensor.h
+++ b/Windows/SDL2/include/SDL_sensor.h
@@ -84,7 +84,7 @@ typedef enum
* The accelerometer returns the current acceleration in SI meters per
* second squared. This measurement includes the force of gravity, so
* a device at rest will have an value of SDL_STANDARD_GRAVITY away
- * from the center of the earth.
+ * from the center of the earth, which is a positive Y value.
*
* values[0]: Acceleration on the x axis
* values[1]: Acceleration on the y axis
diff --git a/Windows/SDL2/include/SDL_stdinc.h b/Windows/SDL2/include/SDL_stdinc.h
index bbce3d06f..182ed86ee 100644
--- a/Windows/SDL2/include/SDL_stdinc.h
+++ b/Windows/SDL2/include/SDL_stdinc.h
@@ -30,12 +30,6 @@
#include "SDL_config.h"
-#ifdef __APPLE__
-#ifndef _DARWIN_C_SOURCE
-#define _DARWIN_C_SOURCE 1 /* for memset_pattern4() */
-#endif
-#endif
-
#ifdef HAVE_SYS_TYPES_H
#include
#endif
@@ -85,7 +79,9 @@
Visual Studio. See http://msdn.microsoft.com/en-us/library/4hwaceh6.aspx
for more information.
*/
-# define _USE_MATH_DEFINES
+# ifndef _USE_MATH_DEFINES
+# define _USE_MATH_DEFINES
+# endif
# endif
# include
#endif
@@ -528,9 +524,7 @@ extern DECLSPEC void *SDLCALL SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c,
/* Note that memset() is a byte assignment and this is a 32-bit assignment, so they're not directly equivalent. */
SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
{
-#ifdef __APPLE__
- memset_pattern4(dst, &val, dwords * 4);
-#elif defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && defined(__i386__)
int u0, u1, u2;
__asm__ __volatile__ (
"cld \n\t"
@@ -694,7 +688,7 @@ extern DECLSPEC size_t SDLCALL SDL_iconv(SDL_iconv_t cd, const char **inbuf,
size_t * outbytesleft);
/**
- * This function converts a string between encodings in one pass, returning a
+ * This function converts a buffer or string between encodings in one pass, returning a
* string that must be freed with SDL_free() or NULL on error.
*
* \since This function is available since SDL 2.0.0.
@@ -722,6 +716,20 @@ size_t strlcpy(char* dst, const char* src, size_t size);
size_t strlcat(char* dst, const char* src, size_t size);
#endif
+#ifndef HAVE_WCSLCPY
+size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size);
+#endif
+
+#ifndef HAVE_WCSLCAT
+size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size);
+#endif
+
+/* Starting LLVM 16, the analyser errors out if these functions do not have
+ their prototype defined (clang-diagnostic-implicit-function-declaration) */
+#include
+#include
+#include
+
#define SDL_malloc malloc
#define SDL_calloc calloc
#define SDL_realloc realloc
diff --git a/Windows/SDL2/include/SDL_thread.h b/Windows/SDL2/include/SDL_thread.h
index 849f70bd4..b829bbad5 100644
--- a/Windows/SDL2/include/SDL_thread.h
+++ b/Windows/SDL2/include/SDL_thread.h
@@ -35,7 +35,7 @@
#include "SDL_atomic.h"
#include "SDL_mutex.h"
-#if defined(__WIN32__) || defined(__GDK__)
+#if (defined(__WIN32__) || defined(__GDK__)) && !defined(__WINRT__)
#include /* _beginthreadex() and _endthreadex() */
#endif
#if defined(__OS2__) /* for _beginthread() and _endthread() */
@@ -88,7 +88,7 @@ typedef enum {
typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
-#if defined(__WIN32__) || defined(__GDK__)
+#if (defined(__WIN32__) || defined(__GDK__)) && !defined(__WINRT__)
/**
* \file SDL_thread.h
*
diff --git a/Windows/SDL2/include/SDL_version.h b/Windows/SDL2/include/SDL_version.h
index 739134a73..57c171ccd 100644
--- a/Windows/SDL2/include/SDL_version.h
+++ b/Windows/SDL2/include/SDL_version.h
@@ -58,8 +58,8 @@ typedef struct SDL_version
/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
*/
#define SDL_MAJOR_VERSION 2
-#define SDL_MINOR_VERSION 26
-#define SDL_PATCHLEVEL 3
+#define SDL_MINOR_VERSION 28
+#define SDL_PATCHLEVEL 4
/**
* Macro to determine SDL version program was compiled against.
diff --git a/Windows/SDL2/include/SDL_video.h b/Windows/SDL2/include/SDL_video.h
index c70facb5e..c8b2d7a0d 100644
--- a/Windows/SDL2/include/SDL_video.h
+++ b/Windows/SDL2/include/SDL_video.h
@@ -187,7 +187,8 @@ typedef enum
SDL_DISPLAYEVENT_NONE, /**< Never used */
SDL_DISPLAYEVENT_ORIENTATION, /**< Display orientation has changed to data1 */
SDL_DISPLAYEVENT_CONNECTED, /**< Display has been added to the system */
- SDL_DISPLAYEVENT_DISCONNECTED /**< Display has been removed from the system */
+ SDL_DISPLAYEVENT_DISCONNECTED, /**< Display has been removed from the system */
+ SDL_DISPLAYEVENT_MOVED /**< Display has changed position */
} SDL_DisplayEventID;
/**
@@ -1274,6 +1275,17 @@ extern DECLSPEC void SDLCALL SDL_RestoreWindow(SDL_Window * window);
extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window * window,
Uint32 flags);
+/**
+ * Return whether the window has a surface associated with it.
+ *
+ * \returns SDL_TRUE if there is a surface associated with the window, or SDL_FALSE otherwise.
+ *
+ * \since This function is available since SDL 2.28.0.
+ *
+ * \sa SDL_GetWindowSurface
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasWindowSurface(SDL_Window *window);
+
/**
* Get the SDL surface associated with the window.
*
@@ -1294,6 +1306,8 @@ extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window * window,
*
* \since This function is available since SDL 2.0.0.
*
+ * \sa SDL_DestroyWindowSurface
+ * \sa SDL_HasWindowSurface
* \sa SDL_UpdateWindowSurface
* \sa SDL_UpdateWindowSurfaceRects
*/
@@ -1328,7 +1342,7 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurface(SDL_Window * window);
*
* \param window the window to update
* \param rects an array of SDL_Rect structures representing areas of the
- * surface to copy
+ * surface to copy, in pixels
* \param numrects the number of rectangles
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
@@ -1342,6 +1356,20 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurfaceRects(SDL_Window * window,
const SDL_Rect * rects,
int numrects);
+/**
+ * Destroy the surface associated with the window.
+ *
+ * \param window the window to update
+ * \returns 0 on success or a negative error code on failure; call
+ * SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.28.0.
+ *
+ * \sa SDL_GetWindowSurface
+ * \sa SDL_HasWindowSurface
+ */
+extern DECLSPEC int SDLCALL SDL_DestroyWindowSurface(SDL_Window *window);
+
/**
* Set a window's input grab mode.
*
diff --git a/Windows/SDL2/include/begin_code.h b/Windows/SDL2/include/begin_code.h
index 1f01e0bc6..4142ffeba 100644
--- a/Windows/SDL2/include/begin_code.h
+++ b/Windows/SDL2/include/begin_code.h
@@ -28,10 +28,10 @@
*/
/* This shouldn't be nested -- included it around code only. */
-#ifdef _begin_code_h
+#ifdef SDL_begin_code_h
#error Nested inclusion of begin_code.h
#endif
-#define _begin_code_h
+#define SDL_begin_code_h
#ifndef SDL_DEPRECATED
# if defined(__GNUC__) && (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
@@ -171,17 +171,17 @@
#define SDL_FALLTHROUGH [[fallthrough]]
#else
#if defined(__has_attribute)
-#define _HAS_FALLTHROUGH __has_attribute(__fallthrough__)
+#define SDL_HAS_FALLTHROUGH __has_attribute(__fallthrough__)
#else
-#define _HAS_FALLTHROUGH 0
+#define SDL_HAS_FALLTHROUGH 0
#endif /* __has_attribute */
-#if _HAS_FALLTHROUGH && \
+#if SDL_HAS_FALLTHROUGH && \
((defined(__GNUC__) && __GNUC__ >= 7) || \
(defined(__clang_major__) && __clang_major__ >= 10))
#define SDL_FALLTHROUGH __attribute__((__fallthrough__))
#else
#define SDL_FALLTHROUGH do {} while (0) /* fallthrough */
-#endif /* _HAS_FALLTHROUGH */
-#undef _HAS_FALLTHROUGH
+#endif /* SDL_HAS_FALLTHROUGH */
+#undef SDL_HAS_FALLTHROUGH
#endif /* C++17 or C2x */
#endif /* SDL_FALLTHROUGH not defined */
diff --git a/Windows/SDL2/include/close_code.h b/Windows/SDL2/include/close_code.h
index 874a926b7..b5ff3e204 100644
--- a/Windows/SDL2/include/close_code.h
+++ b/Windows/SDL2/include/close_code.h
@@ -26,10 +26,10 @@
* after you finish any function and structure declarations in your headers
*/
-#ifndef _begin_code_h
+#ifndef SDL_begin_code_h
#error close_code.h included without matching begin_code.h
#endif
-#undef _begin_code_h
+#undef SDL_begin_code_h
/* Reset structure packing at previous byte alignment */
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
diff --git a/Windows/SDL2/lib/SDL2.dll b/Windows/SDL2/lib/SDL2.dll
index 431a05437..b2d97acad 100644
Binary files a/Windows/SDL2/lib/SDL2.dll and b/Windows/SDL2/lib/SDL2.dll differ
diff --git a/Windows/SDL2/lib/SDL2.lib b/Windows/SDL2/lib/SDL2.lib
index a3583601d..b35ba62a2 100644
Binary files a/Windows/SDL2/lib/SDL2.lib and b/Windows/SDL2/lib/SDL2.lib differ
diff --git a/Windows/SDL2/lib/libSDL2.dll.a b/Windows/SDL2/lib/libSDL2.dll.a
index 7e5750f65..91ac2b8b9 100644
Binary files a/Windows/SDL2/lib/libSDL2.dll.a and b/Windows/SDL2/lib/libSDL2.dll.a differ
diff --git a/Windows/SDL2/lib/libSDL2main.a b/Windows/SDL2/lib/libSDL2main.a
index 8e67e9eda..e38628c5f 100644
Binary files a/Windows/SDL2/lib/libSDL2main.a and b/Windows/SDL2/lib/libSDL2main.a differ
diff --git a/Windows/SDL2/lib64/SDL2.dll b/Windows/SDL2/lib64/SDL2.dll
index 71f5b89a3..58b02a20c 100644
Binary files a/Windows/SDL2/lib64/SDL2.dll and b/Windows/SDL2/lib64/SDL2.dll differ
diff --git a/Windows/SDL2/lib64/SDL2.lib b/Windows/SDL2/lib64/SDL2.lib
index a237dfcda..99c5321ca 100644
Binary files a/Windows/SDL2/lib64/SDL2.lib and b/Windows/SDL2/lib64/SDL2.lib differ
diff --git a/Windows/SDL2/lib64/libSDL2.dll.a b/Windows/SDL2/lib64/libSDL2.dll.a
index 1aca6b8d6..fb3322496 100644
Binary files a/Windows/SDL2/lib64/libSDL2.dll.a and b/Windows/SDL2/lib64/libSDL2.dll.a differ
diff --git a/Windows/SDL2/lib64/libSDL2main.a b/Windows/SDL2/lib64/libSDL2main.a
index 4a1069e49..517f6a43c 100644
Binary files a/Windows/SDL2/lib64/libSDL2main.a and b/Windows/SDL2/lib64/libSDL2main.a differ
diff --git a/Windows/SDL2/main/SDL_windows.h b/Windows/SDL2/main/SDL_windows.h
index 13b0f2fa8..3842e082b 100644
--- a/Windows/SDL2/main/SDL_windows.h
+++ b/Windows/SDL2/main/SDL_windows.h
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
- Copyright (C) 1997-2022 Sam Lantinga
+ Copyright (C) 1997-2023 Sam Lantinga
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -34,31 +34,97 @@
#ifndef UNICODE
#define UNICODE 1
#endif
+#undef WINVER
#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
+#if defined(SDL_VIDEO_RENDER_D3D12)
+#define _WIN32_WINNT 0xA00 /* For D3D12, 0xA00 is required */
+#elif defined(HAVE_SHELLSCALINGAPI_H)
+#define _WIN32_WINNT 0x603 /* For DPI support */
+#else
+#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
+#endif
+#define WINVER _WIN32_WINNT
+
+#elif defined(__WINGDK__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#ifndef STRICT
+#define STRICT 1
+#endif
+#ifndef UNICODE
+#define UNICODE 1
+#endif
+#undef WINVER
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0xA00
+#define WINVER _WIN32_WINNT
+
+#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#ifndef STRICT
+#define STRICT 1
+#endif
+#ifndef UNICODE
+#define UNICODE 1
+#endif
+#undef WINVER
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0xA00
+#define WINVER _WIN32_WINNT
+#endif
+
+/* See https://github.com/libsdl-org/SDL/pull/7607 */
+/* force_align_arg_pointer attribute requires gcc >= 4.2.x. */
+#if defined(__clang__)
+#define HAVE_FORCE_ALIGN_ARG_POINTER
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+#define HAVE_FORCE_ALIGN_ARG_POINTER
+#endif
+#if defined(__GNUC__) && defined(__i386__) && defined(HAVE_FORCE_ALIGN_ARG_POINTER)
+#define MINGW32_FORCEALIGN __attribute__((force_align_arg_pointer))
+#else
+#define MINGW32_FORCEALIGN
#endif
#include
-#include /* for REFIID with broken mingw.org headers */
+#include /* for REFIID with broken mingw.org headers */
+
+/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
+#if defined(_MSC_VER) && (_MSC_VER <= 1200)
+#ifndef DWORD_PTR
+#define DWORD_PTR DWORD
+#endif
+#ifndef LONG_PTR
+#define LONG_PTR LONG
+#endif
+#endif
#include "SDL_rect.h"
/* Routines to convert from UTF8 to native Windows text */
-#define WIN_StringToUTF8W(S) SDL_iconv_string("UTF-8", "UTF-16LE", (const char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR))
-#define WIN_UTF8ToStringW(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)(S), SDL_strlen(S)+1)
+#define WIN_StringToUTF8W(S) SDL_iconv_string("UTF-8", "UTF-16LE", (const char *)(S), (SDL_wcslen(S) + 1) * sizeof(WCHAR))
+#define WIN_UTF8ToStringW(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)(S), SDL_strlen(S) + 1)
/* !!! FIXME: UTF8ToString() can just be a SDL_strdup() here. */
-#define WIN_StringToUTF8A(S) SDL_iconv_string("UTF-8", "ASCII", (const char *)(S), (SDL_strlen(S)+1))
-#define WIN_UTF8ToStringA(S) SDL_iconv_string("ASCII", "UTF-8", (const char *)(S), SDL_strlen(S)+1)
+#define WIN_StringToUTF8A(S) SDL_iconv_string("UTF-8", "ASCII", (const char *)(S), (SDL_strlen(S) + 1))
+#define WIN_UTF8ToStringA(S) SDL_iconv_string("ASCII", "UTF-8", (const char *)(S), SDL_strlen(S) + 1)
#if UNICODE
#define WIN_StringToUTF8 WIN_StringToUTF8W
#define WIN_UTF8ToString WIN_UTF8ToStringW
-#define SDL_tcslen SDL_wcslen
-#define SDL_tcsstr SDL_wcsstr
+#define SDL_tcslen SDL_wcslen
+#define SDL_tcsstr SDL_wcsstr
#else
#define WIN_StringToUTF8 WIN_StringToUTF8A
#define WIN_UTF8ToString WIN_UTF8ToStringA
-#define SDL_tcslen SDL_strlen
-#define SDL_tcsstr SDL_strstr
+#define SDL_tcslen SDL_strlen
+#define SDL_tcsstr SDL_strstr
+#endif
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
#endif
/* Sets an error message based on a given HRESULT */
@@ -93,13 +159,21 @@ extern BOOL WIN_IsWindows8OrGreater(void);
extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid);
/* Checks to see if two GUID are the same. */
-extern BOOL WIN_IsEqualGUID(const GUID * a, const GUID * b);
+extern BOOL WIN_IsEqualGUID(const GUID *a, const GUID *b);
extern BOOL WIN_IsEqualIID(REFIID a, REFIID b);
/* Convert between SDL_rect and RECT */
extern void WIN_RECTToRect(const RECT *winrect, SDL_Rect *sdlrect);
extern void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect);
+/* Returns SDL_TRUE if the rect is empty */
+extern BOOL WIN_IsRectEmpty(const RECT *rect);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _INCLUDED_WINDOWS_H */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Windows/SDL2/main/SDL_windows_main.c b/Windows/SDL2/main/SDL_windows_main.c
index d00989c3a..0ce41a20d 100644
--- a/Windows/SDL2/main/SDL_windows_main.c
+++ b/Windows/SDL2/main/SDL_windows_main.c
@@ -8,7 +8,7 @@
#ifdef __WIN32__
/* Include this so we define UNICODE properly */
-#include "SDL_windows.h" /* copied here from the SDL2 source tree */
+#include "SDL_windows.h"
#include /* CommandLineToArgvW() */
/* Include the SDL main definition header */
@@ -16,12 +16,11 @@
#include "SDL_main.h"
#ifdef main
-# undef main
+#undef main
#endif /* main */
/* Pop up an out of memory message, returns to Windows */
-static BOOL
-OutOfMemory(void)
+static BOOL OutOfMemory(void)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
return FALSE;
@@ -29,16 +28,15 @@ OutOfMemory(void)
#if defined(_MSC_VER)
/* The VC++ compiler needs main/wmain defined */
-# define console_ansi_main main
-# if UNICODE
-# define console_wmain wmain
-# endif
+#define console_ansi_main main
+#if UNICODE
+#define console_wmain wmain
+#endif
#endif
/* Gets the arguments with GetCommandLine, converts them to argc and argv
and calls SDL_main */
-static int
-main_getcmdline(void)
+static int main_getcmdline(void)
{
LPWSTR *argvw;
char **argv;
@@ -56,17 +54,17 @@ main_getcmdline(void)
/* Parse it into argv and argc */
argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv));
- if (!argv) {
+ if (argv == NULL) {
return OutOfMemory();
}
for (i = 0; i < argc; ++i) {
DWORD len;
char *arg = WIN_StringToUTF8W(argvw[i]);
- if (!arg) {
+ if (arg == NULL) {
return OutOfMemory();
}
len = (DWORD)SDL_strlen(arg);
- argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 1);
+ argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)len + 1);
if (!argv[i]) {
return OutOfMemory();
}
@@ -91,25 +89,22 @@ main_getcmdline(void)
}
/* This is where execution begins [console apps, ansi] */
-int
-console_ansi_main(int argc, char *argv[])
+int console_ansi_main(int argc, char *argv[])
{
return main_getcmdline();
}
-
#if UNICODE
/* This is where execution begins [console apps, unicode] */
-int
-console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
+int console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
{
return main_getcmdline();
}
#endif
/* This is where execution begins [windowed apps] */
-int WINAPI
-WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
+int WINAPI MINGW32_FORCEALIGN
+WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) /* NOLINT(readability-inconsistent-declaration-parameter-name) */
{
return main_getcmdline();
}
diff --git a/Windows/SDL2/watcom/SDL2.def b/Windows/SDL2/watcom/SDL2.def
index ed849a0b6..5904992bc 100644
--- a/Windows/SDL2/watcom/SDL2.def
+++ b/Windows/SDL2/watcom/SDL2.def
@@ -843,3 +843,6 @@ SDL_GameControllerGetSensorDataWithTimestamp
SDL_SensorGetDataWithTimestamp
SDL_ResetHints
SDL_strcasestr
+SDL_HasWindowSurface
+SDL_DestroyWindowSurface
+
diff --git a/Windows/SDL2/watcom/SDL2.exp b/Windows/SDL2/watcom/SDL2.exp
index f3b21e1c8..066acebb9 100644
--- a/Windows/SDL2/watcom/SDL2.exp
+++ b/Windows/SDL2/watcom/SDL2.exp
@@ -840,3 +840,5 @@
++'_SDL_SensorGetDataWithTimestamp'.'SDL2.dll'..'SDL_SensorGetDataWithTimestamp'
++'_SDL_ResetHints'.'SDL2.dll'..'SDL_ResetHints'
++'_SDL_strcasestr'.'SDL2.dll'..'SDL_strcasestr'
+++'_SDL_HasWindowSurface'.'SDL2.dll'..'SDL_HasWindowSurface'
+++'_SDL_DestroyWindowSurface'.'SDL2.dll'..'SDL_DestroyWindowSurface'
diff --git a/Windows/SDL2/watcom/SDL2.lib b/Windows/SDL2/watcom/SDL2.lib
index badd61308..577131a7e 100644
Binary files a/Windows/SDL2/watcom/SDL2.lib and b/Windows/SDL2/watcom/SDL2.lib differ
diff --git a/Windows/VisualStudio/custom_build.props b/Windows/VisualStudio/custom_build.props
new file mode 100644
index 000000000..c8632be23
--- /dev/null
+++ b/Windows/VisualStudio/custom_build.props
@@ -0,0 +1,12 @@
+
+
+
+
+ /DIRONWAIL_VER_SUFFIX=\"$(VER_SUFFIX)\" %(AdditionalOptions)
+
+
+
+ $(SolutionDir)$(BUILD_DIR)\
+ $(BUILD_DIR)\Out\
+
+
diff --git a/Windows/VisualStudio/ironwail.natvis b/Windows/VisualStudio/ironwail.natvis
new file mode 100644
index 000000000..88a8be9cf
--- /dev/null
+++ b/Windows/VisualStudio/ironwail.natvis
@@ -0,0 +1,386 @@
+
+
+
+
+
+ [{data[0],g} {data[1],g} {data[2],g}]
+
+ - data[0]
+ - data[1]
+ - data[2]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #{-first_statement} {PR_GetString(s_name),sb} ({qcvm->builtins[-first_statement],na})
+ #{-first_statement} {PR_GetString(s_name),sb} (INVALID)
+
+ {PR_GetString(s_name),sb} ({PR_GetString(s_file),sb})
+
+
+ - PR_GetString(s_name),sb
+ - PR_GetString(s_file),sb
+
+ builtin
+ QuakeC
+
+
+
+ #{-first_statement}
+
+ - qcvm->builtins[-first_statement],na
+
+ INVALID
+
+
+ - parm_size,[numparms]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .void {PR_GetString(s_name),sb}
+ .string {PR_GetString(s_name),sb}
+ .float {PR_GetString(s_name),sb}
+ .vector {PR_GetString(s_name),sb}
+ .entity {PR_GetString(s_name),sb}
+ .field {PR_GetString(s_name),sb}
+ .void() {PR_GetString(s_name),sb}
+ .pointer {PR_GetString(s_name),sb}
+ .??? {PR_GetString(s_name),sb}
+
+
+ - PR_GetString(s_name),sb
+ - Type(),en
+ - IsSaved()
+ - ofs*4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #{EntNum(),i} FREE LINKED
+ #{EntNum(),i} FREE LINKED
+ #{EntNum(),i} {PR_GetString(v.classname),sb} {v.health,g}hp
+
+
+
+ - EntNum()
+ - PR_GetString(v.classname),s
+ - free,en
+ - IsLinked(),b
+
+
+
+
+ - (esolid_t)v.solid
+ - (emovetype_t)v.movetype
+ - (eflags_t)v.flags
+ - *(float3_t*)v.origin,g
+ - *(float3_t*)v.oldorigin,g
+ - *(float3_t*)v.angles,g
+ - v.fixangle,g
+ - *(float3_t*)v.v_angle,g
+ - *(float3_t*)v.view_ofs,g
+ - v.idealpitch,g
+ - *(float3_t*)v.punchangle,g
+ - *(float3_t*)v.velocity,g
+ - *(float3_t*)v.avelocity,g
+ - *(float3_t*)v.movedir,g
+ - *(float3_t*)v.size,g
+ - HullForSize(v.absmax[0]-v.absmin[0])
+ - *(float3_t*)v.absmin,g
+ - *(float3_t*)v.absmax,g
+
+ [{(v.absmin[0]+v.absmax[0])*0.5f,g} {(v.absmin[1]+v.absmax[1])*0.5f,g} {(v.absmin[2]+v.absmax[2])*0.5f,g}]
+
+ - *(float3_t*)v.mins,g
+ - *(float3_t*)v.maxs,g
+ - PROG_TO_EDICT(v.groundentity),na
+ - v.waterlevel,g
+ - v.watertype,g
+ - v.ideal_yaw,g
+ - v.yaw_speed,g
+ - v.teleport_time,g
+
+
+
+
+
+
+ - PR_GetString(v.model),s
+ - v.modelindex,g
+ - v.skin,g
+ - v.frame,g
+ - (efx_t)v.flags
+ - PR_GetString(v.weaponmodel),s
+ - v.weaponframe,g
+ - v.colormap,g
+
+
+
+
+
+
+ - v.sounds,g
+ - PR_GetString(v.noise),s
+ - PR_GetString(v.noise1),s
+ - PR_GetString(v.noise2),s
+ - PR_GetString(v.noise3),s
+
+
+
+
+
+
+ - PR_GetString(v.target),s
+ - PR_GetString(v.targetname),s
+ - PR_GetString(v.netname),s
+ - PR_GetString(v.message),s
+ - v.nextthink,g
+ - v.ltime,g
+ - qcvm->time,g
+ - GetFunction(v.think),na
+ - GetFunction(v.use),na
+ - GetFunction(v.touch),na
+ - GetFunction(v.blocked),na
+ - PROG_TO_EDICT(v.owner),na
+ - PROG_TO_EDICT(v.goalentity),na
+
+
+
+
+
+
+ - v.health,g
+ - v.max_health,g
+ - v.armortype,g
+ - v.armorvalue,g
+ - (etakedamage_t)v.takedamage
+ - (edeadflag_t)v.deadflag
+ - PROG_TO_EDICT(v.dmg_inflictor),na
+ - v.dmg_take,g
+ - v.dmg_save,g
+ - PROG_TO_EDICT(v.enemy),na
+ - PROG_TO_EDICT(v.aiment),na
+ - v.frags,g
+ - v.currentammo,g
+ - v.ammo_shells,g
+ - v.ammo_nails,g
+ - v.ammo_rockets,g
+ - v.ammo_cells,g
+ - v.items,g
+
+
+
+
+
+
+
+
+
+
+
+ - PROG_TO_EDICT(iter),na
+ iter = PROG_TO_EDICT(iter)->v.chain
+ index++
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - PR_GetString(*(int*)FieldData(i)),s
+ - PROG_TO_EDICT(*(int*)FieldData(i)),na
+ - GetFunction(*(int*)FieldData(i)),na
+ - SafeFieldPtr(*(int*)FieldData(i)),na
+ - *(float*)FieldData(i),g
+ - *(float3_t*)FieldData(i),g
+ - (void*)FieldData(i)
+
+ i++
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ type=LEAF solids={HasSolids()} triggers={HasTriggers()}
+ type=NODE axis={axis} dist={dist,g} solids={HasSolids()} triggers={HasTriggers()}
+
+
+
+
+
+
+
+
+
+
+
+
+ - EdictFromLink(iter),na
+ iter = iter->next
+ index++
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - EdictFromLink(iter),na
+ iter = iter->next
+ index++
+
+
+
+
+
+ - children
+
+
+
+
+
diff --git a/Windows/VisualStudio/ironwail.vcxproj b/Windows/VisualStudio/ironwail.vcxproj
index 5a6507ec1..0bb359b13 100644
--- a/Windows/VisualStudio/ironwail.vcxproj
+++ b/Windows/VisualStudio/ironwail.vcxproj
@@ -324,6 +324,12 @@ copy "$(SolutionDir)..\zlib\$(PlatformShortName)\*.dll" "$(TargetDir)"
+
+ true
+ true
+ true
+ true
+
@@ -405,6 +411,9 @@ copy "$(SolutionDir)..\zlib\$(PlatformShortName)\*.dll" "$(TargetDir)"
+
+
+
diff --git a/Windows/VisualStudio/ironwail.vcxproj.filters b/Windows/VisualStudio/ironwail.vcxproj.filters
index 5a944f3ac..023e0873e 100644
--- a/Windows/VisualStudio/ironwail.vcxproj.filters
+++ b/Windows/VisualStudio/ironwail.vcxproj.filters
@@ -261,6 +261,9 @@
Source Files
+
+ Source Files
+
@@ -479,4 +482,7 @@
Resource Files
+
+
+
\ No newline at end of file
diff --git a/Windows/codecs/include/xmp.h b/Windows/codecs/include/xmp.h
index e38857836..22db2a3da 100644
--- a/Windows/codecs/include/xmp.h
+++ b/Windows/codecs/include/xmp.h
@@ -9,26 +9,40 @@
extern "C" {
#endif
-#define XMP_VERSION "4.5.1"
-#define XMP_VERCODE 0x040501
+#define XMP_VERSION "4.6.0"
+#define XMP_VERCODE 0x040600
#define XMP_VER_MAJOR 4
-#define XMP_VER_MINOR 5
-#define XMP_VER_RELEASE 1
+#define XMP_VER_MINOR 6
+#define XMP_VER_RELEASE 0
#if defined(_WIN32) && !defined(__CYGWIN__)
-# if defined(BUILDING_STATIC)
+# if defined(LIBXMP_STATIC)
# define LIBXMP_EXPORT
# elif defined(BUILDING_DLL)
# define LIBXMP_EXPORT __declspec(dllexport)
# else
# define LIBXMP_EXPORT __declspec(dllimport)
# endif
-#elif defined(__OS2__) && defined(__WATCOMC__) && defined(__SW_BD)
+#elif defined(__OS2__) && defined(__WATCOMC__)
+# if defined(LIBXMP_STATIC)
+# define LIBXMP_EXPORT
+# elif defined(BUILDING_DLL)
# define LIBXMP_EXPORT __declspec(dllexport)
+# else
+# define LIBXMP_EXPORT
+# endif
#elif (defined(__GNUC__) || defined(__clang__) || defined(__HP_cc)) && defined(XMP_SYM_VISIBILITY)
-# define LIBXMP_EXPORT __attribute__((visibility ("default")))
+# if defined(LIBXMP_STATIC)
+# define LIBXMP_EXPORT
+# else
+# define LIBXMP_EXPORT __attribute__((visibility("default")))
+# endif
#elif defined(__SUNPRO_C) && defined(XMP_LDSCOPE_GLOBAL)
-# define LIBXMP_EXPORT __global
+# if defined(LIBXMP_STATIC)
+# define LIBXMP_EXPORT
+# else
+# define LIBXMP_EXPORT __global
+# endif
#elif defined(EMSCRIPTEN)
# define LIBXMP_EXPORT EMSCRIPTEN_KEEPALIVE
# define LIBXMP_EXPORT_VAR
@@ -36,7 +50,7 @@ extern "C" {
# define LIBXMP_EXPORT
#endif
-#if !defined (LIBXMP_EXPORT_VAR)
+#if !defined(LIBXMP_EXPORT_VAR)
# define LIBXMP_EXPORT_VAR LIBXMP_EXPORT
#endif
@@ -241,6 +255,7 @@ struct xmp_sample {
#define XMP_SAMPLE_LOOP_FULL (1 << 4) /* Play full sample before looping */
#define XMP_SAMPLE_SLOOP (1 << 5) /* Sample has sustain loop */
#define XMP_SAMPLE_SLOOP_BIDIR (1 << 6) /* Bidirectional sustain loop */
+#define XMP_SAMPLE_STEREO (1 << 7) /* Interlaced stereo sample */
#define XMP_SAMPLE_SYNTH (1 << 15) /* Data contains synth patch */
int flg; /* Flags */
unsigned char *data; /* Sample data */
diff --git a/Windows/codecs/x64/libmpg123-0.dll b/Windows/codecs/x64/libmpg123-0.dll
index 1eb100c3f..8b7de4dfd 100644
Binary files a/Windows/codecs/x64/libmpg123-0.dll and b/Windows/codecs/x64/libmpg123-0.dll differ
diff --git a/Windows/codecs/x64/libopusfile-0.dll b/Windows/codecs/x64/libopusfile-0.dll
index 92b3cdb5b..72b19c9ef 100644
Binary files a/Windows/codecs/x64/libopusfile-0.dll and b/Windows/codecs/x64/libopusfile-0.dll differ
diff --git a/Windows/codecs/x64/libxmp.dll b/Windows/codecs/x64/libxmp.dll
index 588da83b0..aa62e7f9f 100644
Binary files a/Windows/codecs/x64/libxmp.dll and b/Windows/codecs/x64/libxmp.dll differ
diff --git a/Windows/codecs/x86-watcom/libxmp.lib b/Windows/codecs/x86-watcom/libxmp.lib
index bf0c70a71..1a82ce9f2 100644
Binary files a/Windows/codecs/x86-watcom/libxmp.lib and b/Windows/codecs/x86-watcom/libxmp.lib differ
diff --git a/Windows/codecs/x86-watcom/mpg123.lib b/Windows/codecs/x86-watcom/mpg123.lib
index 53fc127f9..a7e20b874 100644
Binary files a/Windows/codecs/x86-watcom/mpg123.lib and b/Windows/codecs/x86-watcom/mpg123.lib differ
diff --git a/Windows/codecs/x86-watcom/opusfile.lib b/Windows/codecs/x86-watcom/opusfile.lib
index c0c477557..5219e7277 100644
Binary files a/Windows/codecs/x86-watcom/opusfile.lib and b/Windows/codecs/x86-watcom/opusfile.lib differ
diff --git a/Windows/codecs/x86/libmpg123-0.dll b/Windows/codecs/x86/libmpg123-0.dll
index 81e6bd29b..49ddfecee 100644
Binary files a/Windows/codecs/x86/libmpg123-0.dll and b/Windows/codecs/x86/libmpg123-0.dll differ
diff --git a/Windows/codecs/x86/libopusfile-0.dll b/Windows/codecs/x86/libopusfile-0.dll
index 3cb063e0c..292cd5041 100644
Binary files a/Windows/codecs/x86/libopusfile-0.dll and b/Windows/codecs/x86/libopusfile-0.dll differ
diff --git a/Windows/codecs/x86/libxmp.dll b/Windows/codecs/x86/libxmp.dll
index aa30bb2e8..9d5cee7ad 100644
Binary files a/Windows/codecs/x86/libxmp.dll and b/Windows/codecs/x86/libxmp.dll differ