diff --git a/Build/Configurations/Includes/Common.cfg b/Build/Configurations/Includes/Common.cfg
index 981eefa4611a09ef13ffc45e0dd633d3de3d39e7..4f3877cc83e1494f1d870102e43908e5a87babd0 100644
--- a/Build/Configurations/Includes/Common.cfg
+++ b/Build/Configurations/Includes/Common.cfg
@@ -13,7 +13,7 @@ start3dmode = 32000;
 
 
 // Flat used as sky
-skyflatname = "F_SKY1";
+//skyflatname = "F_SKY1"; //mxd: moved to game_xxx sections of ZDoom_common.cfg because different games use different skyflatname
 
 // Map boundaries. Map objects can only be placed within these boundaries
 // WARNING: changing this may mess your map up, so only change it when you
diff --git a/Build/Configurations/Includes/ZDoom_common.cfg b/Build/Configurations/Includes/ZDoom_common.cfg
index 109e8c63695926c0a63ce7bdd31bdb8b86712611..1e3fb24b8047ad6d42090959866cfa2bbe66e3f1 100644
--- a/Build/Configurations/Includes/ZDoom_common.cfg
+++ b/Build/Configurations/Includes/ZDoom_common.cfg
@@ -365,6 +365,7 @@ game_doom
 {
 	// Default lump name for new map
 	defaultlumpname = "MAP01";
+	basegame = 0; //mxd: 0 - DOOM, 1 - HERETIC, 2 - HEXEN, 3 - STRIFE, 4 - UNKNOWN
 
 	// Decorate actors to include depending on actor game property
 	decorategames = "doom";
@@ -403,6 +404,7 @@ game_heretic
 {
 	// Default lump name for new map
 	defaultlumpname = "MAP01";
+	basegame = 1;
 
 	// Decorate actors to include depending on actor game property
 	decorategames = "heretic raven";
@@ -441,6 +443,8 @@ game_hexen
 {
 	// Default lump name for new map
 	defaultlumpname = "MAP01";
+	skyflatname = "F_SKY";
+	basegame = 2;
 
 	// Decorate actors to include depending on actor game property
 	decorategames = "hexen raven";
@@ -479,6 +483,8 @@ game_strife
 {
 	// Default lump name for new map
 	defaultlumpname = "MAP01";
+	skyflatname = "F_SKY001";
+	basegame = 3;
 
 	// Decorate actors to include depending on actor game property
 	decorategames = "strife";
diff --git a/Build/Gldefs/Readme.txt b/Build/Gldefs/Readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..85399d699f2a65168c67cc4b1856b49f59faaddb
--- /dev/null
+++ b/Build/Gldefs/Readme.txt
@@ -0,0 +1,2 @@
+This folder holds default GZDoom light definitions, taken from lights.pk3
+I've removed "Monsters" and "Weapons" sections from all of them to speed up parsing times.
\ No newline at end of file
diff --git a/Build/Gldefs/doomdefs.txt b/Build/Gldefs/doomdefs.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2bb6351de971362a71ee6ae323f5d9f1ddc5c241
--- /dev/null
+++ b/Build/Gldefs/doomdefs.txt
@@ -0,0 +1,410 @@
+// ----------------------
+// -- Doom Decorations --
+// ----------------------
+
+// Barrel
+pulselight BARREL
+{
+    color 0.0 0.5 0.0
+    size 20
+    secondarySize 21
+    interval 0.5
+    offset 0 36 0
+	dontlightself 1
+}
+
+object ExplosiveBarrel
+{
+    frame BAR1  { light BARREL    }
+
+    frame BEXPC { light ROCKET_X1 }
+    frame BEXPD { light ROCKET_X2 }
+    frame BEXPE { light ROCKET_X3 }
+}
+
+// Floor lamp
+pointlight LAMP
+{
+    color 1.0 1.0 0.8
+    size 56
+    offset 0 44 0
+}
+
+object Column
+{
+    frame COLU { light LAMP }
+}
+
+// Short tech lamp
+pulselight SMALLLAMP
+{
+    color 0.8 0.8 1.0
+    size 56
+    secondarySize 58
+    interval 0.4
+    offset 0 44 0
+}
+
+object TechLamp2
+{
+    frame TLP2 { light SMALLLAMP }
+}
+
+// Tall tech lamp
+pulselight BIGLAMP
+{
+    color 0.8 0.8 1.0
+    size 64
+    secondarySize 66
+    interval 0.4
+    offset 0 72 0
+}
+
+object TechLamp
+{
+    frame TLMP { light BIGLAMP }
+}
+
+// Tall red torch
+flickerlight2 BIGREDTORCH
+{
+    color 1.0 0.3 0.0
+    size 64
+    secondarySize 72
+    interval 0.1
+    offset 0 60 0
+}
+
+object RedTorch
+{
+    frame TRED { light BIGREDTORCH }
+}
+
+// Tall green torch
+flickerlight2 BIGGREENTORCH
+{
+    color 0.0 1.0 0.0
+    size 64
+    secondarySize 72
+    interval 0.1
+    offset 0 60 0
+}
+
+object GreenTorch
+{
+    frame TGRN { light BIGGREENTORCH }
+}
+
+// Tall blue torch
+flickerlight2 BIGBLUETORCH
+{
+    color 0.0 0.0 1.0
+    size 64
+    secondarySize 72
+    interval 0.1
+    offset 0 60 0
+}
+
+object BlueTorch
+{
+    frame TBLU { light BIGBLUETORCH }
+}
+
+// Small red torch
+flickerlight2 SMALLREDTORCH
+{
+    color 1.0 0.3 0.0
+    size 48
+    secondarySize 54
+    interval 0.1
+    offset 0 35 0
+}
+
+object ShortRedTorch
+{
+    frame SMRT { light SMALLREDTORCH }
+}
+
+// Small green torch
+flickerlight2 SMALLGREENTORCH
+{
+    color 0.0 1.0 0.0
+    size 48
+    secondarySize 54
+    interval 0.1
+    offset 0 35 0
+}
+
+object ShortGreenTorch
+{
+    frame SMGT { light SMALLGREENTORCH }
+}
+
+// Small blue torch
+flickerlight2 SMALLBLUETORCH
+{
+    color 0.0 0.0 1.0
+    size 48
+    secondarySize 54
+    interval 0.1
+    offset 0 35 0
+}
+
+object ShortBlueTorch
+{
+    frame SMBT { light SMALLBLUETORCH }
+}
+
+// Burning barrel
+flickerlight2 FIREBARREL
+{
+    color 1.0 0.9 0.0
+    size 48
+    secondarySize 54
+    interval 0.1
+    offset 0 32 0
+}
+
+object BurningBarrel
+{
+    frame FCAN { light FIREBARREL }
+}
+
+// Skulls w/candles
+flickerlight2 SKULLCANDLES
+{
+    color 1.0 1.0 0.0
+    size 32
+    secondarySize 34
+    interval 0.1
+    offset 0 24 0
+}
+
+object HeadCandles
+{
+    frame POL3 { light SKULLCANDLES }
+}
+
+// Candle
+pointlight CANDLE
+{
+    color 1.0 1.0 0.0
+    size 16
+    offset 0 16 0
+}
+
+object Candlestick
+{
+    frame CAND { light CANDLE }
+}
+
+// Candelabra
+pointlight CANDELABRA
+{
+    color 1.0 1.0 0.0
+    size 48
+    offset 0 52 0
+}
+
+object Candelabra
+{
+    frame CBRA { light CANDELABRA }
+}
+
+
+
+// ----------------
+// -- Doom Items --
+// ----------------
+
+// Soul Sphere
+pulselight SOULSPHERE
+{
+    color 0.0 0.0 1.0
+    size 40
+    secondarySize 42
+    interval 2.0
+    offset 0 16 0
+}
+
+object SoulSphere
+{
+    frame SOUL { light SOULSPHERE }
+}
+
+// Invulnerability Sphere
+pulselight INVULN
+{
+    color 0.0 1.0 0.0
+    size 40
+    secondarySize 42
+    interval 2.0
+    offset 0 16 0
+}
+
+object InvulnerabilitySphere
+{
+    frame PINV { light INVULN }
+}
+
+// Blur Sphere
+pointlight BLURSPHERE1
+{
+    color 1.0 0.0 0.0
+    size 40
+    offset 0 16 0
+}
+
+pointlight BLURSPHERE2
+{
+    color 0.0 0.0 1.0
+    size 32
+    offset 0 16 0
+}
+
+pointlight BLURSPHERE3
+{
+    color 0.0 0.0 1.0
+    size 24
+    offset 0 16 0
+}
+
+pointlight BLURSPHERE4
+{
+    color 0.0 0.0 1.0
+    size 16
+    offset 0 16 0
+}
+
+pointlight BLURSPHERE5
+{
+    color 0.0 0.0 1.0
+    size 8
+    offset 0 16 0
+}
+
+object BlurSphere
+{
+    frame PINS { light BLURSPHERE1 }
+
+    frame PINSA { light BLURSPHERE2 }
+    frame PINSB { light BLURSPHERE3 }
+    frame PINSC { light BLURSPHERE4 }
+    frame PINSD { light BLURSPHERE5 }
+}
+
+// Health Potion
+pulselight HEALTHPOTION
+{
+    color 0.0 0.0 0.6
+    size 16
+    secondarySize 18
+    interval 2.0
+}
+
+object HealthBonus
+{
+    frame BON1 { light HEALTHPOTION }
+}
+
+// Armour Helmet
+pulselight ARMORBONUS
+{
+    color 0.0 0.6 0.0
+    size 16
+    secondarySize 14
+    interval 1.0
+	dontlightself 1
+}
+
+object ArmorBonus
+{
+    frame BON2 { light ARMORBONUS }
+}
+
+// Blue Keys
+object BlueCard
+{
+    frame BKEY { light HEALTHPOTION }
+}
+
+object BlueSkull
+{
+    frame BSKU { light HEALTHPOTION }
+}
+
+// Yellow Keys
+pulselight YELLOWKEY
+{
+    color 0.6 0.6 0.0
+    size 16
+    secondarySize 18
+    interval 2.0
+}
+
+object YellowCard
+{
+    frame YKEY { light YELLOWKEY }
+}
+
+object YellowSkull
+{
+    frame YSKU { light YELLOWKEY }
+}
+
+// Red Keys
+pulselight REDKEY
+{
+    color 0.6 0.0 0.0
+    size 16
+    secondarySize 18
+    interval 2.0
+}
+
+object RedCard
+{
+    frame RKEY { light REDKEY }
+}
+
+object RedSkull
+{
+    frame RSKU { light REDKEY }
+}
+
+// Green armour
+pointlight GREENARMOR1
+{
+    color 0.0 0.6 0.0
+    size 48
+}
+
+pointlight GREENARMOR2
+{
+    color 0.0 0.6 0.0
+    size 32
+}
+
+object GreenArmor
+{
+    frame ARM1A { light GREENARMOR1 }
+    frame ARM1B { light GREENARMOR2 }
+}
+
+// Blue armour
+pointlight BLUEARMOR1
+{
+    color 0.0 0.0 0.6
+    size 48
+}
+
+pointlight BLUEARMOR2
+{
+    color 0.0 0.0 0.6
+    size 32
+}
+
+object BlueArmor
+{
+    frame ARM2A { light BLUEARMOR1 }
+    frame ARM2B { light BLUEARMOR2 }
+}
\ No newline at end of file
diff --git a/Build/Gldefs/hexndefs.txt b/Build/Gldefs/hexndefs.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c8f433d58d047296f882085c4cfc606dcec0eebf
--- /dev/null
+++ b/Build/Gldefs/hexndefs.txt
@@ -0,0 +1,444 @@
+// -----------------------
+// -- Hexen Decorations --
+// -----------------------
+
+// Candles
+flickerlight2 HCANDLES
+{
+    color 1.0 1.0 0.0
+    size 16
+    secondarySize 20
+    interval 0.1
+}
+
+object ZCandle
+{
+    frame CNDL { light HCANDLES }
+}
+
+// Twined torch
+flickerlight2 TWINETORCH
+{
+    color 1.0 0.7 0.0
+    size 46
+    secondarySize 52
+    interval 0.1
+    offset 0 64 0
+}
+
+object ZTwinedTorch
+{
+    frame TWTRA { light TWINETORCH }
+    frame TWTRB { light TWINETORCH }
+    frame TWTRC { light TWINETORCH }
+    frame TWTRD { light TWINETORCH }
+    frame TWTRE { light TWINETORCH }
+    frame TWTRF { light TWINETORCH }
+    frame TWTRG { light TWINETORCH }
+    frame TWTRH { light TWINETORCH }
+}
+
+object ZTwinedTorchUnlit
+{
+    frame TWTRA { light TWINETORCH }
+    frame TWTRB { light TWINETORCH }
+    frame TWTRC { light TWINETORCH }
+    frame TWTRD { light TWINETORCH }
+    frame TWTRE { light TWINETORCH }
+    frame TWTRF { light TWINETORCH }
+    frame TWTRG { light TWINETORCH }
+    frame TWTRH { light TWINETORCH }
+}
+
+
+// Wall torch
+flickerlight2 WALLTORCH2
+{
+    color 1.0 0.7 0.0
+    size 24
+    secondarySize 28
+    interval 0.1
+    offset 0 24 0
+}
+
+object ZWallTorch
+{
+    frame WLTRA { light WALLTORCH2 }
+    frame WLTRB { light WALLTORCH2 }
+    frame WLTRC { light WALLTORCH2 }
+    frame WLTRD { light WALLTORCH2 }
+    frame WLTRE { light WALLTORCH2 }
+    frame WLTRF { light WALLTORCH2 }
+    frame WLTRG { light WALLTORCH2 }
+    frame WLTRH { light WALLTORCH2 }
+}
+
+
+object ZWallTorchUnlit
+{
+    frame WLTRA { light WALLTORCH2 }
+    frame WLTRB { light WALLTORCH2 }
+    frame WLTRC { light WALLTORCH2 }
+    frame WLTRD { light WALLTORCH2 }
+    frame WLTRE { light WALLTORCH2 }
+    frame WLTRF { light WALLTORCH2 }
+    frame WLTRG { light WALLTORCH2 }
+    frame WLTRH { light WALLTORCH2 }
+}
+
+
+// Fire bull
+flickerlight2 FIREBULL
+{
+    color 1.0 0.7 0.0
+    size 64
+    secondarySize 70
+    interval 0.1
+    offset 0 40 0
+}
+
+object ZFireBull
+{
+    frame FBULA { light FIREBULL }
+    frame FBULB { light FIREBULL }
+    frame FBULC { light FIREBULL }
+    frame FBULD { light FIREBULL }
+    frame FBULE { light FIREBULL }
+    frame FBULF { light FIREBULL }
+    frame FBULG { light FIREBULL }
+    frame FBULH { light FIREBULL }
+}
+
+object ZFireBullUnlit
+{
+    frame FBULA { light FIREBULL }
+    frame FBULB { light FIREBULL }
+    frame FBULC { light FIREBULL }
+    frame FBULD { light FIREBULL }
+    frame FBULE { light FIREBULL }
+    frame FBULF { light FIREBULL }
+    frame FBULG { light FIREBULL }
+    frame FBULH { light FIREBULL }
+}
+
+
+// Cauldron
+flickerlight2 CAULFLAME
+{
+    color 1.0 0.9 0.0
+    size 24
+    secondarySize 26
+    interval 0.1
+}
+
+object ZCauldron
+{
+    frame CDRNB { light CAULFLAME }
+    frame CDRNC { light CAULFLAME }
+    frame CDRND { light CAULFLAME }
+    frame CDRNE { light CAULFLAME }
+    frame CDRNF { light CAULFLAME }
+    frame CDRNG { light CAULFLAME }
+    frame CDRNH { light CAULFLAME }
+}
+
+object ZCauldronUnlit
+{
+    frame CDRNB { light CAULFLAME }
+    frame CDRNC { light CAULFLAME }
+    frame CDRND { light CAULFLAME }
+    frame CDRNE { light CAULFLAME }
+    frame CDRNF { light CAULFLAME }
+    frame CDRNG { light CAULFLAME }
+    frame CDRNH { light CAULFLAME }
+}
+
+// Blue candle
+flickerlight2 BCANDLE
+{
+    color 0.3 0.3 1.0
+    size 14
+    secondarySize 16
+    interval 0.1
+}
+
+object ZBlueCandle
+{
+    frame CAND { light BCANDLE }
+}
+
+// Small flame
+object FlameSmall
+{
+    frame FFSM { light HCANDLES }
+}
+
+object FlameSmallTemp
+{
+    frame FFSM { light HCANDLES }
+}
+
+// Large flame
+flickerlight2 LARGEFLAME
+{
+    color 1.0 0.7 0.0
+    size 40
+    secondarySize 48
+    interval 0.1
+}
+
+object FlameLarge
+{
+    frame FFLG { light LARGEFLAME }
+}
+
+object FlameLargeTemp
+{
+    frame FFLG { light LARGEFLAME }
+}
+
+// Chandelier
+flickerlight2 CHANDELIER
+{
+    color 1.0 1.0 0.0
+    size 64
+    secondarySize 68
+    interval 0.1
+}
+
+object ZChandelier
+{
+    frame CDLR { light CHANDELIER }
+}
+
+// Brass torch
+flickerlight2 BRASSTORCH
+{
+    color 1.0 0.7 0.0
+    size 40
+    secondarySize 48
+    interval 0.1
+    offset 0 32 0
+}
+
+object BrassTorch
+{
+    frame BRTR { light BRASSTORCH }
+}
+
+// Skull flame
+object FireThing
+{
+    frame FSKL { light BRASSTORCH }
+}
+
+// Teleport smoke
+flickerlight2 TELESMOKE
+{
+    color 1.0 0.0 0.0
+    size 64
+    secondarySize 72
+    interval 0.1
+    offset 0 44 0
+}
+
+object TeleSmoke
+{
+    frame TSMK { light TELESMOKE }
+}
+
+// Fireball
+pointlight HFIREBALL
+{
+    color 1.0 0.4 0.0
+    size 48
+}
+
+object FireBall
+{
+    frame FBL1A { light HFIREBALL }
+    frame FBL1B { light HFIREBALL }
+}
+
+// -----------------
+// -- Hexen Items --
+// -----------------
+
+// Blue mana
+pointlight MANA1
+{
+    color 0.0 0.0 0.7
+    size 24
+    offset 0 36 0
+}
+
+object Mana1
+{
+    frame MAN1 { light MANA1 }
+}
+
+// Green mana
+pointlight MANA2
+{
+    color 0.0 0.6 0.0
+    size 24
+    offset 0 36 0
+}
+
+object Mana2
+{
+    frame MAN2 { light MANA2 }
+}
+
+// Combined mana
+pointlight MANA3
+{
+    color 0.7 0.0 0.0
+    size 24
+    offset 0 36 0
+}
+
+object Mana3
+{
+    frame MAN3 { light MANA3 }
+}
+
+// ZXmasTree
+flickerlight2 XMASFIRE1
+{
+    color 1.0 0.7 0.0
+    size 16
+    secondarySize 24
+    interval 0.1
+    offset 0 48 0
+}
+
+
+flickerlight2 XMASFIRE2
+{
+    color 1.0 0.8 0.0
+    size 32
+    secondarySize 48
+    interval 0.1
+    offset 0 48 0
+}
+
+
+flickerlight2 XMASFIRE3
+{
+    color 1.0 0.9 0.0
+    size 48
+    secondarySize 64
+    interval 0.1
+    offset 0 32 0
+}
+
+
+flickerlight2 XMASFIRE4
+{
+    color 1.0 0.8 0.0
+    size 32
+    secondarySize 40
+    interval 0.1
+    offset 0 120 0
+}
+
+
+flickerlight2 XMASFIRE5
+{
+    color 1.0 0.7 0.0
+    size 12
+    secondarySize 20
+    interval 0.1
+    offset 0 140 0
+}
+
+
+flickerlight2 XMASFIRE6
+{
+    color 1.0 0.8 0.0
+    size 10
+    secondarySize 14
+    interval 0.1
+    offset 0 148 0
+}
+
+
+object ZXmasTree
+{
+    frame XMASB { light XMASFIRE1 }
+    frame XMASC { light XMASFIRE2 }
+    frame XMASD { light XMASFIRE3 }
+    frame XMASE { light XMASFIRE3 }
+    frame XMASF { light XMASFIRE4 }
+    frame XMASG { light XMASFIRE5 }
+    frame XMASH { light XMASFIRE6 }
+}
+
+
+
+
+// TreeDestructible
+flickerlight2 TDESTRUCT1
+{
+    color 1.0 0.8 0.0
+    size 48
+    secondarySize 56
+    interval 0.1
+    offset 0 32 0
+}
+
+
+flickerlight2 TDESTRUCT2
+{
+    color 1.0 0.9 0.0
+    size 56
+    secondarySize 72
+    interval 0.1
+    offset 0 32 0
+}
+
+
+flickerlight2 TDESTRUCT3
+{
+    color 1.0 0.8 0.0
+    size 40
+    secondarySize 48
+    interval 0.1
+    offset 0 20 0
+}
+
+
+flickerlight2 TDESTRUCT4
+{
+    color 1.0 0.7 0.0
+    size 16
+    secondarySize 24
+    interval 0.1
+    offset 0 12 0
+}
+
+flickerlight2 TDESTRUCT5
+{
+    color 1.0 0.7 0.0
+    size 8
+    secondarySize 12
+    interval 0.1
+    offset 0 4 0
+}
+
+
+
+
+object TreeDestructible
+{
+    frame TRDTH { light TDESTRUCT1 }
+    frame TRDTI { light TDESTRUCT2 }
+    frame TRDTJ { light TDESTRUCT2 }
+    frame TRDTK { light TDESTRUCT2 }
+    frame TRDTL { light TDESTRUCT2 }
+    frame TRDTM { light TDESTRUCT3 }
+    frame TRDTN { light TDESTRUCT4 }
+    frame TRDTO { light TDESTRUCT4 }
+    frame TRDTP { light TDESTRUCT5 }
+}
diff --git a/Build/Gldefs/hticdefs.txt b/Build/Gldefs/hticdefs.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c883a8ceaf1ba92a61283b3ef1140300c9d1955c
--- /dev/null
+++ b/Build/Gldefs/hticdefs.txt
@@ -0,0 +1,405 @@
+// -------------------------
+// -- Heretic Decorations --
+// -------------------------
+
+// Wall Torch
+flickerlight2 WALLTORCH
+{
+    color 1.0 0.8 0.0
+    size 32
+    secondarySize 36
+    interval 0.1
+    offset 0 70 0
+}
+
+object WallTorch
+{
+    frame WTRH { light WALLTORCH }
+}
+
+// Fire Brazier
+flickerlight2 FIREBRAZ
+{
+    color 1.0 0.8 0.0
+    size 68
+    secondarySize 76
+    interval 0.1
+    offset 0 48 0
+}
+
+object FireBrazier
+{
+    frame KFR1 { light FIREBRAZ }
+}
+
+// Serpent torch
+flickerlight2 SERPTORCH
+{
+    color 1.0 0.8 0.0
+    size 48
+    secondarySize 56
+    interval 0.1
+    offset 0 48 0
+}
+
+object SerpentTorch
+{
+    frame SRTC { light SERPTORCH }
+}
+
+// Chandelier
+flickerlight2 CHANDELIER
+{
+    color 1.0 1.0 0.0
+    size 64
+    secondarySize 68
+    interval 0.1
+}
+
+object Chandelier
+{
+    frame CHDL { light CHANDELIER }
+}
+
+// Pod
+flickerlight POD_X1
+{
+    color 0.0 1.0 0.0
+    size 48
+    secondarySize 56
+    chance 0.3
+}
+
+flickerlight POD_X2
+{
+    color 0.0 0.7 0.0
+    size 64
+    secondarySize 72
+    chance 0.3
+}
+
+flickerlight POD_X3
+{
+    color 0.0 0.4 0.0
+    size 72
+    secondarySize 80
+    chance 0.3
+}
+
+flickerlight POD_X4
+{
+    color 0.0 0.2 0.0
+    size 80
+    secondarySize 88
+    chance 0.3
+}
+
+object Pod
+{
+    frame PPODC { light POD_X1 }
+    frame PPODD { light POD_X2 }
+    frame PPODE { light POD_X3 }
+    frame PPODF { light POD_X4 }
+}
+
+// Big volcano fireball
+flickerlight VOLCANOBALL1
+{
+    color 1.0 0.5 0.0
+    size 56
+    secondarySize 64
+    chance 0.5
+}
+
+object VolcanoBlast
+{
+    frame VFBL { light VOLCANOBALL1 }
+}
+
+// Small volcano fireball
+flickerlight VOLCANOBALL1
+{
+    color 1.0 0.5 0.0
+    size 40
+    secondarySize 48
+    chance 0.5
+}
+
+object VolcanoTBlast
+{
+    frame VTFB { light VOLCANOBALL1 }
+}
+
+// Blue Key Statue
+pointlight BLUESTATUE
+{
+    color 0.0 0.0 1.0
+    size 32
+    offset 0 64 0
+}
+
+object KeyGizmoBlue
+{
+    frame KGZ1 { light BLUESTATUE }
+}
+
+// Yellow Key Statue
+pointlight YELLOWSTATUE
+{
+    color 1.0 1.0 0.0
+    size 32
+    offset 0 64 0
+}
+
+object KeyGizmoYellow
+{
+    frame KGZ1 { light YELLOWSTATUE }
+}
+
+// Green Key Statue
+pointlight GREENSTATUE
+{
+    color 0.0 1.0 0.0
+    size 32
+    offset 0 64 0
+}
+
+object KeyGizmoGreen
+{
+    frame KGZ1 { light GREENSTATUE }
+}
+
+// -------------------
+// -- Heretic Items --
+// -------------------
+
+// Time bomb explosion
+flickerlight TIMEBOMB_X1
+{
+    color 1.0 0.6 0.0
+    size 48
+    secondarySize 56
+    chance 0.3
+}
+
+flickerlight TIMEBOMB_X1
+{
+    color 0.8 0.4 0.0
+    size 56
+    secondarySize 64
+    chance 0.3
+}
+
+flickerlight TIMEBOMB_X1
+{
+    color 0.6 0.2 0.0
+    size 64
+    secondarySize 72
+    chance 0.3
+}
+
+flickerlight TIMEBOMB_X1
+{
+    color 0.4 0.0 0.0
+    size 72
+    secondarySize 80
+    chance 0.3
+}
+
+flickerlight TIMEBOMB_X1
+{
+    color 0.2 0.0 0.0
+    size 80
+    secondarySize 88
+    chance 0.3
+}
+
+object ActivatedTimeBomb
+{
+    frame XPL1A { light TIMEBOMB_X1 }
+    frame XPL1B { light TIMEBOMB_X2 }
+    frame XPL1C { light TIMEBOMB_X3 }
+    frame XPL1D { light TIMEBOMB_X4 }
+    frame XPL1E { light TIMEBOMB_X5 }
+    frame XPL1F { light TIMEBOMB_X5 }
+}
+
+// Small wand ammo
+pointlight SWANDAMMO
+{
+    color 1.0 1.0 0.0
+    size 8
+}
+
+object GoldWandAmmo
+{
+    frame AMG1 { light SWANDAMMO }
+}
+
+// Large wand ammo
+pulselight LWANDAMMO
+{
+    color 1.0 1.0 0.0
+    size 16
+    secondarySize 18
+    interval 2.0
+}
+
+object GoldWandHefty
+{
+    frame AMG2 { light LWANDAMMO }
+}
+
+// Ethereal arrows
+pointlight ETHARROWS
+{
+    color 0.0 1.0 0.0
+    size 12
+    offset 0 8 0
+}
+
+object CrossbowAmmo
+{
+    frame AMC1 { light ETHARROWS }
+}
+
+// Quiver of ethereal arrows
+pulselight ETHQUIVER
+{
+    color 0.0 1.0 0.0
+    size 16
+    secondarySize 18
+    interval 2.0
+    offset 0 16 0
+}
+
+object CrossbowHefty
+{
+    frame AMC2 { light ETHQUIVER }
+}
+
+// Small claw ammo
+pulselight SCLAWAMMO
+{
+    color 0.0 0.0 1.0
+    size 8
+    secondarySize 10
+    interval 2.0
+}
+
+object BlasterAmmo
+{
+    frame AMB1 { light SCLAWAMMO }
+}
+
+// Large claw ammo
+pulselight LCLAWAMMO
+{
+    color 0.0 0.0 1.0
+    size 16
+    secondarySize 18
+    interval 2.0
+    offset 0 6 0
+}
+
+object BlasterHefty
+{
+    frame AMB2 { light LCLAWAMMO }
+}
+
+// Small hellstaff ammo
+pulselight SSTAFFAMMO
+{
+    color 1.0 0.0 0.0
+    size 8
+    secondarySize 10
+    interval 2.0
+}
+
+object SkullRodAmmo
+{
+    frame AMS1 { light SSTAFFAMMO }
+}
+
+// Large hellstaff ammo
+pulselight LSTAFFAMMO
+{
+    color 1.0 0.0 0.0
+    size 16
+    secondarySize 18
+    interval 2.0
+}
+
+object SkullRodHefty
+{
+    frame AMS2 { light LSTAFFAMMO }
+}
+
+// Small phoenix rod ammo
+pulselight SRODAMMO
+{
+    color 1.0 0.6 0.0
+    size 8
+    secondarySize 10
+    interval 2.0
+}
+
+object PhoenixRodAmmo
+{
+    frame AMP1 { light SRODAMMO }
+}
+
+// Large phoenix rod ammo
+pulselight LRODAMMO
+{
+    color 1.0 0.6 0.0
+    size 16
+    secondarySize 18
+    interval 2.0
+}
+
+object PhoenixRodHefty
+{
+    frame AMP2 { light LRODAMMO }
+}
+
+// Yellow Key
+pulselight HYELLOWKEY
+{
+    color 1.0 1.0 0.0
+    size 24
+    secondarySize 26
+    interval 2.0
+}
+object KeyYellow
+{
+    frame CKYY { light HYELLOWKEY }
+}
+
+// Blue Key
+pulselight HBLUEKEY
+{
+    color 0.0 0.0 1.0
+    size 24
+    secondarySize 26
+    interval 2.0
+}
+
+object KeyBlue
+{
+    frame BKYY { light HBLUEKEY }
+}
+
+// Green Key
+pulselight HGREENKEY
+{
+    color 0.0 1.0 0.0
+    size 24
+    secondarySize 26
+    interval 2.0
+}
+
+object KeyGreen
+{
+    frame AKYY { light HGREENKEY }
+}
\ No newline at end of file
diff --git a/Build/Gldefs/strfdefs.txt b/Build/Gldefs/strfdefs.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a779fdea9f9bfa26eba304b00c4ec998c174d2d6
--- /dev/null
+++ b/Build/Gldefs/strfdefs.txt
@@ -0,0 +1,862 @@
+// ------------------
+// -- Strife Items --
+// ------------------
+
+// Degnin Ore
+flickerlight DEGORE_X1
+{
+    color 1.0 0.6 0.0
+    size 32
+    secondarySize 40
+    chance 0.3
+}
+
+flickerlight DEGORE_X2
+{
+    color 1.0 0.8 0.0
+    size 40
+    secondarySize 48
+    chance 0.3
+}
+
+flickerlight DEGORE_X3
+{
+    color 1.0 0.8 0.0
+    size 44
+    secondarySize 52
+    chance 0.3
+}
+
+flickerlight DEGORE_X4
+{
+    color 1.0 0.75 0.0
+    size 48
+    secondarySize 56
+    chance 0.3
+}
+
+flickerlight DEGORE_X5
+{
+    color 1.0 0.7 0.0
+    size 52
+    secondarySize 60
+    chance 0.3
+}
+
+flickerlight DEGORE_X6
+{
+    color 1.0 0.5 0.0
+    size 56
+    secondarySize 64
+    chance 0.3
+}
+
+flickerlight DEGORE_X7
+{
+    color 0.5 0.125 0.0
+    size 60
+    secondarySize 68
+    chance 0.3
+}
+
+flickerlight DEGORE_X8
+{
+    color 0.25 0.05 0.0
+    size 64
+    secondarySize 72
+    chance 0.3
+}
+
+object DegninOre
+{
+    frame BNG3A { light DEGORE_X1 }
+    frame BNG3B { light DEGORE_X2 }
+    frame BNG3C { light DEGORE_X3 }
+    frame BNG3D { light DEGORE_X4 }
+    frame BNG3E { light DEGORE_X5 }
+    frame BNG3F { light DEGORE_X6 }
+    frame BNG3G { light DEGORE_X7 }
+    frame BNG3H { light DEGORE_X8 }
+}
+
+// Power Coupling
+pointlight POWCOUP1
+{
+    color 0.5 0.5 1.0
+    size 24
+}
+
+pointlight POWCOUP2
+{
+    color 0.7 0.7 1.0
+    size 32
+}
+
+object PowerCoupling
+{
+    frame COUPA { light POWCOUP1 }
+    frame COUPB { light POWCOUP2 }
+}
+
+// Energy Ammo
+pointlight ENERGY1
+{
+    color 0.4 1.0 0.4
+    size 16
+}
+
+pointlight ENERGY2
+{
+    color 0.4 1.0 0.4
+    size 32
+}
+
+object EnergyPod
+{
+    frame BRY1B { light ENERGY1 }
+}
+
+object EnergyPack
+{
+    frame CPACB { light ENERGY2 }
+}
+
+// ------------------
+// - Strife Objects -
+// ------------------
+
+// Lights
+pointlight LIGHT1
+{
+    color 1.0 1.0 1.0
+    size 56
+    offset 0 30 0
+}
+
+pointlight LIGHT2
+{
+    color 1.0 1.0 1.0
+    size 40
+    offset 0 72 0
+}
+
+pointlight LIGHT3
+{
+    color 1.0 1.0 1.0
+    size 64
+}
+
+pointlight LIGHT4
+{
+    color 1.0 1.0 1.0
+    size 64
+    offset 0 80 0
+}
+
+pointlight LIGHT5
+{
+    color 1.0 1.0 1.0
+    size 56
+    offset 0 72 0
+}
+
+pointlight CLIGHT1
+{
+    color 1.0 1.0 0.0
+    size 24
+    offset 0 12 0
+}
+
+pulselight CLIGHT2
+{
+    color 1.0 1.0 0.0
+    size 48
+    secondarySize 50
+    interval 8.0    
+    offset 0 64 0
+}
+
+pulselight LLIGHT
+{
+    color 1.0 0.5 0.0
+    size 24
+    secondarySize 32
+    interval 12.0    
+    offset 0 76 0
+}
+
+pulselight TLLIGHT1
+{
+    color 0.9 0.9 1.0
+    size 56
+    secondarySize 64
+    interval 3.0    
+    offset 0 48 0
+}
+
+pointlight TLLIGHT2
+{
+    color 1.0 1.0 0.5
+    size 80
+    offset 0 56 0
+}
+
+flickerlight HTECH
+{
+    color 0.3 1.0 0.3
+    size 96
+    secondarySize 104
+    chance 0.5
+    offset 0 80 0
+}
+
+pulselight BCOLUMN
+{
+    color 0.5 1.0 0.5
+    size 120
+    secondarySize 128
+    interval 10.0    
+    offset 0 64 0
+}
+
+pulselight FBUBBLE
+{
+    color 0.5 1.0 0.5
+    size 60
+    secondarySize 64
+    interval 10.0    
+    offset 0 32 0
+}
+
+pulselight CBUBBLE
+{
+    color 0.5 1.0 0.5
+    size 60
+    secondarySize 64
+    interval 10.0
+}
+
+pointlight SPIDLGHT1
+{
+    color 0.5 1.0 0.5
+    size 64
+    offset 0 10 0
+}
+
+pointlight SPIDLGHT2
+{
+    color 0.2 0.75 0.2
+    size 56
+    offset 0 10 0
+}
+
+pointlight SPIDLGHT3
+{
+    color 0.0 0.25 0.0
+    size 48
+    offset 0 10 0
+}
+
+object LightSilverFluorescent 
+{
+    frame LITS { light LIGHT1 }
+}
+
+object LightBrownFluorescent 
+{
+    frame LITB { light LIGHT1 }
+}
+
+object LightGoldFluorescent 
+{
+    frame LITG { light LIGHT1 }
+}
+
+object LightGlobe
+{
+    frame LITE { light LIGHT5 }
+}
+
+object PillarHugeTech
+{
+    frame HUGE { light HTECH }
+}
+
+object Candle
+{
+    frame KNDL { light CLIGHT1 }
+}
+
+object StrifeCandelabra
+{
+    frame CLBR { light CLIGHT2 }
+}
+
+object CageLight
+{
+    frame CAGE { light LIGHT3 }
+}
+
+object OutsideLamp
+{
+    frame LAMP { light LIGHT4 }
+}
+
+object PoleLantern
+{
+    frame LANT { light LLIGHT }
+}
+
+object TechLampSilver
+{
+    frame TECHA { light TLLIGHT1 }
+}
+
+object TechLampBrass
+{
+    frame TECHB { light TLLIGHT2 }
+}
+
+object AlienBubbleColumn
+{
+    frame BUBB { light BCOLUMN }
+}
+
+object AlienFloorBubble
+{
+    frame BUBF { light FBUBBLE }
+}
+
+object AlienCeilingBubble
+{
+    frame BUBC { light CBUBBLE }
+}
+
+object AlienSpiderLight
+{
+    frame SPDLA { light SPIDLGHT1 }
+    frame SPDLB { light SPIDLGHT2 }
+    frame SPDLC { light SPIDLGHT3 }
+}
+
+// Burning Things
+flickerlight BBARREL
+{
+    color 1.0 0.6 0.0
+    size 32
+    secondarySize 40
+    chance 0.8
+    offset 0 32 0
+}
+
+flickerlight BBOWL
+{
+    color 1.0 0.7 0.0
+    size 24
+    secondarySize 32
+    chance 0.5
+    offset 0 10 0
+}
+
+flickerlight BBRAZIER
+{
+    color 1.0 0.8 0.0
+    size 40
+    secondarySize 48
+    chance 0.2
+    offset 0 32 0
+}
+
+pulselight STORCH
+{
+    color 1.0 0.6 0.0
+    size 28
+    secondarySize 32
+    interval 5.0    
+    offset 0 56 0
+}
+
+pulselight MTORCH
+{
+    color 1.0 0.6 0.0
+    size 56
+    secondarySize 64
+    interval 5.0    
+    offset 0 64 0
+}
+
+pulselight LTORCH
+{
+    color 1.0 0.8 0.0
+    size 64
+    secondarySize 72
+    interval 2.0    
+    offset 0 64 0
+}
+
+pulselight HTORCH
+{
+    color 1.0 0.6 0.0
+    size 72
+    secondarySize 76
+    interval 3.0    
+    offset 0 72 0
+}
+
+object StrifeBurningBarrel 
+{
+    frame BBAR { light BBARREL }
+}
+
+object BurningBowl
+{
+    frame BOWL { light BBOWL }
+}
+
+object BurningBrazier
+{
+    frame BRAZ { light BBRAZIER }
+}
+
+object SmallTorchLit
+{
+    frame TRHL { light STORCH }
+}
+
+object MediumTorch
+{
+    frame LTRH { light MTORCH }
+}
+
+object LargeTorch
+{
+    frame LMPC { light LTORCH }
+}
+
+object HugeTorch
+{
+    frame LOGS { light HTORCH }
+}
+
+// Power Crystal
+pointlight PCRYSTAL
+{
+    color 1.0 1.0 0.0
+    size 40
+    offset 0 16 0
+}
+
+pointlight PCRYSTAL1
+{
+    color 0.4 0.4 1.0
+    size 24
+    offset 0 12 0
+}
+
+pointlight PCRYSTAL2
+{
+    color 0.5 0.5 1.0
+    size 30
+    offset 0 18 0
+}
+
+pointlight PCRYSTAL3
+{
+    color 0.45 0.45 1.0
+    size 32
+    offset 0 24 0
+}
+
+pointlight PCRYSTAL4
+{
+    color 0.35 0.35 1.0
+    size 28
+    offset 0 32 0
+}
+
+pointlight PCRYSTAL5
+{
+    color 0.1 0.1 1.0
+    size 18
+    offset 0 40 0
+}
+
+flickerlight POWCRYS_X1
+{
+    color 1.0 0.7 0.1
+    size 108
+    secondarySize 112
+    chance 0.3
+}
+
+flickerlight POWCRYS_X2
+{
+    color 1.0 0.75 0.2
+    size 112
+    secondarySize 116
+    chance 0.3
+}
+
+flickerlight POWCRYS_X3
+{
+    color 1.0 0.8 0.4
+    size 116
+    secondarySize 120
+    chance 0.3
+}
+
+flickerlight POWCRYS_X4
+{
+    color 1.0 0.75 0.3
+    size 115
+    secondarySize 117
+    chance 0.3
+}
+
+flickerlight POWCRYS_X5
+{
+    color 1.0 0.7 0.27
+    size 114
+    secondarySize 113
+    chance 0.3
+}
+
+flickerlight POWCRYS_X6
+{
+    color 1.0 0.65 0.24
+    size 113
+    secondarySize 115
+    chance 0.3
+}
+
+flickerlight POWCRYS_X6
+{
+    color 1.0 0.62 0.22
+    size 112
+    secondarySize 114
+    chance 0.3
+}
+
+flickerlight POWCRYS_X7
+{
+    color 1.0 0.6 0.20
+    size 111
+    secondarySize 113
+    chance 0.3
+}
+
+flickerlight POWCRYS_X8
+{
+    color 1.0 0.58 0.18
+    size 110
+    secondarySize 112
+    chance 0.3
+}
+
+flickerlight POWCRYS_X9
+{
+    color 1.0 0.56 0.16
+    size 109
+    secondarySize 111
+    chance 0.3
+}
+
+flickerlight POWCRYS_X10
+{
+    color 1.0 0.54 0.14
+    size 108
+    secondarySize 110
+    chance 0.3
+}
+
+flickerlight POWCRYS_X11
+{
+    color 1.0 0.52 0.12
+    size 107
+    secondarySize 109
+    chance 0.3
+}
+
+flickerlight POWCRYS_X12
+{
+    color 1.0 0.5 0.10
+    size 106
+    secondarySize 108
+    chance 0.3
+}
+
+flickerlight POWCRYS_X13
+{
+    color 1.0 0.48 0.10
+    size 105
+    secondarySize 106
+    chance 0.3
+}
+
+flickerlight POWCRYS_X14
+{
+    color 1.0 0.46 0.08
+    size 103
+    secondarySize 104
+    chance 0.3
+}
+
+flickerlight POWCRYS_X15
+{
+    color 1.0 0.44 0.06
+    size 102
+    secondarySize 104
+    chance 0.3
+}
+
+flickerlight POWCRYS_X16
+{
+    color 1.0 0.42 0.04
+    size 101
+    secondarySize 103
+    chance 0.3
+}
+
+flickerlight POWCRYS_X15
+{
+    color 1.0 0.4 0.02
+    size 100
+    secondarySize 102
+    chance 0.3
+}
+
+flickerlight POWCRYS_X16
+{
+    color 1.0 0.38 0.0
+    size 99
+    secondarySize 101
+    chance 0.3
+}
+
+flickerlight POWCRYS_X17
+{
+    color 1.0 0.36 0.02
+    size 98
+    secondarySize 100
+    chance 0.3
+}
+
+flickerlight POWCRYS_X18
+{
+    color 1.0 0.34 0.0
+    size 97
+    secondarySize 100
+    chance 0.3
+}
+
+flickerlight POWCRYS_X19
+{
+    color 1.0 0.32 0.0
+    size 96
+    secondarySize 99
+    chance 0.3
+}
+
+flickerlight POWCRYS_X20
+{
+    color 1.0 0.3 0.0
+    size 95
+    secondarySize 98
+    chance 0.3
+}
+
+flickerlight POWCRYS_X21
+{
+    color 1.0 0.28 0.0
+    size 94
+    secondarySize 93
+    chance 0.3
+}
+
+flickerlight POWCRYS_X22
+{
+    color 1.0 0.26 0.0
+    size 93
+    secondarySize 92
+    chance 0.3
+}
+
+flickerlight POWCRYS_X23
+{
+    color 1.0 0.24 0.0
+    size 92
+    secondarySize 91
+    chance 0.3
+}
+
+flickerlight POWCRYS_X24
+{
+    color 1.0 0.22 0.0
+    size 90
+    secondarySize 92
+    chance 0.3
+}
+
+flickerlight POWCRYS_X25
+{
+    color 1.0 0.2 0.0
+    size 86
+    secondarySize 90
+    chance 0.3
+}
+
+object PowerCrystal
+{
+    frame CRYS  { light PCRYSTAL    }
+
+    frame CRYSB { light PCRYSTAL1   }
+    frame CRYSC { light PCRYSTAL2   }
+    frame CRYSD { light PCRYSTAL3   }
+    frame CRYSE { light PCRYSTAL4   }
+    frame CRYSF { light PCRYSTAL5   }
+
+    frame BOOMA { light POWCRYS_X1  }
+    frame BOOMB { light POWCRYS_X2  }
+    frame BOOMC { light POWCRYS_X3  }
+    frame BOOMD { light POWCRYS_X4  }
+    frame BOOME { light POWCRYS_X5  }
+    frame BOOMF { light POWCRYS_X6  }
+    frame BOOMG { light POWCRYS_X7  }
+    frame BOOMH { light POWCRYS_X8  }
+    frame BOOMI { light POWCRYS_X9  }
+    frame BOOMJ { light POWCRYS_X10 }
+    frame BOOMK { light POWCRYS_X11 }
+    frame BOOML { light POWCRYS_X12 }
+    frame BOOMM { light POWCRYS_X13 }
+    frame BOOMN { light POWCRYS_X14 }
+    frame BOOMO { light POWCRYS_X15 }
+    frame BOOMP { light POWCRYS_X16 }
+    frame BOOMQ { light POWCRYS_X17 }
+    frame BOOMR { light POWCRYS_X18 }
+    frame BOOMS { light POWCRYS_X19 }
+    frame BOOMT { light POWCRYS_X20 }
+    frame BOOMU { light POWCRYS_X21 }
+    frame BOOMV { light POWCRYS_X22 }
+    frame BOOMW { light POWCRYS_X23 }
+    frame BOOMX { light POWCRYS_X24 }
+    frame BOOMY { light POWCRYS_X25 }
+}
+
+// Computer
+pulselight COMPUTER
+{
+    color 0.25 1.0 0.25
+    size 112
+    secondarySize 128
+    interval 0.25    
+    offset 0 64 0
+}
+
+object Computer
+{
+    frame SECRA { light COMPUTER }
+    frame SECRB { light COMPUTER }
+    frame SECRC { light COMPUTER }
+    frame SECRD { light COMPUTER }
+}
+
+// Strife Explosive Barrel
+flickerlight BARREL_X1
+{
+    color 1.0 0.6 0.1
+    size 48
+    secondarySize 56
+    chance 0.3
+}
+
+flickerlight BARREL_X2
+{
+    color 1.0 0.8 0.0
+    size 56
+    secondarySize 64
+    chance 0.3
+}
+
+flickerlight BARREL_X3
+{
+    color 1.0 0.7 0.0
+    size 72
+    secondarySize 80
+    chance 0.3
+}
+
+flickerlight BARREL_X4
+{
+    color 1.0 0.6 0.0
+    size 80
+    secondarySize 88
+    chance 0.3
+}
+
+flickerlight BARREL_X5
+{
+    color 1.0 0.5 0.0
+    size 72
+    secondarySize 76
+    chance 0.3
+}
+
+flickerlight BARREL_X6
+{
+    color 1.0 0.45 0.0
+    size 56
+    secondarySize 60
+    chance 0.3
+}
+
+flickerlight BARREL_X7
+{
+    color 1.0 0.4 0.0
+    size 52
+    secondarySize 56
+    chance 0.3
+    offset 0 24 0
+}
+
+flickerlight BARREL_X8
+{
+    color 1.0 0.35 0.0
+    size 36
+    secondarySize 40
+    chance 0.3
+    offset 0 40 0
+}
+
+flickerlight BARREL_X9
+{
+    color 1.0 0.3 0.0
+    size 16
+    secondarySize 24
+    chance 0.3
+    offset 0 56 0
+}
+
+object ExplosiveBarrel2
+{
+    frame BARTC { light BARREL_X1 }
+    frame BARTD { light BARREL_X2 }
+    frame BARTE { light BARREL_X3 }
+    frame BARTF { light BARREL_X4 }
+    frame BARTG { light BARREL_X5 }
+    frame BARTH { light BARREL_X6 }
+    frame BARTI { light BARREL_X7 }
+    frame BARTJ { light BARREL_X8 }
+    frame BARTK { light BARREL_X9 }
+}
+
+// Alarm
+pointlight KLAXON
+{
+    color 1.0 0.0 0.0
+    size 24
+}
+
+object KlaxonWarningLight
+{
+    frame KLAXC { light KLAXON }
+}
\ No newline at end of file
diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 0bdd93ea2d78f42c8a00c0c672073965d56f67e0..7dfd99b4ebbbdb404ca1e017ec725b6c644cd4f8 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -712,10 +712,14 @@
       <DependentUpon>ConsoleDocker.cs</DependentUpon>
     </Compile>
     <Compile Include="GZBuilder\Data\BoundingBox.cs" />
+    <Compile Include="GZBuilder\Data\GameType.cs" />
     <Compile Include="GZBuilder\Data\GZDoomLight.cs" />
+    <Compile Include="GZBuilder\Data\MapInfo.cs" />
     <Compile Include="GZBuilder\Data\ModeldefEntry.cs" />
+    <Compile Include="GZBuilder\Data\TextureData.cs" />
     <Compile Include="GZBuilder\Data\ThingBoundingBox.cs" />
     <Compile Include="GZBuilder\GZDoom\GldefsParser.cs" />
+    <Compile Include="GZBuilder\GZDoom\MapinfoParser.cs" />
     <Compile Include="GZBuilder\GZDoom\ModeldefParser.cs" />
     <Compile Include="GZBuilder\GZDoom\ModeldefStructure.cs" />
     <Compile Include="GZBuilder\GZGeneral.cs" />
diff --git a/Source/Core/Builder.sln b/Source/Core/Builder.sln
index 9a59c636000acdd516a53194970da7805119c1a1..87f1bad790aa7a9770446c0015cc623722cdd512 100644
--- a/Source/Core/Builder.sln
+++ b/Source/Core/Builder.sln
@@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 10.00
 # Visual C# Express 2008
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj", "{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GZDoomEditing", "..\Plugins\GZDoomEditing\GZDoomEditing.csproj", "{760A9BC7-CB73-4C36-858B-994C14996FCD}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -23,6 +25,16 @@ Global
 		{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|Mixed Platforms.Build.0 = Release|x86
 		{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.ActiveCfg = Release|x86
 		{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.Build.0 = Release|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|x86.ActiveCfg = Debug|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|x86.Build.0 = Debug|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|Any CPU.ActiveCfg = Release|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|Mixed Platforms.Build.0 = Release|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|x86.ActiveCfg = Release|x86
+		{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/Source/Core/Config/GameConfiguration.cs b/Source/Core/Config/GameConfiguration.cs
index b5912efc0b2d8a5381bb8755d65f5953f9faa520..5bf75cff136c29cc0c09485ccf7d4e58789f3ded 100644
--- a/Source/Core/Config/GameConfiguration.cs
+++ b/Source/Core/Config/GameConfiguration.cs
@@ -29,6 +29,8 @@ using System.Windows.Forms;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Editing;
 
+using CodeImp.DoomBuilder.GZBuilder.Data;
+
 #endregion
 
 namespace CodeImp.DoomBuilder.Config
@@ -131,6 +133,9 @@ namespace CodeImp.DoomBuilder.Config
 		// Defaults
 		private List<DefinedTextureSet> texturesets;
 		private List<ThingsFilter> thingfilters;
+
+        //mxd. Holds base game type (doom, heretic, hexen or strife)
+        private GameType gameType;
 		
 		#endregion
 
@@ -221,6 +226,9 @@ namespace CodeImp.DoomBuilder.Config
 		// Defaults
 		internal List<DefinedTextureSet> TextureSets { get { return texturesets; } }
 		public List<ThingsFilter> ThingsFilters { get { return thingfilters; } }
+
+        //mxd
+        public GameType GameType { get { return gameType; } }
 		
 		#endregion
 
@@ -260,6 +268,10 @@ namespace CodeImp.DoomBuilder.Config
 			
 			// Read general settings
 			configname = cfg.ReadSetting("game", "<unnamed game>");
+
+            //mxd
+            gameType = (GameType)(cfg.ReadSetting("basegame", (int)GameType.UNKNOWN));
+
 			enginename = cfg.ReadSetting("engine", "");
 			defaultsavecompiler = cfg.ReadSetting("defaultsavecompiler", "");
 			defaulttestcompiler = cfg.ReadSetting("defaulttestcompiler", "");
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index bca1ac74abd32b1eb97ed789293432956d3eeed2..85fe3f1bc5794553dbdf542750651a9eeb12e10c 100644
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -32,6 +32,7 @@ using System.Threading;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Windows;
 using CodeImp.DoomBuilder.ZDoom;
+using CodeImp.DoomBuilder.VisualModes;
 
 using CodeImp.DoomBuilder.GZBuilder.Data;
 using CodeImp.DoomBuilder.GZBuilder.GZDoom;
@@ -68,11 +69,10 @@ namespace CodeImp.DoomBuilder.Data
 		private List<ResourceTextureSet> resourcetextures;
 		private AllTextureSet alltextures;
 
-        //mxd Folders
-        //private List<string> folders;
-
-        //mxd modeldefs
-        private Dictionary<int, ModeldefEntry> modeldefEntries;
+        //mxd 
+        private Dictionary<int, ModeldefEntry> modeldefEntries; //Thing.Type, Model entry
+        private Dictionary<int, GZDoomLight> gldefsEntries; //Thing.Type, Light entry
+        private MapInfo mapInfo; //mapinfo
 		
 		// Background loading
 		private Queue<ImageData> imageque;
@@ -114,8 +114,9 @@ namespace CodeImp.DoomBuilder.Data
 		#region ================== Properties
 
         //mxd
-        //public List<string> Folders { get { return folders; } }
         public Dictionary<int, ModeldefEntry> ModeldefEntries { get { return modeldefEntries; } }
+        public Dictionary<int, GZDoomLight> GldefsEntries { get { return gldefsEntries; } }
+        public MapInfo MapInfo { get { return mapInfo; } }
 
 		public Playpal Palette { get { return palette; } }
 		public PreviewManager Previews { get { return previews; } }
@@ -207,6 +208,14 @@ namespace CodeImp.DoomBuilder.Data
 				//thingbox = null;
 				whitetexture.Dispose();
 				whitetexture = null;
+
+                //mxd
+                if (modeldefEntries != null) {
+                    foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries)
+                        group.Value.Dispose();
+                    modeldefEntries = null;
+                }
+                mapInfo = null;
 				
 				// Done
 				isdisposed = true;
@@ -325,7 +334,16 @@ namespace CodeImp.DoomBuilder.Data
 			LoadInternalSprites();
 
             //mxd
-            loadModeldefs();
+            General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing MAPINFO...");
+            loadMapInfo();
+            Dictionary<string, int> actorsByClass = createActorsByClassList();
+            General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing model definitions...");
+            loadModeldefs(actorsByClass);
+            General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing GLDEFS...");
+            loadGldefs(actorsByClass, true);
+            General.MainWindow.DisplayReady();
+            //don't need them any more
+            actorsByClass = null;
 			
 			// Process colormaps (we just put them in as textures)
 			foreach(KeyValuePair<long, ImageData> t in colormapsonly)
@@ -1354,8 +1372,9 @@ namespace CodeImp.DoomBuilder.Data
 		
 		#endregion
 
-        #region ================== Modeldef and models
+        #region ================== Modeldef, Gldefs, Mapinfo and models loading
 
+        //mxd
         public void LoadModels() {
             General.MainWindow.DisplayStatus(StatusType.Busy, "Loading models...");
 
@@ -1365,6 +1384,7 @@ namespace CodeImp.DoomBuilder.Data
             General.MainWindow.RedrawDisplay();
         }
 
+        //mxd
         public bool LoadModelForThing(Thing t) {
             if (modeldefEntries.ContainsKey(t.Type)) {
                 if (modeldefEntries[t.Type].Model == null) {
@@ -1381,11 +1401,11 @@ namespace CodeImp.DoomBuilder.Data
                     currentreader = null;
 
                     if (mde.Model != null) {
-                        GZBuilder.GZGeneral.LogAndTraceWarning("Loaded model for Thing ¹" + t.Type);
+                        //GZBuilder.GZGeneral.Trace("Loaded model for Thing ¹" + t.Type);
                         return true;
                     } else {
                         modeldefEntries.Remove(t.Type);
-                        GZBuilder.GZGeneral.LogAndTraceWarning("Failed to load model(s) for Thing ¹" + t.Type + ", model(s) location is "+mde.Location+ "\\" + mde.Path +". MODELDEF node removed.");
+                        GZBuilder.GZGeneral.LogAndTraceWarning("Failed to load model" + (mde.ModelNames.Count > 1 ? "s" : "") + " for Thing ¹" + t.Type + " from '"+mde.Location+ "\\" + mde.Path +"'");
                         return false;
                     }
                 }
@@ -1394,25 +1414,83 @@ namespace CodeImp.DoomBuilder.Data
             return false;
         }
 
-        //mxd. This parses modeldefs. Should be called after all DECORATE actors are parsed
-        private void loadModeldefs() {
-            General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing model definitions...");
+        //mxd. This creates <Actor Class, Thing.Type> dictionary. Should be called after all DECORATE actors are parsed
+        private Dictionary<string, int> createActorsByClassList() {
+            Dictionary<string, int> actors = new Dictionary<string, int>();
 
-            Dictionary<string, int> Actors = new Dictionary<string, int>();
             Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
 
             //read our new shiny ClassNames for default game things
             foreach (KeyValuePair<int, ThingTypeInfo> ti in things) {
                 if (ti.Value.ClassName != null)
-                    Actors.Add(ti.Value.ClassName, ti.Key);
+                    actors.Add(ti.Value.ClassName, ti.Key);
             }
 
             //and for actors defined in DECORATE
-            ICollection<ActorStructure> ac = decorate.Actors; //General.Map.Data.Decorate.Actors;
+            ICollection<ActorStructure> ac = decorate.Actors;
             foreach (ActorStructure actor in ac) {
+                if (actor.DoomEdNum == -1) //we don't need actors without DoomEdNum
+                    continue;
+
                 string className = actor.ClassName.ToLower();
-                if (actor.DoomEdNum != -1 && !Actors.ContainsKey(className)) //we don't need actors without DoomEdNum
-                    Actors.Add(className, actor.DoomEdNum);
+                if (!actors.ContainsKey(className)) 
+                    actors.Add(className, actor.DoomEdNum);
+            }
+
+            return actors;
+        }
+
+        //mxd
+        public void ReloadModeldef() {
+            if (modeldefEntries != null) {
+                foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries)
+                    group.Value.Dispose();
+            }
+            General.MainWindow.DisplayStatus(StatusType.Busy, "Reloading model definitions...");
+            loadModeldefs(createActorsByClassList());
+
+            //rebuild geometry if in Visual mode
+            if (General.Editing.Mode != null && General.Editing.Mode.GetType().Name == "BaseVisualMode") {
+                General.Editing.Mode.OnReloadResources();
+            }
+
+            General.MainWindow.DisplayReady();
+        }
+
+        //mxd
+        public void ReloadGldefs() {
+            General.MainWindow.DisplayStatus(StatusType.Busy, "Reloading GLDEFS...");
+            loadGldefs(createActorsByClassList(), false);
+
+            //rebuild geometry if in Visual mode
+            if (General.Editing.Mode != null && General.Editing.Mode.GetType().Name == "BaseVisualMode") {
+                General.Editing.Mode.OnReloadResources();
+            }
+
+            General.MainWindow.DisplayReady();
+        }
+
+        //mxd
+        public void ReloadMapInfo() {
+            General.MainWindow.DisplayStatus(StatusType.Busy, "Reloading (Z)MAPINFO...");
+            loadMapInfo();
+
+            //rebuild geometry if in Visual mode
+            if (General.Editing.Mode != null && General.Editing.Mode.GetType().Name == "BaseVisualMode") {
+                General.Editing.Mode.OnReloadResources();
+            }
+
+            General.MainWindow.DisplayReady();
+        }
+
+        //mxd. This parses modeldefs. Should be called after all DECORATE actors are parsed and actorsByClass dictionary created
+        private void loadModeldefs(Dictionary<string, int> actorsByClass) {
+            modeldefEntries = new Dictionary<int, ModeldefEntry>(); //create it in all cases, so we don't have to check if it's null every time we need to access it
+            
+            //if no actors defined in DECORATE or game config...
+            if (actorsByClass == null || actorsByClass.Count == 0) {
+                GZBuilder.GZGeneral.Trace("Warning: current game has no Actors!");
+                return;
             }
 
             Dictionary<string, ModeldefEntry> modelDefEntriesByName = new Dictionary<string, ModeldefEntry>();
@@ -1424,7 +1502,6 @@ namespace CodeImp.DoomBuilder.Data
                 Dictionary<string, Stream> streams = dr.GetModeldefData();
                 foreach (KeyValuePair<string, Stream> group in streams) {
                     // Parse the data
-                    group.Value.Seek(0, SeekOrigin.Begin);
                     if (mdeParser.Parse(group.Value, currentreader.Location.location + "\\" + group.Key)) {
                         foreach (KeyValuePair<string, ModeldefEntry> g in mdeParser.ModelDefEntries) {
                             g.Value.Location = currentreader.Location.location;
@@ -1435,14 +1512,153 @@ namespace CodeImp.DoomBuilder.Data
             }
 
             currentreader = null;
-            modeldefEntries = new Dictionary<int, ModeldefEntry>();
 
             foreach (KeyValuePair<string, ModeldefEntry> e in modelDefEntriesByName) {
-                if (Actors.ContainsKey(e.Key))
-                    modeldefEntries[Actors[e.Key]] = modelDefEntriesByName[e.Key];
+                if (actorsByClass.ContainsKey(e.Key))
+                    modeldefEntries[actorsByClass[e.Key]] = modelDefEntriesByName[e.Key];
                 else
                     GZBuilder.GZGeneral.LogAndTraceWarning("Got MODELDEF override for class '" + e.Key + "', but haven't found such class in Decorate");
             }
+
+            //dbg
+            /*foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries) {
+                GZBuilder.GZGeneral.Trace("MDE for thing " + group.Key + ":");
+                GZBuilder.GZGeneral.Trace("Name: " + group.Value.ClassName);
+                GZBuilder.GZGeneral.Trace("Path: " + group.Value.Path);
+
+                foreach (string d in group.Value.ModelNames)
+                    GZBuilder.GZGeneral.Trace("ModelName: " + d);
+
+                foreach (string d in group.Value.TextureNames)
+                    GZBuilder.GZGeneral.Trace("TextureName: " + d);
+
+                GZBuilder.GZGeneral.Trace("Scale: " + group.Value.Scale.X + "," + group.Value.Scale.Y + "," + group.Value.Scale.Z);
+                GZBuilder.GZGeneral.Trace("zOffset: " + group.Value.zOffset);
+            }*/
+        }
+
+        //mxd. This parses gldefs. Should be called after all DECORATE actors are parsed and actorsByClass dictionary created
+        private void loadGldefs(Dictionary<string, int> actorsByClass, bool loadDefaultDefinitions) {
+            gldefsEntries = new Dictionary<int, GZDoomLight>();//create it in all cases, so we don't have to check if it's null every time we need to access it
+
+            //if no actors defined in DECORATE or game config...
+            if (actorsByClass == null || actorsByClass.Count == 0) {
+                GZBuilder.GZGeneral.Trace("Warning: current game has no Actors!");
+                return;
+            }
+
+            GldefsParser parser = new GldefsParser();
+            parser.OnInclude = loadGldefsFromLocation;
+
+            //load default GZDoom gldefs for current game
+            if (loadDefaultDefinitions && General.Map.Config.GameType != GameType.UNKNOWN) {
+                string defaultGldefsPath = Gldefs.GLDEFS_LUMPS_PER_GAME[(int)General.Map.Config.GameType].ToLowerInvariant() + ".txt";
+                defaultGldefsPath = Path.Combine(Path.Combine(General.AppPath, "Gldefs"), defaultGldefsPath);
+
+                if (File.Exists(defaultGldefsPath)) {
+                    StreamReader s = File.OpenText(defaultGldefsPath);
+                    parser.Parse(s.BaseStream, defaultGldefsPath);
+                } else {
+                    GZBuilder.GZGeneral.LogAndTraceWarning("Unable to load default GLDEFS for current game: unable to load file '" + defaultGldefsPath + "'");
+                }
+            } else {
+                GZBuilder.GZGeneral.LogAndTraceWarning("Default GLDEFS for current game not found.");
+            }
+
+            //load gldefs from resources
+            foreach (DataReader dr in containers) {
+                currentreader = dr;
+                Dictionary<string, Stream> streams = dr.GetGldefsData(General.Map.Config.GameType);
+
+                foreach (KeyValuePair<string, Stream> group in streams)
+                    parser.Parse(group.Value, group.Key);
+            }
+
+            //create gldefsEntries dictionary
+            foreach (KeyValuePair<string, string> e in parser.Objects) { //ClassName, Light name
+                
+                //if we have decorate actor and light definition for given ClassName...
+                if (actorsByClass.ContainsKey(e.Key) && parser.LightsByName.ContainsKey(e.Value)) {
+                    int thingType = actorsByClass[e.Key];
+                    if (gldefsEntries.ContainsKey(thingType)) {
+                        gldefsEntries[thingType] = parser.LightsByName[e.Value];
+                    }else{
+                        gldefsEntries.Add(thingType, parser.LightsByName[e.Value]);
+                    }
+                } else {
+                    GZBuilder.GZGeneral.LogAndTraceWarning("Got GLDEFS for class '" + e.Key + "', but haven't found such class in Decorate");
+                }
+            }
+
+            //dbg
+            GZBuilder.GZGeneral.Trace("******************************************");
+            foreach (KeyValuePair<int, GZDoomLight> group in gldefsEntries) {
+                if (group.Key == 2015) {
+                    GZBuilder.GZGeneral.Trace("----------------------------------------");
+                    GZBuilder.GZGeneral.Trace("gldefsEntry for id " + group.Key + ":");
+                    GZBuilder.GZGeneral.Trace("Color: " + group.Value.Color.Red + "," + group.Value.Color.Green + "," + group.Value.Color.Blue);
+                    GZBuilder.GZGeneral.Trace("PrimaryRadius: " + group.Value.PrimaryRadius);
+                    GZBuilder.GZGeneral.Trace("SecondaryRadius: " + group.Value.SecondaryRadius);
+                    GZBuilder.GZGeneral.Trace("Interval: " + group.Value.Interval);
+                    GZBuilder.GZGeneral.Trace("Offset: " + group.Value.Offset.X + "," + group.Value.Offset.Y + "," + group.Value.Offset.Z);
+                    //GZBuilder.GZGeneral.Trace("Scale: " + group.Value.Scale);
+                    GZBuilder.GZGeneral.Trace("Type: " + group.Value.Type);
+                    //GZBuilder.GZGeneral.Trace("Chance: " + group.Value.Chance);
+
+                    GZBuilder.GZGeneral.Trace("Subtractive: " + group.Value.Subtractive);
+                    GZBuilder.GZGeneral.Trace("DontLightSelf: " + group.Value.DontLightSelf);
+                }
+            }
+        }
+
+        //mxd. This loads (Z)MAPINFO
+        private void loadMapInfo() {
+            //dbg
+            //GZBuilder.GZGeneral.Trace("Loading MAPINFO for map " + General.Map.Options.LevelName);
+
+            MapinfoParser parser = new MapinfoParser();
+
+            foreach (DataReader dr in containers) {
+                currentreader = dr;
+
+                Dictionary<string, Stream> streams = dr.GetMapinfoData();
+                foreach (KeyValuePair<string, Stream> group in streams) {
+                    // Parse the data
+                    //group.Value.Seek(0, SeekOrigin.Begin);
+                    parser.Parse(group.Value, Path.Combine(currentreader.Location.location, group.Key), General.Map.Options.LevelName); 
+                }
+            }
+            currentreader = null;
+
+            if (parser.MapInfo != null)
+                mapInfo = parser.MapInfo;
+            else
+                mapInfo = new MapInfo();
+
+            //dbg
+            /*GZBuilder.GZGeneral.Trace("********************************");
+            GZBuilder.GZGeneral.Trace("MAPINFO for map " + General.Map.Options.LevelName + ":");
+            GZBuilder.GZGeneral.Trace("EvenLighting: " + mapInfo.EvenLighting);
+            GZBuilder.GZGeneral.Trace("HasFadeColor: " + mapInfo.HasFadeColor);
+            GZBuilder.GZGeneral.Trace("FadeColor: " + mapInfo.FadeColor.Red + "," + mapInfo.FadeColor.Green + "," + mapInfo.FadeColor.Blue);
+            GZBuilder.GZGeneral.Trace("HasOutsideFogColor: " + mapInfo.HasOutsideFogColor);
+            GZBuilder.GZGeneral.Trace("OutsideFogColor: " + mapInfo.OutsideFogColor.Red + "," + mapInfo.OutsideFogColor.Green + "," + mapInfo.OutsideFogColor.Blue);
+            GZBuilder.GZGeneral.Trace("Sky1: " + mapInfo.Sky1);
+            GZBuilder.GZGeneral.Trace("Sky1ScrollSpeed: " + mapInfo.Sky1ScrollSpeed);
+            GZBuilder.GZGeneral.Trace("Sky2: " + mapInfo.Sky2);
+            GZBuilder.GZGeneral.Trace("Sky2ScrollSpeed: " + mapInfo.Sky2ScrollSpeed);
+            GZBuilder.GZGeneral.Trace("DoubleSky: " + mapInfo.DoubleSky);
+            //GZBuilder.GZGeneral.Trace("SmoothLighting: " + mapInfo.SmoothLighting);
+            GZBuilder.GZGeneral.Trace("HorizWallShade: " + mapInfo.HorizWallShade);
+            GZBuilder.GZGeneral.Trace("VertWallShade: " + mapInfo.VertWallShade);
+            GZBuilder.GZGeneral.Trace("********************************");*/
+        }
+
+        private void loadGldefsFromLocation(GldefsParser parser, string location) {
+            Dictionary<string, Stream> streams = currentreader.GetGldefsData(location);
+
+            foreach (KeyValuePair<string, Stream> group in streams)
+                parser.Parse(group.Value, group.Key);
         }
 
         #endregion
diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs
index 0cecb7b136783acf7a8ddd7d402604f4567f12bc..f8afb602cd19d13309bad86a3a75267fb95153e8 100644
--- a/Source/Core/Data/DataReader.cs
+++ b/Source/Core/Data/DataReader.cs
@@ -27,6 +27,7 @@ using System.IO;
 using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.IO;
 using CodeImp.DoomBuilder.Rendering;
+using CodeImp.DoomBuilder.GZBuilder.Data;
 
 #endregion
 
@@ -151,14 +152,21 @@ namespace CodeImp.DoomBuilder.Data
 		
 		#endregion
 
-		#region ================== Decorate
+		#region ================== Decorate, Modeldef, Mapinfo, Gldefs
 
 		// When implemented, this returns the decorate lump
 		public virtual List<Stream> GetDecorateData(string pname) { return new List<Stream>(); }
 
-        //mxd. When implemented, this returns the modeldef lump
+        //mxd. When implemented, this returns the Modeldef lump
         public virtual Dictionary<string, Stream> GetModeldefData() { return new Dictionary<string, Stream>(); }
 
+        //mxd. When implemented, this returns the Mapinfo lump
+        public virtual Dictionary<string, Stream> GetMapinfoData() { return new Dictionary<string, Stream>(); }
+
+        //mxd. When implemented, this returns the Gldefs lump
+        public virtual Dictionary<string, Stream> GetGldefsData(GameType gameType) { return new Dictionary<string, Stream>(); }
+        public virtual Dictionary<string, Stream> GetGldefsData(string location) { return new Dictionary<string, Stream>(); }
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs
index af3cbcc11f36c84a5bbd7ca1f85593d4d95f79f6..8fdaebde38cf0dd7b46241ebdc058f5237ded412 100644
--- a/Source/Core/Data/PK3StructuredReader.cs
+++ b/Source/Core/Data/PK3StructuredReader.cs
@@ -25,6 +25,7 @@ using System.Drawing;
 using System.Drawing.Imaging;
 using System.IO;
 using CodeImp.DoomBuilder.IO;
+using CodeImp.DoomBuilder.GZBuilder.Data;
 
 #endregion
 
@@ -440,6 +441,74 @@ namespace CodeImp.DoomBuilder.Data
 
         #endregion
 
+        #region ================== (Z)MAPINFO
+        
+        //mxd
+        public override Dictionary<string, Stream> GetMapinfoData() {
+            Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
+            // Error when suspended
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            //mapinfo should be in root folder
+            string[] allFiles = GetAllFiles("", false);
+            string fileName;
+
+            //try to find (z)mapinfo
+            foreach (string s in allFiles) {
+                fileName = s.ToLowerInvariant();
+                if (fileName.IndexOf("zmapinfo") != -1 || fileName.IndexOf("mapinfo") != -1)
+                    streams.Add(s, LoadFile(s));
+            }
+
+            return streams;
+        }
+
+        #endregion
+
+        #region ================== GLDEFS
+
+        //mxd
+        public override Dictionary<string, Stream> GetGldefsData(GameType gameType) {
+            Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
+            // Error when suspended
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            //at least one of gldefs should be in root folder
+            string[] allFiles = GetAllFiles("", false);
+
+            //try to load game specific GLDEFS first
+            string lumpName = Gldefs.GLDEFS_LUMPS_PER_GAME[(int)gameType].ToLowerInvariant();
+            foreach (string s in allFiles) {
+                if (s.ToLowerInvariant().IndexOf(lumpName) != -1)
+                    streams.Add(s, LoadFile(s));
+            }
+
+            //can be several entries
+            lumpName = "gldefs";
+            foreach (string s in allFiles) {
+                if (s.ToLowerInvariant().IndexOf(lumpName) != -1)
+                    streams.Add(s, LoadFile(s));
+            }
+
+            return streams;
+        }
+
+        //mxd
+        public override Dictionary<string, Stream> GetGldefsData(string location) {
+            Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
+            // Error when suspended
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            Stream s = LoadFile(location);
+
+            if (s != null)
+                streams.Add(location, s);
+
+            return streams;
+        }
+
+        #endregion
+
         #region ================== Methods
 
         // This loads the images in this directory
diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs
index 80d77c219f0afa0206339882acda9a3cc8c0a6a2..b37aa74d0ae9a80e4a9d8015759f26a8cfad8577 100644
--- a/Source/Core/Data/WADReader.cs
+++ b/Source/Core/Data/WADReader.cs
@@ -27,6 +27,7 @@ using System.IO;
 using CodeImp.DoomBuilder.IO;
 using CodeImp.DoomBuilder.ZDoom;
 using CodeImp.DoomBuilder.Rendering;
+using CodeImp.DoomBuilder.GZBuilder.Data;
 
 #endregion
 
@@ -793,7 +794,7 @@ namespace CodeImp.DoomBuilder.Data
 		
 		#endregion
 
-		#region ================== Things
+		#region ================== Decorate, Gldefs, Mapinfo
 
 		// This finds and returns a sprite stream
 		public override List<Stream> GetDecorateData(string pname)
@@ -816,6 +817,71 @@ namespace CodeImp.DoomBuilder.Data
 			
 			return streams;
 		}
+
+        //mxd
+        public override Dictionary<string, Stream> GetMapinfoData() {
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
+            int lumpindex;
+            string src = "ZMAPINFO";
+
+            //should be only one entry per wad
+            //first look for ZMAPINFO
+            lumpindex = file.FindLumpIndex(src);
+
+            //then for MAPINFO
+            if (lumpindex == -1) {
+                src = "MAPINFO";
+                lumpindex = file.FindLumpIndex(src);
+            }
+
+            if(lumpindex != -1)
+                streams.Add(src, file.Lumps[lumpindex].Stream);
+
+            return streams;
+        }
+
+        //mxd
+        public override Dictionary<string, Stream> GetGldefsData(GameType gameType) {
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
+            int lumpindex;
+
+            //try to load game specific GLDEFS first
+            if (gameType != GameType.UNKNOWN) {
+                string lumpName = Gldefs.GLDEFS_LUMPS_PER_GAME[(int)gameType];
+                lumpindex = file.FindLumpIndex(lumpName);
+
+                if (lumpindex != -1)
+                    streams.Add(lumpName, file.Lumps[lumpindex].Stream);
+            }
+
+            //should be only one entry per wad
+            lumpindex = file.FindLumpIndex("GLDEFS");
+            
+            if (lumpindex != -1)
+                streams.Add("GLDEFS", file.Lumps[lumpindex].Stream);
+
+            return streams;
+        }
+
+        //mxd
+        public override Dictionary<string, Stream> GetGldefsData(string location) {
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
+            int lumpindex;
+
+            lumpindex = file.FindLumpIndex(location);
+            
+            if (lumpindex != -1)
+                streams.Add(location, file.Lumps[lumpindex].Stream);
+
+            return streams;
+        }
+
 		#endregion
 	}
 }
diff --git a/Source/Core/GZBuilder/Data/GZDoomLight.cs b/Source/Core/GZBuilder/Data/GZDoomLight.cs
index c680c4ae6e476967006c37ab14dc4ee3ec80e0e4..9457554fb1ea7f522a2e13165e74c5477d88bb71 100644
--- a/Source/Core/GZBuilder/Data/GZDoomLight.cs
+++ b/Source/Core/GZBuilder/Data/GZDoomLight.cs
@@ -1,18 +1,64 @@
-//using SlimDX;
+using System;
+using SlimDX;
 
 namespace CodeImp.DoomBuilder.GZBuilder.Data
 {
-    /*public struct GZDoomLight
-    {
+    public class GZDoomLight {
+        public int Type; //holds GZDoomLightType
         public Color3 Color;
-        public Vector4 PosAndRadius;
-        public int MinRadius;
-        public int MaxRadius;
-        public int Type; //listed in GZDoomLightType
-        public int RenderStyle; //normal, additive, negative
-        public int CameraDistance;
-        public float AnimationSpeed;
-    }*/
+        public int PrimaryRadius;
+        public int SecondaryRadius;
+        public int Interval;
+        public Vector3 Offset;
+        public bool Subtractive;
+        public bool DontLightSelf;
+
+        public GZDoomLight() {
+            Color = new Color3();
+            Offset = new Vector3();
+        }
+
+        public static int[] GetDefaultLightSettings(int type) {
+            int light_id = Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, type);
+            if (light_id != -1) {
+                int[] args = new int[5];
+                
+                if (light_id == (int)GZDoomLightType.VAVOOM_COLORED) {
+                    args[0] = 16;
+                    args[1] = 255;
+                    args[2] = 255;
+                    args[3] = 255;
+                } else if (light_id == (int)GZDoomLightType.VAVOOM) {
+                    args[0] = 16;
+                } else {
+                    int n;
+                    if (light_id < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) {
+                        n = 0;
+                    } else if (light_id < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) {
+                        n = 10;
+                    } else {
+                        n = 20;
+                    }
+                    light_id = type - 9800 - n;
+
+                    args[0] = 255;
+                    args[1] = 255;
+                    args[2] = 255;
+
+                    if (light_id == (int)GZDoomLightType.SECTOR)
+                        args[3] = 4;
+                    else
+                        args[3] = 64;
+
+                    if (Array.IndexOf(GZBuilder.GZGeneral.GZ_ANIMATED_LIGHT_TYPES, light_id) != -1) {
+                        args[4] = 32;
+                    }
+                }
+                return args;
+            }
+            return null;
+        }
+    }
 
     public enum GZDoomLightType : int
     {
@@ -22,7 +68,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
         SECTOR = 3,
         RANDOM = 4,
         VAVOOM = 1502,
-        VAVOOM_COLORED = 1503
+        VAVOOM_COLORED = 1503,
     }
 
     //divide these by 100 to get light color alpha
@@ -31,6 +77,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
         NORMAL = 99,
         VAVOOM = 50,
         ADDITIVE = 25,
-        NEGATIVE = 100
+        NEGATIVE = 100,
     }
 }
diff --git a/Source/Core/GZBuilder/Data/GameType.cs b/Source/Core/GZBuilder/Data/GameType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2e086c5eac1f93b02741bc0d8fdf2e86e74a596a
--- /dev/null
+++ b/Source/Core/GZBuilder/Data/GameType.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace CodeImp.DoomBuilder.GZBuilder.Data {
+    public enum GameType : int {
+        DOOM = 0,
+        HERETIC = 1,
+        HEXEN = 2,
+        STRIFE = 3,
+        UNKNOWN = 4,
+    }
+
+    public struct Gldefs {
+        public static string[] GLDEFS_LUMPS_PER_GAME = { "DOOMDEFS", "HTICDEFS", "HEXNDEFS", "STRFDEFS" };
+    }
+}
diff --git a/Source/Core/GZBuilder/Data/MapInfo.cs b/Source/Core/GZBuilder/Data/MapInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ee556f8ba795f2c4c91ad2b9b2ad522006275aa2
--- /dev/null
+++ b/Source/Core/GZBuilder/Data/MapInfo.cs
@@ -0,0 +1,27 @@
+using System;
+using SlimDX;
+using SlimDX.Direct3D9;
+
+namespace CodeImp.DoomBuilder.GZBuilder.Data {
+    public class MapInfo {
+        public string Sky1;
+        public float Sky1ScrollSpeed;
+        public string Sky2;
+        public float Sky2ScrollSpeed;
+        public bool DoubleSky;
+        public bool HasFadeColor;
+        public Color4 FadeColor;
+        public bool HasOutsideFogColor;
+        public Color4 OutsideFogColor;
+
+        public bool EvenLighting;
+        public bool SmoothLighting;
+        public int VertWallShade;
+        public int HorizWallShade;
+
+        public MapInfo() {
+            VertWallShade = 16;
+            HorizWallShade = -16;
+        }
+    }
+}
diff --git a/Source/Core/GZBuilder/Data/TextureData.cs b/Source/Core/GZBuilder/Data/TextureData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2cbd3e9bbbefa995bf078e20f3fe0d288c81afec
--- /dev/null
+++ b/Source/Core/GZBuilder/Data/TextureData.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace CodeImp.DoomBuilder.GZBuilder.Data {
+    public struct TextureData {
+        public const string INVALID_TEXTURE = "**INVALID_TEXTURE**";
+        public static string[] SUPPORTED_TEXTURE_EXTENSIONS = { ".jpg", ".tga", ".png", ".dds" };
+    }
+}
diff --git a/Source/Core/GZBuilder/GZDoom/GldefsParser.cs b/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
index 4cb07a72e9d502958af9a41478dab53cc49b8667..711d8b7bab3233f0b8a268bb92b849ce4fe5bf7a 100644
--- a/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
+++ b/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
@@ -5,52 +5,80 @@ using System.Globalization;
 using System.Text;
 
 using CodeImp.DoomBuilder.ZDoom;
+using CodeImp.DoomBuilder.GZBuilder.Data;
 
 using SlimDX;
 using SlimDX.Direct3D9;
 
 namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
     public class GldefsParser : ZDTextParser {
-        private Dictionary<string, GldefsLight> gldefsEntries;
-        public Dictionary<string, GldefsLight> GldefsEntries { get { return gldefsEntries; } }
-        public string Source { get { return sourcename; } }
+
+        public delegate void IncludeDelegate(GldefsParser parser, string includefile);
+        public IncludeDelegate OnInclude;
+
+        private Dictionary<string, GZDoomLight> lightsByName; //LightName, light definition
+        private Dictionary<string, string> objects; //ClassName, LightName
+
+        public Dictionary<string, GZDoomLight> LightsByName { get { return lightsByName; } }
+        public Dictionary<string, string> Objects { get { return objects; } }
+
+        private List<string> parsedLumps;
+
+        private struct GldefsLightType {
+            public const string POINT = "pointlight";
+            public const string PULSE = "pulselight";
+            public const string FLICKER = "flickerlight";
+            public const string FLICKER2 = "flickerlight2";
+            public const string SECTOR = "sectorlight";
+
+            public static Dictionary<string, int> GLDEFS_TO_GZDOOM_LIGHT_TYPE = new Dictionary<string, int>() { { POINT, 0 }, { PULSE, 1 }, { FLICKER, 2 }, { FLICKER2, 4 }, { SECTOR, 3 } };
+        }
+
+        public GldefsParser() {
+            parsedLumps = new List<string>();
+            lightsByName = new Dictionary<string, GZDoomLight>(); //LightName, Light params
+            objects = new Dictionary<string, string>(); //ClassName, LightName
+        }
 
         public override bool Parse(Stream stream, string sourcefilename) {
             base.Parse(stream, sourcefilename);
 
-            gldefsEntries = new Dictionary<string, GldefsLight>();
-            Dictionary<string, GldefsLight> lightsByName = new Dictionary<string, GldefsLight>();
-            List<string> objects = new List<string>();
+            if (parsedLumps.IndexOf(sourcefilename) != -1) {
+                GZBuilder.GZGeneral.LogAndTraceWarning("Error: already parsed '" + sourcefilename + "'. Check your #include directives!");
+                return false;
+            }
+            parsedLumps.Add(sourcefilename);
+
+            // Keep local data
+            Stream localstream = datastream;
+            string localsourcename = sourcename;
+            BinaryReader localreader = datareader;
 
             // Continue until at the end of the stream
             while (SkipWhitespace(true)) {
                 string token = ReadToken();
                 if (!string.IsNullOrEmpty(token)) {
-                    token = token.ToLowerInvariant();
+                    token = StripTokenQuotes(token.ToLowerInvariant()); //Quotes can be anywhere! ANYWHERE!!! And GZDoom will still parse data correctly
 
                     //got light structure
                     if (token == GldefsLightType.POINT || token == GldefsLightType.PULSE || token == GldefsLightType.FLICKER || token == GldefsLightType.FLICKER2 || token == GldefsLightType.SECTOR) {
                         bool gotErrors = false;
-                        string lightType = token; //todo: set correct type
-                        GldefsLight light = new GldefsLight();
+                        string lightType = token;
+
+                        GZDoomLight light = new GZDoomLight();
+                        light.Type = GldefsLightType.GLDEFS_TO_GZDOOM_LIGHT_TYPE[lightType];
 
                         //find classname
                         SkipWhitespace(true);
-                        string lightName = ReadToken().ToLowerInvariant();
+                        string lightName = StripTokenQuotes(ReadToken()).ToLowerInvariant();
 
                         if (!string.IsNullOrEmpty(lightName)) {
-                            if (lightsByName.ContainsKey(lightName)) {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Already got light '" + lightName + "'; entry skipped");
-                                continue; //already got this light; continue to next one
-                            }
-
                             //now find opening brace
                             SkipWhitespace(true);
                             token = ReadToken();
                             if (token != "{") {
-                                //Form1.Trace("Unexpected token found in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got " + token);
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got " + token);
-                                continue; //something wrong with modeldef declaration, continue to next one
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got " + token);
+                                continue; //something wrong with gldefs declaration, continue to next one
                             }
 
                             //read gldefs light structure
@@ -59,11 +87,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                                 if (!string.IsNullOrEmpty(token)) {
                                     token = token.ToLowerInvariant();
-                                    //color
+//color
                                     if (token == "color") {
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
+                                        token = StripTokenQuotes(ReadToken());
                                         if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Red)) {
                                             // Not numeric!
                                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Red Color value, but got '" + token + "'");
@@ -73,7 +101,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
+                                        token = StripTokenQuotes(ReadToken());
                                         if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Green)) {
                                             // Not numeric!
                                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Green Color value, but got '" + token + "'");
@@ -83,30 +111,38 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
+                                        token = StripTokenQuotes(ReadToken());
                                         if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Blue)) {
                                             // Not numeric!
                                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Blue Color value, but got '" + token + "'");
                                             gotErrors = true;
                                             break;
                                         }
-                                        //size
+//size
                                     } else if (token == "size") {
-                                        SkipWhitespace(true);
+                                        if (lightType != GldefsLightType.SECTOR) {
+                                            SkipWhitespace(true);
+
+                                            token = StripTokenQuotes(ReadToken());
+                                            if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.PrimaryRadius)) {
+                                                // Not numeric!
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Size value, but got '" + token + "'");
+                                                gotErrors = true;
+                                                break;
+                                            }
+                                            light.PrimaryRadius *= 2;
 
-                                        token = ReadToken();
-                                        if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.Size)) {
-                                            // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Size value, but got '" + token + "'");
+                                        } else {
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType);
                                             gotErrors = true;
                                             break;
                                         }
-                                        //offset
+//offset
                                     } else if (token == "offset") {
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
-                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Offset.X)) {
+                                        token = StripTokenQuotes(ReadToken());
+                                        if (!ReadSignedFloat(token, ref light.Offset.X)) {
                                             // Not numeric!
                                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset X value, but got '" + token + "'");
                                             gotErrors = true;
@@ -115,28 +151,28 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
-                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Offset.Y)) {
+                                        token = StripTokenQuotes(ReadToken());
+                                        if (!ReadSignedFloat(token, ref light.Offset.Z)) {
                                             // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset Y value, but got '" + token + "'");
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset X value, but got '" + token + "'");
                                             gotErrors = true;
                                             break;
                                         }
 
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
-                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Offset.Z)) {
+                                        token = StripTokenQuotes(ReadToken());
+                                        if (!ReadSignedFloat(token, ref light.Offset.Y)) {
                                             // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset Z value, but got '" + token + "'");
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset X value, but got '" + token + "'");
                                             gotErrors = true;
                                             break;
                                         }
-                                        //subtractive
+//subtractive
                                     } else if (token == "subtractive") {
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
+                                        token = StripTokenQuotes(ReadToken());
                                         int i;
                                         if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) {
                                             // Not numeric!
@@ -146,11 +182,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                                         }
 
                                         light.Subtractive = i == 1;
-                                        //dontlightself
+//dontlightself
                                     } else if (token == "dontlightself") {
                                         SkipWhitespace(true);
 
-                                        token = ReadToken();
+                                        token = StripTokenQuotes(ReadToken());
                                         int i;
                                         if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) {
                                             // Not numeric!
@@ -159,74 +195,136 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                                             break;
                                         }
 
-                                        light.DontLightSelf = i == 1;
-                                        //interval
-                                    } else if (token == "interval" && (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER2)) {
-                                        SkipWhitespace(true);
+                                        light.DontLightSelf = (i == 1);
+//interval
+                                    } else if (token == "interval") {
+                                        if (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER2) {
+                                            SkipWhitespace(true);
+
+                                            token = StripTokenQuotes(ReadToken());
+                                            float interval;
+                                            if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out interval)) {
+                                                // Not numeric!
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Interval value, but got '" + token + "'");
+                                                gotErrors = true;
+                                                break;
+                                            }
 
-                                        token = ReadToken();
-                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Interval)) {
-                                            // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Interval value, but got '" + token + "'");
+                                            //I wrote logic for dynamic lights animation first, so here I modify gldefs settings to fit in existing logic
+                                            if (lightType == GldefsLightType.PULSE) {
+                                                light.Interval = (int)(interval * 35); //measured in tics (35 per second) in PointLightPulse, measured in seconds in gldefs' PulseLight
+                                            } else { //FLICKER2. Seems like PointLightFlickerRandom to me
+                                                light.Interval = (int)(interval * 350); //0.1 is one second for FlickerLight2
+                                            }
+                                        } else {
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '"+token+"' is not valid property for " + lightType);
                                             gotErrors = true;
                                             break;
                                         }
-                                        //todo: modify Interval based on light type
-
-                                        //secondarysize
-                                    } else if (token == "secondarysize" && (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER || lightType == GldefsLightType.FLICKER2)) {
-                                        SkipWhitespace(true);
+//secondarysize
+                                    } else if (token == "secondarysize") {
+                                        if (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER || lightType == GldefsLightType.FLICKER2) {
+                                            SkipWhitespace(true);
+
+                                            token = StripTokenQuotes(ReadToken());
+                                            if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.SecondaryRadius)) {
+                                                // Not numeric!
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected SecondarySize value, but got '" + token + "'");
+                                                gotErrors = true;
+                                                break;
+                                            }
+                                            light.SecondaryRadius *= 2;
 
-                                        token = ReadToken();
-                                        if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.SecondarySize)) {
-                                            // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected SecondarySize value, but got '" + token + "'");
+                                        } else {
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType);
                                             gotErrors = true;
                                             break;
                                         }
-                                        //chance
-                                    } else if (token == "chance" && lightType == GldefsLightType.FLICKER) {
-                                        SkipWhitespace(true);
+//chance
+                                    } else if (token == "chance") {
+                                        if (lightType == GldefsLightType.FLICKER) {
+                                            SkipWhitespace(true);
+
+                                            token = StripTokenQuotes(ReadToken());
+                                            float chance;
+                                            if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out chance)) {
+                                                // Not numeric!
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Chance value, but got '" + token + "'");
+                                                gotErrors = true;
+                                                break;
+                                            }
 
-                                        token = ReadToken();
-                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Chance)) {
-                                            // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Chance value, but got '" + token + "'");
+                                            //transforming from 0.0 .. 1.0 to 0 .. 359 to fit in existing logic
+                                            light.Interval = (int)(chance * 359.0f);
+                                        } else {
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType);
                                             gotErrors = true;
                                             break;
                                         }
-                                        //scale
-                                    } else if (token == "scale" && lightType == GldefsLightType.SECTOR) {
-                                        SkipWhitespace(true);
+//scale
+                                    } else if (token == "scale") {
+                                        if (lightType == GldefsLightType.SECTOR) {
+                                            SkipWhitespace(true);
+
+                                            token = StripTokenQuotes(ReadToken());
+                                            float scale;
+                                            if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale)) {
+                                                // Not numeric!
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'");
+                                                gotErrors = true;
+                                                break;
+                                            }
 
-                                        token = ReadToken();
-                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Scale)) {
-                                            // Not numeric!
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'");
-                                            gotErrors = true;
-                                            break;
-                                        }
+                                            if (scale < 0.0f || scale > 1.0f) {
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": scale must be in 0.0 - 1.0 range, but is " + scale);
+                                                gotErrors = true;
+                                                break;
+                                            }
 
-                                        if (light.Scale < 0 || light.Scale > 1) {
-                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": scale must be in 0.0 - 1.0 range, but is " + light.Scale);
+                                            //sector light doesn't have animation, so we will store it's size in Interval
+                                            //transforming from 0.0 .. 1.0 to 0 .. 10 to preserve value.
+                                            light.Interval = (int)(scale * 10.0f);
+                                        } else {
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType);
                                             gotErrors = true;
                                             break;
                                         }
+
                                         //end of structure
                                     } else if (token == "}") {
                                         if (!gotErrors) {
-                                            //check light
-                                            bool valid = true;
+                                            //general checks
                                             if (light.Color.Red == 0.0f && light.Color.Green == 0.0f && light.Color.Blue == 0.0f) {
-                                                GZBuilder.GZGeneral.LogAndTraceWarning("'" + lightName + "' light Color is 0,0,0. It won't be shown in GZDoom!");
-                                                valid = false;
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": light Color is " + light.Color.Red + "," + light.Color.Green + "," + light.Color.Blue + ". It won't be shown in GZDoom!");
+                                                gotErrors = true;
                                             }
-                                            if (light.Size == 0) {
-                                                GZBuilder.GZGeneral.LogAndTraceWarning("'" + lightName + "' light Size is 0. It won't be shown in GZDoom!");
-                                                valid = false;
+
+                                            //light-type specific checks
+                                            if (light.Type == (int)GZDoomLightType.NORMAL) {
+                                                if (light.PrimaryRadius == 0) {
+                                                    GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": light Size is 0. It won't be shown in GZDoom!");
+                                                    gotErrors = true;
+                                                }
+                                            }
+
+                                            if (light.Type == (int)GZDoomLightType.FLICKER || light.Type == (int)GZDoomLightType.PULSE || light.Type == (int)GZDoomLightType.RANDOM) {
+                                                if (light.PrimaryRadius == 0 && light.SecondaryRadius == 0) {
+                                                    GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": 'Size' and 'SecondarySize' are 0. This light won't be shown in GZDoom!");
+                                                    gotErrors = true;
+                                                }
                                             }
 
-                                            if (valid) lightsByName.Add(lightName, light);
+                                            //offset it slightly to avoid shading glitches
+                                            if (light.Offset.Y == 0)
+                                                light.Offset.Y = 0.1f;
+
+                                            if (!gotErrors) {
+                                                if (lightsByName.ContainsKey(lightName)) {
+                                                    lightsByName[lightName] = light;
+                                                } else {
+                                                    lightsByName.Add(lightName, light);
+                                                }
+                                            }
                                         }
                                         break; //break out of this parsing loop
                                     }
@@ -238,58 +336,68 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         SkipWhitespace(true);
 
                         //read object class
-                        string objectClass = ReadToken().ToLowerInvariant();
+                        string objectClass = StripTokenQuotes(ReadToken()).ToLowerInvariant();
 
                         if (!string.IsNullOrEmpty(objectClass)) {
-                            if (objects.Contains(objectClass)) {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": already got object '" + objectClass + "'; entry skipped");
-                                continue; //already got this object; continue to next one
-                            }
-
-                            objects.Add(objectClass);
-
                             //now find opening brace
                             SkipWhitespace(true);
                             token = ReadToken();
+
                             if (token != "{") {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got " + token);
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got " + token);
                                 continue;
                             }
 
+                            int bracesCount = 1;
+                            bool foundLight = false;
+
                             //read frames structure
                             while (SkipWhitespace(true)) {
                                 token = ReadToken();
 
                                 if (!string.IsNullOrEmpty(token)) {
-                                    token = token.ToLowerInvariant();
+                                    token = StripTokenQuotes(token).ToLowerInvariant();
 
-                                    if (token == "light") { //just use first light from first frame and be done with it
+                                    if (!foundLight && token == "light") { //just use first light from first frame and be done with it
                                         SkipWhitespace(true);
                                         token = ReadToken().ToLowerInvariant(); //should be light name
 
                                         if (!string.IsNullOrEmpty(token)) {
                                             if (lightsByName.ContainsKey(token)) {
-                                                gldefsEntries.Add(objectClass, lightsByName[token]);
+                                                if (objects.ContainsKey(objectClass))
+                                                    objects[objectClass] = token;
+                                                else
+                                                    objects.Add(objectClass, token);
+                                                foundLight = true;
                                             } else {
-                                                GZBuilder.GZGeneral.LogAndTraceWarning("Light declaration not found for light '" + token + "' in '" + sourcefilename+"'");
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": light declaration not found for light '" + token + "'");
                                             }
-                                            break;
                                         }
+                                    } else if (token == "{") { //continue in this loop until object structure ends
+                                        bracesCount++;
+                                    } else if (token == "}") {
+                                        if (--bracesCount <= 0)
+                                            break; //This was Cave Johnson. And we are done here.
                                     }
-
                                 }
                             }
-
                         }
 
                     } else if (token == "#include") {
                         SkipWhitespace(true);
                         string includeLump = StripTokenQuotes(ReadToken()).ToLowerInvariant();
 
-                        if (!string.IsNullOrEmpty(includeLump) && includeLump.IndexOf(".gl") != -1) {
-                            //todo: load included file. check for recursive includes?
+                        if (!string.IsNullOrEmpty(includeLump)) {
+                            // Callback to parse this file
+                            if (OnInclude != null)
+                                OnInclude(this, includeLump.Replace("/", "\\"));
+
+                            // Set our buffers back to continue parsing
+                            datastream = localstream;
+                            datareader = localreader;
+                            sourcename = localsourcename;
                         } else {
-                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive with missing or incorrect include path: '" + includeLump + "'");
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive with missing or incorrect path: '" + includeLump + "'");
                         }
 
                     } else {
@@ -314,35 +422,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                 }
             }
 
-            if (gldefsEntries.Count > 0)
+            if (objects.Count > 0)
                 return true;
             return false;
         }
     }
-
-    public class GldefsLight {
-        public int Type;
-        public Color3 Color;
-        public int Size;
-        public int SecondarySize;
-        public float Interval;
-        public Vector3 Offset;
-        public float Chance;
-        public float Scale;
-        public bool Subtractive;
-        public bool DontLightSelf;
-
-        public GldefsLight() {
-            Color = new Color3();
-            Offset = new Vector3();
-        }
-    }
-
-    public struct GldefsLightType {
-        public const string POINT = "pointlight";
-        public const string PULSE = "pulselight";
-        public const string FLICKER = "flickerlight";
-        public const string FLICKER2 = "flickerlight2";
-        public const string SECTOR = "sectorlight";
-    }
-}
+}
\ No newline at end of file
diff --git a/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs b/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f60223dca79529b5f83eb48f331dc0f824e72d73
--- /dev/null
+++ b/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs
@@ -0,0 +1,348 @@
+using System;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+
+using SlimDX;
+using SlimDX.Direct3D9;
+
+using CodeImp.DoomBuilder.ZDoom;
+using CodeImp.DoomBuilder.GZBuilder.Data;
+
+namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
+    public class MapinfoParser : ZDTextParser {
+
+        private MapInfo mapInfo;
+        public MapInfo MapInfo { get { return mapInfo; } }
+
+        public bool Parse(Stream stream, string sourcefilename, string mapName) {
+            base.Parse(stream, sourcefilename);
+
+            mapName = mapName.ToLowerInvariant();
+            mapInfo = new MapInfo();
+
+            while (SkipWhitespace(true)) {
+                string token = ReadToken();
+                if (token != null) {
+                    token = token.ToLowerInvariant();
+
+                    if (parseBlock(token, mapName))
+                        break;
+                }
+            }
+
+            //check values
+            if (mapInfo.FadeColor != null && (mapInfo.FadeColor.Red > 0 || mapInfo.FadeColor.Green > 0 || mapInfo.FadeColor.Blue > 0))
+                mapInfo.HasFadeColor = true;
+
+            if (mapInfo.OutsideFogColor != null && (mapInfo.OutsideFogColor.Red > 0 || mapInfo.OutsideFogColor.Green > 0 || mapInfo.OutsideFogColor.Blue > 0))
+                mapInfo.HasOutsideFogColor = true;
+
+            //Cannot fail here
+            return true;
+        }
+
+        //returns true if parsing is finished
+        private bool parseBlock(string token, string mapName) {
+            string curBlockName;
+            mapName = mapName.ToLowerInvariant();
+
+            if (token == "map" || token == "defaultmap" || token == "adddefaultmap") {
+                curBlockName = token;
+
+                if (token == "map") { //check map name
+                    //get map name
+                    SkipWhitespace(true);
+                    token = ReadToken().ToLowerInvariant();
+
+                    if (token != mapName)
+                        return false; //not finished, search for next "map", "defaultmap" or "adddefaultmap" block
+                } else if (token == "defaultmap") {
+                    //reset MapInfo
+                    mapInfo = new MapInfo();
+                }
+
+                //search for required keys
+                while (SkipWhitespace(true)) {
+                    token = ReadToken().ToLowerInvariant();
+
+                    //sky1 or sky2
+                    if (token == "sky1" || token == "sky2") {
+                        //Form1.Trace("Got sky " + token);
+
+                        string skyType = token;
+                        SkipWhitespace(true);
+                        token = StripTokenQuotes(ReadToken()).ToLowerInvariant();
+
+                        //new format
+                        if (token == "=") {
+                            SkipWhitespace(true);
+
+                            //should be sky texture name
+                            token = StripTokenQuotes(ReadToken());
+                            bool gotComma = (token.IndexOf(",") != -1);
+                            if (gotComma)
+                                token = token.Replace(",", "");
+                            string skyTexture = StripTokenQuotes(token).ToLowerInvariant();
+
+                            if (!string.IsNullOrEmpty(skyTexture)) {
+                                if (skyType == "sky1")
+                                    mapInfo.Sky1 = skyTexture;
+                                else
+                                    mapInfo.Sky2 = skyTexture;
+
+                                //check if we have scrollspeed
+                                SkipWhitespace(true);
+                                token = StripTokenQuotes(ReadToken());
+
+                                if (!gotComma && token == ",") {
+                                    gotComma = true;
+                                    SkipWhitespace(true);
+                                    token = ReadToken();
+                                }
+
+                                if (gotComma) {
+                                    float scrollSpeed = 0;
+
+                                    /*if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scrollSpeed)) {
+                                        // Not numeric!
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " scroll speed value, but got '" + token + "'");
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                        continue;
+                                    }*/
+
+                                    if (!ReadSignedFloat(token, ref scrollSpeed)) {
+                                        // Not numeric!
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " scroll speed value, but got '" + token + "'");
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                        continue;
+                                    }
+
+                                    if (skyType == "sky1")
+                                        mapInfo.Sky1ScrollSpeed = scrollSpeed;
+                                    else
+                                        mapInfo.Sky2ScrollSpeed = scrollSpeed;
+                                } else {
+                                    datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                }
+                            } else {
+                                datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " texture name.");
+                            }
+                            //old format
+                        } else {
+                            //token should be sky1/2 name
+                            if (!string.IsNullOrEmpty(token)) {
+                                if (skyType == "sky1")
+                                    mapInfo.Sky1 = token;
+                                else
+                                    mapInfo.Sky2 = token;
+
+                                //try to read scroll speed
+                                SkipWhitespace(true);
+                                token = StripTokenQuotes(ReadToken());
+
+                                float scrollSpeed = 0;
+                                /*if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scrollSpeed)) {
+                                    // Not numeric!
+                                    GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " scroll speed value, but got '" + token + "'");
+                                    datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                    continue;
+                                }*/
+                                if (!ReadSignedFloat(token, ref scrollSpeed)) {
+                                    // Not numeric!
+                                    GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " scroll speed value, but got '" + token + "'");
+                                    datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                    continue;
+                                }
+
+                                if (skyType == "sky1")
+                                    mapInfo.Sky1ScrollSpeed = scrollSpeed;
+                                else
+                                    mapInfo.Sky2ScrollSpeed = scrollSpeed;
+
+                            } else {
+                                datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " texture name.");
+                            }
+                        }
+                        //fade or outsidefog
+                    } else if (token == "fade" || token == "outsidefog") {
+                        string fadeType = token;
+                        SkipWhitespace(true);
+                        token = StripTokenQuotes(ReadToken()).ToLowerInvariant();
+
+                        //new format
+                        if (token == "=") {
+                            SkipWhitespace(true);
+
+                            //red color value or color name...
+                            token = ReadToken();
+                            string colorVal = StripTokenQuotes(token).ToLowerInvariant();
+                            if (!string.IsNullOrEmpty(colorVal)) {
+                                Color4 color = new Color4();
+                                //color.Alpha = 1.0f;
+
+                                //is it color name?
+                                if (getColorByName(colorVal, ref color)) {
+                                    if (fadeType == "fade")
+                                        mapInfo.FadeColor = color;
+                                    else
+                                        mapInfo.OutsideFogColor = color;
+                                } else { //no, it's not
+                                    //try to get color values
+                                    int r, g, b;
+                                    string[] parts = colorVal.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+                                    if (parts.Length != 3) {
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color values, but got '" + token + "'");
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                        continue;
+                                    }
+
+                                    if (!int.TryParse(parts[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out r)) {
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " red value, but got '" + parts[0] + "'");
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                        continue;
+                                    }
+                                    if (!int.TryParse(parts[1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out g)) {
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " green value, but got '" + parts[1] + "'");
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                        continue;
+                                    }
+                                    if (!int.TryParse(parts[2], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b)) {
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " blue value, but got '" + parts[2] + "'");
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                        continue;
+                                    }
+
+                                    color.Red = (float)r / 255;
+                                    color.Green = (float)g / 255;
+                                    color.Blue = (float)b / 255;
+
+                                    if (fadeType == "fade")
+                                        mapInfo.FadeColor = color;
+                                    else
+                                        mapInfo.OutsideFogColor = color;
+                                }
+                            } else {
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color value.");
+                                datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                            }
+
+                            //old format
+                        } else {
+                            //token should contain red color value or color name...
+                            if (!string.IsNullOrEmpty(token)) {
+                                int r, g, b;
+                                Color4 color = new Color4();
+
+                                if (!int.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out r)) {
+                                    //Not numeric! Maybe it's a color name?
+                                    if (getColorByName(token, ref color)) {
+                                        if (fadeType == "fade")
+                                            mapInfo.FadeColor = color;
+                                        else
+                                            mapInfo.OutsideFogColor = color;
+                                    } else {
+                                        datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                    }
+                                    continue;
+                                }
+
+                                SkipWhitespace(true);
+                                token = ReadToken();
+
+                                //should be color, let's continue parsing it.
+                                if (!int.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out g)) {
+                                    // Not numeric!
+                                    GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " green value, but got '" + token + "'");
+                                    datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                    continue;
+                                }
+
+                                SkipWhitespace(true);
+                                token = StripTokenQuotes(ReadToken());
+
+                                if (!int.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b)) {
+                                    // Not numeric!
+                                    GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " blue value, but got '" + token + "'");
+                                    datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                                    continue;
+                                }
+
+                                color.Red = (float)r / 255;
+                                color.Green = (float)g / 255;
+                                color.Blue = (float)b / 255;
+
+                                if (fadeType == "fade")
+                                    mapInfo.FadeColor = color;
+                                else
+                                    mapInfo.OutsideFogColor = color;
+
+                            } else {
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color value.");
+                                datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                            }
+                        }
+                        //vertwallshade or horizwallshade
+                    } else if (token == "vertwallshade" || token == "horizwallshade") {
+                        string shadeType = token;
+                        SkipWhitespace(true);
+                        token = StripTokenQuotes(ReadToken());
+
+                        //new format
+                        if (token == "=") {
+                            SkipWhitespace(true);
+                            token = StripTokenQuotes(ReadToken());
+                        }
+
+                        int val = 0;
+                        if (!ReadSignedInt(token, ref val)) {
+                            // Not numeric!
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + shadeType + " value, but got '" + token + "'");
+                            datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
+                            continue;
+                        }
+
+                        if (shadeType == "vertwallshade")
+                            mapInfo.VertWallShade = General.Clamp(val, -255, 255);
+                        else
+                            mapInfo.HorizWallShade = General.Clamp(val, -255, 255);
+                        //doublesky
+                    } else if (token == "doublesky") {
+                        mapInfo.DoubleSky = true;
+                        //evenlighting
+                    } else if (token == "evenlighting") {
+                        mapInfo.EvenLighting = true;
+                        //smoothlighting
+                    } else if (token == "smoothlighting") {
+                        mapInfo.SmoothLighting = true;
+                        //block end
+                    } else if (token == "}") {
+                        if (curBlockName == "map") {
+                            return true; //we are done here
+                        } else {
+                            return parseBlock(token, mapName);
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        private bool getColorByName(string name, ref Color4 color) {
+            if (name == "black")
+                return true;
+
+            Color c = Color.FromName(name); //should be similar to C++ color name detection, I suppose
+            if (c.IsKnownColor) {
+                color = new Color4(c);
+                return true;
+            }
+            return false;
+        }
+    }
+}
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
index e5ecbc1195339758da0847c727ff94886db86ffa..e7efe80a2ce3da61d373553a747ddf9bd913e633 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
@@ -10,13 +10,18 @@ using CodeImp.DoomBuilder.GZBuilder.GZDoom;
 namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
    
     public class ModeldefParser : ZDTextParser {
-        public static string INVALID_TEXTURE = "**INVALID_TEXTURE**";
-        
         private Dictionary<string, ModeldefEntry> modelDefEntries; //classname, entry
         public Dictionary<string, ModeldefEntry> ModelDefEntries { get { return modelDefEntries; } }
 
+        private List<string> classNames;
+
         public string Source { get { return sourcename; } }
 
+        public ModeldefParser() {
+            modelDefEntries = new Dictionary<string, ModeldefEntry>();
+            classNames = new List<string>();
+        }
+
         //should be called after all decorate actors are parsed 
         public override bool Parse(Stream stream, string sourcefilename) {
             base.Parse(stream, sourcefilename);
@@ -27,7 +32,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                 string token = ReadToken();
 
                 if (token != null) {
-                    token = token.ToLowerInvariant();
+                    token = StripTokenQuotes(token).ToLowerInvariant();
 
                     if (token == "model") { //model structure start
                         //find classname
@@ -35,8 +40,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         string className = StripTokenQuotes(ReadToken()).ToLowerInvariant();
 
                         if (!string.IsNullOrEmpty(className)) {
-                            if (modelDefEntries.ContainsKey(className))
+                            if (classNames.IndexOf(className) != -1) {
                                 continue; //already got this class; continue to next one
+                            }
+                            classNames.Add(className);
 
                             //now find opening brace
                             SkipWhitespace(true);
@@ -50,7 +57,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             ModeldefEntry mde = mds.Parse(this);
                             if (mde != null) {
                                 mde.ClassName = className;
-                                modelDefEntries.Add(className, mde); 
+                                modelDefEntries.Add(className, mde);
+                                classNames.Add(mde.ClassName);
                             }
                         }
 
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
index 7296b762911a061b0722443e6def9efbd0ac8e88..cc161e246bf5c7b5f0b670997dc850325f0958be 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Text;
@@ -10,11 +11,11 @@ using CodeImp.DoomBuilder.GZBuilder.Data;
 
 namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
     public sealed class ModeldefStructure {
-        private string[] supportedTextureExtensions = { ".jpg", ".tga", ".png", ".dds" };
+        private const int MAX_MODELS = 3; //maximum models per modeldef entry, zero-based
 
         public ModeldefEntry Parse(ModeldefParser parser) {
-            string[] textureNames = new string[16];
-            string[] modelNames = new string[16];
+            string[] textureNames = new string[4];
+            string[] modelNames = new string[4];
             string path = "";
             Vector3 scale = new Vector3(1, 1, 1);
             float zOffset = 0;
@@ -26,24 +27,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                 token = parser.ReadToken();
 
                 if (!string.IsNullOrEmpty(token)) {
-                    token = token.ToLowerInvariant();
-//path
+                    token = parser.StripTokenQuotes(token).ToLowerInvariant(); //ANYTHING can be quoted...
+                    //path
                     if (token == "path") {
                         parser.SkipWhitespace(true);
                         path = parser.StripTokenQuotes(parser.ReadToken()).Replace("/", "\\");
 
                         if (string.IsNullOrEmpty(path)) {
-                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line "+parser.GetCurrentLineNumber()+": expected path to model, but got '" + token + "'");
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected path to model, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
-//model
+                        //model
                     } else if (token == "model") {
                         parser.SkipWhitespace(true);
 
                         //model index
                         int modelIndex;
-                        token = parser.ReadToken();
+                        token = parser.StripTokenQuotes(parser.ReadToken());
                         if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelIndex)) {
                             // Not numeric!
                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model index, but got '" + token + "'");
@@ -51,6 +52,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             break;
                         }
 
+                        if (modelIndex > MAX_MODELS) {
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": GZDoom doesn't allow more than " + MAX_MODELS + " per MODELDEF entry!");
+                            break;
+                        }
+
                         //model path
                         token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
                         if (string.IsNullOrEmpty(token)) {
@@ -62,26 +68,21 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             int dotPos = token.LastIndexOf(".");
                             string fileExt = token.Substring(token.LastIndexOf("."), token.Length - dotPos);
                             if (fileExt != ".md3" && fileExt != ".md2") {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Model '" + token + "' not parsed in " + parser.Source + " at line " + parser.GetCurrentLineNumber() +". Only MD3 and MD2 models are supported.");
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": model '" + token + "' not parsed. Only MD3 and MD2 models are supported.");
                                 gotErrors = true;
                                 break;
                             }
 
-                            if (modelNames[modelIndex] != null) {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": already got model for index " + modelIndex);
-                                gotErrors = true;
-                                break;
-                            } else {
-                                modelNames[modelIndex] = token;
-                            }
+                            //GZDoom allows models with identical modelIndex, it uses the last one encountered
+                            modelNames[modelIndex] = token;
                         }
-//skin
+                        //skin
                     } else if (token == "skin") {
                         parser.SkipWhitespace(true);
 
                         //skin index
                         int skinIndex;
-                        token = parser.ReadToken();
+                        token = parser.StripTokenQuotes(parser.ReadToken());
                         if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out skinIndex)) {
                             // Not numeric!
                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected skin index, but got '" + token + "'");
@@ -89,6 +90,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             break;
                         }
 
+                        if (skinIndex > MAX_MODELS) {
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": GZDoom doesn't allow more than " + MAX_MODELS + " per MODELDEF entry!");
+                            break;
+                        }
+
                         //skin path
                         token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
                         if (string.IsNullOrEmpty(token)) {
@@ -99,95 +105,151 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             //check extension
                             int dotPos = token.LastIndexOf(".");
                             string fileExt = token.Substring(token.LastIndexOf("."), token.Length - dotPos);
-                            if(Array.IndexOf(supportedTextureExtensions, fileExt) == -1)
-                                token = ModeldefParser.INVALID_TEXTURE;
+                            if (Array.IndexOf(TextureData.SUPPORTED_TEXTURE_EXTENSIONS, fileExt) == -1)
+                                token = TextureData.INVALID_TEXTURE;
 
-                            if (textureNames[skinIndex] != null) {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": already got model for index " + skinIndex);
-                                gotErrors = true;
-                                break;
-                            } else {
-                                textureNames[skinIndex] = token;
-                            }
+                            //GZDoom allows skins with identical modelIndex, it uses the last one encountered
+                            textureNames[skinIndex] = token;
                         }
-//scale
+                        //scale
                     } else if (token == "scale") {
                         parser.SkipWhitespace(true);
 
-                        token = parser.ReadToken();
-
-                        int sign = 1;
-                        if (token == "-") {
-                            sign = -1;
-                            token = parser.ReadToken();
-                        }
-
-                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale.X)) {
+                        token = parser.StripTokenQuotes(parser.ReadToken());
+                        if (!parser.ReadSignedFloat(token, ref scale.X)) {
                             // Not numeric!
                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected scale X value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
-                        scale.X *= sign;
 
                         parser.SkipWhitespace(true);
 
-                        token = parser.ReadToken();
-
-                        sign = 1;
-                        if (token == "-") {
-                            sign = -1;
-                            token = parser.ReadToken();
-                        }
-
-                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale.Y)) {
+                        token = parser.StripTokenQuotes(parser.ReadToken());
+                        if (!parser.ReadSignedFloat(token, ref scale.Y)) {
                             // Not numeric!
                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected scale Y value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
-                        scale.Y *= sign;
-
 
                         parser.SkipWhitespace(true);
 
-                        token = parser.ReadToken();
-
-                        sign = 1;
-                        if (token == "-") {
-                            sign = -1;
-                            token = parser.ReadToken();
-                        }
-
-                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale.Z)) {
+                        token = parser.StripTokenQuotes(parser.ReadToken());
+                        if (!parser.ReadSignedFloat(token, ref scale.Z)) {
                             // Not numeric!
                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected scale Z value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
-                        scale.Z *= sign;
-//zoffset
+                        //zoffset
                     } else if (token == "zoffset") {
                         parser.SkipWhitespace(true);
 
-                        token = parser.ReadToken();
-
-                        int sign = 1;
-                        if (token == "-") {
-                            sign = -1;
-                            token = parser.ReadToken();
-                        }
-
-                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out zOffset)) {
+                        token = parser.StripTokenQuotes(parser.ReadToken());
+                        if (!parser.ReadSignedFloat(token, ref zOffset)) {
                             // Not numeric!
                             GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected ZOffset value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
-                        zOffset *= sign;
-//frameindex
+                        //frameindex
                     } else if (token == "frameindex") {
-                        //parsed all required fields
+                        //parsed all required fields. if got more than one model - find which one(s) should be displayed 
+                        int len = modelNames.GetLength(0);
+                        if (!gotErrors && len > 1) {
+                            string spriteLump = null;
+                            string spriteFrame = null;
+                            bool[] modelsUsed = new bool[MAX_MODELS];
+
+                            //step back
+                            parser.DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
+
+                            //here we check which models are used in first encountered lump and frame
+                            while (parser.SkipWhitespace(true)) {
+                                token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
+
+                                if (token == "frameindex") {
+                                    parser.SkipWhitespace(true);
+
+                                    //should be sprite lump
+                                    token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
+
+                                    if (string.IsNullOrEmpty(spriteLump)) {
+                                        spriteLump = token;
+                                    } else if (spriteLump != token) { //got another lump
+                                        for (int i = 0; i < modelsUsed.Length; i++) {
+                                            if (!modelsUsed[i]) {
+                                                modelNames[i] = null;
+                                                textureNames[i] = null;
+                                            }
+                                        }
+                                        break;
+                                    }
+
+                                    parser.SkipWhitespace(true);
+
+                                    //should be sprite frame
+                                    token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
+
+                                    if (string.IsNullOrEmpty(spriteFrame)) {
+                                        spriteFrame = token;
+                                    } else if (spriteFrame != token) { //got another frame
+                                        for (int i = 0; i < modelsUsed.Length; i++) {
+                                            if (!modelsUsed[i]) {
+                                                modelNames[i] = null;
+                                                textureNames[i] = null;
+                                            }
+                                        }
+                                        break;
+                                    }
+
+                                    parser.SkipWhitespace(true);
+
+                                    //should be model index
+                                    token = parser.StripTokenQuotes(parser.ReadToken());
+
+                                    int modelIndex;
+                                    if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelIndex)) {
+                                        // Not numeric!
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model index, but got '" + token + "'");
+                                        gotErrors = true;
+                                        break;
+                                    }
+
+                                    if (modelIndex > MAX_MODELS) {
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": GZDoom doesn't allow more than " + MAX_MODELS + " per MODELDEF entry!");
+                                        gotErrors = true;
+                                        break;
+                                    }
+
+                                    if (modelNames[modelIndex] == null) {
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": got model index, which doesn't correspond to any defined model!");
+                                        gotErrors = true;
+                                        break;
+                                    }
+
+                                    modelsUsed[modelIndex] = true;
+
+                                    parser.SkipWhitespace(true);
+
+                                    //should be frame index. Currently I have no use for it
+                                    token = parser.StripTokenQuotes(parser.ReadToken());
+                                    int frame;
+                                    if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out frame)) {
+                                        // Not numeric!
+                                        GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model frame, but got '" + token + "'");
+                                        gotErrors = true;
+                                        break;
+                                    }
+
+                                } else {
+                                    //must be "}", step back
+                                    parser.DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
+                                    break;
+                                }
+                            }
+                        }
                         break;
                     }
                 }
@@ -201,7 +263,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
             }
 
             if (gotErrors)
-                return null;    
+                return null;
 
             //classname is set in ModeldefParser
             ModeldefEntry mde = new ModeldefEntry();
@@ -209,7 +271,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
             mde.Scale = scale;
             mde.zOffset = zOffset;
 
-            for (int i = 0; i < textureNames.Length; i++ ) {
+            for (int i = 0; i < textureNames.Length; i++) {
                 if (textureNames[i] != null && modelNames[i] != null) {
                     mde.TextureNames.Add(textureNames[i]);
                     mde.ModelNames.Add(modelNames[i]);
diff --git a/Source/Core/GZBuilder/GZGeneral.cs b/Source/Core/GZBuilder/GZGeneral.cs
index e0b4b8eb84453b03e8e529e7c580e91038220857..d339cb6154231275d8687511487a7c2f34ad69c7 100644
--- a/Source/Core/GZBuilder/GZGeneral.cs
+++ b/Source/Core/GZBuilder/GZGeneral.cs
@@ -21,7 +21,7 @@ namespace CodeImp.DoomBuilder.GZBuilder
         //gzdoom light types
         private static int[] gzLights = { /* normal lights */ 9800, 9801, 9802, 9803, 9804, /* additive lights */ 9810, 9811, 9812, 9813, 9814, /* negative lights */ 9820, 9821, 9822, 9823, 9824, /* vavoom lights */ 1502, 1503};
         public static int[] GZ_LIGHTS { get { return gzLights; } }
-        private static int[] gzLightTypes = { 5, 10, 15 }; //this is actually offsets in gz_lights
+        private static int[] gzLightTypes = { 5, 10, 15 }; //these are actually offsets in gz_lights
         public static int[] GZ_LIGHT_TYPES { get { return gzLightTypes; } }
         private static int[] gzAnimatedLightTypes = { (int)GZDoomLightType.FLICKER, (int)GZDoomLightType.RANDOM, (int)GZDoomLightType.PULSE };
         public static int[] GZ_ANIMATED_LIGHT_TYPES {  get { return gzAnimatedLightTypes; } }
@@ -31,7 +31,7 @@ namespace CodeImp.DoomBuilder.GZBuilder
         //public static float[] FogTable; // light to fog conversion table for black fog
 
         //version
-        public const float Version = 1.06f;
+        public const float Version = 1.07f;
 
         //debug console
 #if DEBUG
@@ -87,7 +87,6 @@ namespace CodeImp.DoomBuilder.GZBuilder
 //debug
         public static void LogAndTraceWarning(string message) {
             General.ErrorLogger.Add(ErrorType.Warning, message);
-            General.WriteLogLine(message);
 #if DEBUG
             Trace(message);
 #endif
@@ -173,5 +172,24 @@ namespace CodeImp.DoomBuilder.GZBuilder
             General.MainWindow.RedrawDisplay();
             General.MainWindow.UpdateGZDoomPannel();
         }
+
+        //main menu actions
+        [BeginAction("gzreloadmodeldef")]
+        private static void reloadModeldef() {
+            if(General.Map != null)
+                General.Map.Data.ReloadModeldef();
+        }
+
+        [BeginAction("gzreloadgldefs")]
+        private static void reloadGldefs() {
+            if (General.Map != null)
+                General.Map.Data.ReloadGldefs();
+        }
+
+        [BeginAction("gzreloadmapinfo")]
+        private static void reloadMapInfo() {
+            if (General.Map != null)
+                General.Map.Data.ReloadMapInfo();
+        }
     }
 }
diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs
index 23c03004acb7cf8dce0085fc356bbfb15c05f315..d022d0e7c3d8c8de7f4ce4031a3f58a1a64c18f3 100644
--- a/Source/Core/GZBuilder/md3/ModelReader.cs
+++ b/Source/Core/GZBuilder/md3/ModelReader.cs
@@ -55,11 +55,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
                     if (string.IsNullOrEmpty(error)) {
                         string texturePath = Path.Combine(mde.Path, textureNames[i]);
                         
-                        if (textureNames[i] != ModeldefParser.INVALID_TEXTURE && reader.FileExists(texturePath)) {
+                        if (textureNames[i] != TextureData.INVALID_TEXTURE && reader.FileExists(texturePath)) {
                             mde.Model.Textures.Add(Texture.FromStream(D3DDevice, reader.LoadFile(texturePath)));
                         } else {
                             mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
-                            if (textureNames[i] != ModeldefParser.INVALID_TEXTURE)
+                            if (textureNames[i] != TextureData.INVALID_TEXTURE)
                                 GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: unable to load texture '" + texturePath + "' - no such file");
                         }
                     } else {
diff --git a/Source/Core/General/ErrorLogger.cs b/Source/Core/General/ErrorLogger.cs
index d8e224cce1213d070d49867d641bc871b3283ed8..b14450864a2749f96abaa5e160c0aea93b41a76b 100644
--- a/Source/Core/General/ErrorLogger.cs
+++ b/Source/Core/General/ErrorLogger.cs
@@ -73,6 +73,9 @@ namespace CodeImp.DoomBuilder
 				erroradded = false;
 				warningadded = false;
 				errors.Clear();
+
+                //mxd
+                General.MainWindow.SetWarningsCount(0);
 			}
 		}
 		
@@ -98,6 +101,9 @@ namespace CodeImp.DoomBuilder
 				}
 				changed = true;
 				General.WriteLogLine(prefix + message);
+                
+                //mxd
+                General.MainWindow.SetWarningsCount(errors.Count);
 			}
 		}
 		
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index 920ecb74fc8a77c2ba93399d4a9392a6bac36867..43c71cb12c3be0ce0cade226feb4de1aece6ecf8 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -654,7 +654,7 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new thing and returns it.</summary>
 		public Thing CreateThing()
 		{
-			if(numthings == General.Map.FormatInterface.MaxThings)
+            if(numthings == General.Map.FormatInterface.MaxThings)
 			{
 				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached.");
 				return null;
@@ -669,7 +669,7 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new thing and returns it.</summary>
 		public Thing CreateThing(int index)
 		{
-			if(numthings == General.Map.FormatInterface.MaxThings)
+            if(numthings == General.Map.FormatInterface.MaxThings)
 			{
 				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached.");
 				return null;
diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs
index 061985f450451d61ef4a2c3e115ce8b40da3a0a2..e4eb08a45a7708914343d9af7c4c78a9655b62e3 100644
--- a/Source/Core/Map/Thing.cs
+++ b/Source/Core/Map/Thing.cs
@@ -28,6 +28,8 @@ using System.Drawing;
 using CodeImp.DoomBuilder.IO;
 using CodeImp.DoomBuilder.VisualModes;
 
+using CodeImp.DoomBuilder.GZBuilder.Data;
+
 #endregion
 
 namespace CodeImp.DoomBuilder.Map
@@ -72,7 +74,7 @@ namespace CodeImp.DoomBuilder.Map
 		#region ================== Properties
 
 		public MapSet Map { get { return map; } }
-		public int Type { get { return type; } set { BeforePropsChange(); type = value; } }
+        public int Type { get { return type; } set { BeforePropsChange(); type = value; } }
 		public Vector3D Position { get { return pos; } }
 		public float Angle { get { return anglerad; } }
 		public int AngleDoom { get { return angledoom; } }
diff --git a/Source/Core/Rendering/IRenderer3D.cs b/Source/Core/Rendering/IRenderer3D.cs
index f28a90f9786c7c54e4f3fe239509ad8ab7d325f5..ef4f6c5058980a669805665e9a028770dc147e3c 100644
--- a/Source/Core/Rendering/IRenderer3D.cs
+++ b/Source/Core/Rendering/IRenderer3D.cs
@@ -59,6 +59,9 @@ namespace CodeImp.DoomBuilder.Rendering
 
 		// Rendering methods
 		int CalculateBrightness(int level);
+        //mxd
+        int CalculateBrightness(int level, Sidedef sd);
+
 		void SetHighlightedObject(IVisualPickable obj);
 		void AddSectorGeometry(VisualGeometry g);
 		void AddThingGeometry(VisualThing t);
diff --git a/Source/Core/Rendering/Renderer.cs b/Source/Core/Rendering/Renderer.cs
index d42ed2e8c9da88d9e405c3ea561a09be549a521c..f5ef3394a7520526173e81599c0047888da5d696 100644
--- a/Source/Core/Rendering/Renderer.cs
+++ b/Source/Core/Rendering/Renderer.cs
@@ -22,6 +22,8 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Text;
 
+using CodeImp.DoomBuilder.Map;
+
 #endregion
 
 namespace CodeImp.DoomBuilder.Rendering
@@ -99,6 +101,32 @@ namespace CodeImp.DoomBuilder.Rendering
 			return c.ToInt();
 		}
 
+        //mxd. This calculates wall brightness level with doom-style shading
+        public int CalculateBrightness(int level, Sidedef sd) {
+            if (!General.Map.Data.MapInfo.EvenLighting && sd != null) {
+                //all walls are shaded by their angle
+                if (General.Map.Data.MapInfo.SmoothLighting) {
+                    float ammount = Math.Abs((float)Math.Sin(sd.Angle));
+                    int hAmmount = (int)((1.0f - ammount) * General.Map.Data.MapInfo.HorizWallShade);
+                    int vAmmount = (int)(ammount * General.Map.Data.MapInfo.VertWallShade);
+
+                    level = General.Clamp(level - hAmmount - vAmmount, 0, 255);
+
+                } else { //only horizontal/verticel walls are shaded
+                    int angle = (int)(sd.Angle * 180.0f / Math.PI);
+                    //horizontal wall
+                    if (angle == 270 || angle == 90) {
+                        level = General.Clamp(level + General.Map.Data.MapInfo.HorizWallShade, 0, 255);
+                    //vertical wall
+                    } else if (angle == 0 || angle == 180) {
+                        level = General.Clamp(level + General.Map.Data.MapInfo.VertWallShade, 0, 255);
+                    }
+                }
+            }
+
+            return CalculateBrightness(level);
+        }
+
 		// This is called when the graphics need to be reset
 		public virtual void Reset() { }
 
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index 41c80a5acf556d0216ad748f4bd2723b1298c53c..34b19030dcbffdeb28cb52c2d2a18594c1e87250 100644
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -685,6 +685,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		// This performs a single render pass
 		private void RenderSinglePass(int pass)
 		{
+            Color4 fogColor;
             int currentshaderpass = shaderpass;
 			int highshaderpass = shaderpass + 2;
 			
@@ -779,14 +780,8 @@ namespace CodeImp.DoomBuilder.Rendering
                             if (wantedshaderpass > 7) {
                                 graphics.Shaders.World3D.World = world;
 
-                                bool sectorHasFogColor = true;
-                                if(GZBuilder.GZGeneral.UDMF && sector.Sector.Fields.ContainsKey("fadecolor")){
-                                    graphics.Shaders.World3D.LightColor = new Color4( (int)sector.Sector.Fields["fadecolor"].Value );
-                                }else{
-                                    graphics.Shaders.World3D.LightColor = new Color4(); //black
-                                    sectorHasFogColor = false;
-                                }
-
+                                bool sectorHasFogColor = getFogColor(sector.Sector, out fogColor);
+                                graphics.Shaders.World3D.LightColor = fogColor;
                                 graphics.Shaders.World3D.CameraPosition = new Vector4(cameraposition.x, cameraposition.y, cameraposition.z, getFogEnd(sector.Sector, sectorHasFogColor));
                             }
                             
@@ -850,12 +845,12 @@ namespace CodeImp.DoomBuilder.Rendering
                                         wantedshaderpass += 8;
 
                                     //mxd. if current thing is light - set it's color to light color
-                                    if (t.LightType != -1 && !fullbrightness) {
+                                    if (Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, t.Thing.Type) != -1 && !fullbrightness) {
                                         wantedshaderpass += 4; //render using one of passes, which uses World3D.VertexColor
                                         graphics.Shaders.World3D.VertexColor = t.LightColor;
                                     //mxd. check if Thing is affected by dynamic lights and set color accordingly
                                     }else if (General.Settings.GZDrawLights && !fullbrightness && thingsWithLight.Count > 0) {
-                                        Color4 litColor = getLitColor(t.PositionV3);
+                                        Color4 litColor = getLitColorForThing(t);
                                         if (litColor.ToArgb() != 0) {
                                             wantedshaderpass += 4; //render using one of passes, which uses World3D.VertexColor
                                             graphics.Shaders.World3D.VertexColor = new Color4(t.VertexColor) + litColor;
@@ -885,17 +880,11 @@ namespace CodeImp.DoomBuilder.Rendering
 
                                     //mxd. set variables for fog rendering
                                     if (wantedshaderpass > 7) {
-                                        Sector sector = t.Thing.Sector;
                                         graphics.Shaders.World3D.World = world;
 
-                                        bool sectorHasFogColor = true;
-                                        if (GZBuilder.GZGeneral.UDMF && sector.Fields.ContainsKey("fadecolor")) {
-                                            graphics.Shaders.World3D.LightColor = new Color4((int)sector.Fields["fadecolor"].Value);
-                                        } else {
-                                            graphics.Shaders.World3D.LightColor = new Color4(); //black
-                                            sectorHasFogColor = false;
-                                        }
-                                        graphics.Shaders.World3D.CameraPosition = new Vector4(cameraposition.x, cameraposition.y, cameraposition.z, getFogEnd(sector, sectorHasFogColor));
+                                        bool sectorHasFogColor = getFogColor(t.Thing.Sector, out fogColor);
+                                        graphics.Shaders.World3D.LightColor = fogColor;
+                                        graphics.Shaders.World3D.CameraPosition = new Vector4(cameraposition.x, cameraposition.y, cameraposition.z, getFogEnd(t.Thing.Sector, sectorHasFogColor));
                                     }
 
                                     graphics.Shaders.World3D.ApplySettings();
@@ -947,11 +936,12 @@ namespace CodeImp.DoomBuilder.Rendering
 
                         for (i = 0; i < count; i++) {
                             if (checkBBoxIntersection(g.BoundingBox, lights[i].BoundingBox)) {
-                                lpr = lights[i].LightPositionAndRadius;
+                                lpr = new Vector4(lights[i].Center,lights[i].LightRadius) ;
                                 if (lpr.W == 0)
                                     continue;
                                 graphics.Shaders.World3D.LightColor = lights[i].LightColor;
-                                graphics.Shaders.World3D.LightPositionAndRadius = lights[i].LightPositionAndRadius;
+                                //graphics.Shaders.World3D.LightPositionAndRadius = lights[i].LightPositionAndRadius;
+                                graphics.Shaders.World3D.LightPositionAndRadius = lpr;
                                 graphics.Shaders.World3D.ApplySettings();
                                 graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles);
                             }
@@ -965,11 +955,13 @@ namespace CodeImp.DoomBuilder.Rendering
 
                         for (i = lightOffsets[0]; i < count; i++) {
                             if (checkBBoxIntersection(g.BoundingBox, lights[i].BoundingBox)) {
-                                lpr = lights[i].LightPositionAndRadius;
+                                //lpr = lights[i].LightPositionAndRadius;
+                                lpr = new Vector4(lights[i].Center, lights[i].LightRadius);
                                 if (lpr.W == 0)
                                     continue;
                                 graphics.Shaders.World3D.LightColor = lights[i].LightColor;
-                                graphics.Shaders.World3D.LightPositionAndRadius = lights[i].LightPositionAndRadius;
+                                //graphics.Shaders.World3D.LightPositionAndRadius = lights[i].LightPositionAndRadius;
+                                graphics.Shaders.World3D.LightPositionAndRadius = lpr;
                                 graphics.Shaders.World3D.ApplySettings();
                                 graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles);
                            }
@@ -983,12 +975,14 @@ namespace CodeImp.DoomBuilder.Rendering
 
                         for (i = lightOffsets[0] + lightOffsets[1]; i < count; i++) {
                             if (checkBBoxIntersection(g.BoundingBox, lights[i].BoundingBox)) {
-                                lpr = lights[i].LightPositionAndRadius;
+                                //lpr = lights[i].LightPositionAndRadius;
+                                lpr = new Vector4(lights[i].Center, lights[i].LightRadius);
                                 if (lpr.W == 0)
                                     continue;
                                 Color4 lc = lights[i].LightColor;
                                 graphics.Shaders.World3D.LightColor = new Color4(lc.Alpha, (lc.Green + lc.Blue) / 2, (lc.Red + lc.Blue) / 2, (lc.Green + lc.Red) / 2);
-                                graphics.Shaders.World3D.LightPositionAndRadius = lights[i].LightPositionAndRadius;
+                                //graphics.Shaders.World3D.LightPositionAndRadius = lights[i].LightPositionAndRadius;
+                                graphics.Shaders.World3D.LightPositionAndRadius = lpr;
                                 graphics.Shaders.World3D.ApplySettings();
                                 graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles);
                             }
@@ -1006,6 +1000,7 @@ namespace CodeImp.DoomBuilder.Rendering
 
         //mxd. render models
         private void RenderModels() {
+            Color4 fogColor;
             int shaderpass = fullbrightness ? 1 : 4;
             int currentshaderpass = shaderpass;
             int highshaderpass = shaderpass + 2;
@@ -1019,7 +1014,7 @@ namespace CodeImp.DoomBuilder.Rendering
                     vertexColor.Alpha = 1.0f;
                     //check if model is affected by dynamic lights and set color accordingly
                     if (General.Settings.GZDrawLights && !fullbrightness && thingsWithLight.Count > 0) {
-                        Color4 litColor = getLitColor(t.PositionV3);
+                        Color4 litColor = getLitColorForThing(t);
                         graphics.Shaders.World3D.VertexColor = vertexColor + litColor;
                     } else {
                         graphics.Shaders.World3D.VertexColor = vertexColor;
@@ -1054,22 +1049,13 @@ namespace CodeImp.DoomBuilder.Rendering
 
                     //mxd. set variables for fog rendering
                     if (wantedshaderpass > 7) {
-                        Sector sector = t.Thing.Sector;
                         graphics.Shaders.World3D.World = world;
 
-                        bool sectorHasFogColor = true;
-                        if (GZBuilder.GZGeneral.UDMF && sector.Fields.ContainsKey("fadecolor")) {
-                            graphics.Shaders.World3D.LightColor = new Color4((int)sector.Fields["fadecolor"].Value);
-                        } else {
-                            graphics.Shaders.World3D.LightColor = new Color4(); //black
-                            sectorHasFogColor = false;
-                        }
-                        graphics.Shaders.World3D.CameraPosition = new Vector4(cameraposition.x, cameraposition.y, cameraposition.z, getFogEnd(sector, sectorHasFogColor));
+                        bool sectorHasFogColor = getFogColor(t.Thing.Sector, out fogColor);
+                        graphics.Shaders.World3D.LightColor = fogColor;
+                        graphics.Shaders.World3D.CameraPosition = new Vector4(cameraposition.x, cameraposition.y, cameraposition.z, getFogEnd(t.Thing.Sector, sectorHasFogColor));
                     }
 
-                    //dbg
-                    //GZBuilder.GZGeneral.TraceInHeader("Using shader #"+wantedshaderpass);
-
                     for (int i = 0; i < group.Key.Model.NUM_MESHES; i++) {
                         if (!graphics.Shaders.Enabled) graphics.Device.SetTexture(0, group.Key.Model.Textures[i]);
                         graphics.Shaders.World3D.Texture1 = group.Key.Model.Textures[i];
@@ -1084,16 +1070,20 @@ namespace CodeImp.DoomBuilder.Rendering
         }
 
         //mxd. This gets color from dynamic lights based on distance to thing. 
-        //WARNING: thing position must be in absolute cordinates 
+        //thing position must be in absolute cordinates 
         //(thing.Position.Z value is relative to floor of the sector the thing is in)
-        //so use visualThing.PositionV3 instead
-        private Color4 getLitColor(Vector3 thingPosition) {
+        private Color4 getLitColorForThing(VisualThing t) {
             Color4 litColor = new Color4();
             float radius, radiusSquared, distSquared, scaler;
             int sign;
 
             for (int i = 0; i < thingsWithLight.Count; i++ ) {
-                distSquared = Vector3.DistanceSquared(thingsWithLight[i].Center, thingPosition);
+                //don't light self
+                if (General.Map.Data.GldefsEntries.ContainsKey(t.Thing.Type) && General.Map.Data.GldefsEntries[t.Thing.Type].DontLightSelf && t.Thing.Index == thingsWithLight[i].Thing.Index) {
+                    continue;
+                }
+
+                distSquared = Vector3.DistanceSquared(thingsWithLight[i].Center, t.PositionV3);
                 radius = thingsWithLight[i].LightRadius;
                 radiusSquared = radius * radius;
                 if (distSquared < radiusSquared) {
@@ -1109,12 +1099,27 @@ namespace CodeImp.DoomBuilder.Rendering
 
         //mxd. This returns distance, at which fog color completely replaces texture color for given sector
         private float getFogEnd(Sector s, bool sectorHasFogColor) {
-            //TODO: check if MapInfo has fog settings and apply them 
             float brightness = (float)Math.Max(30, s.Brightness);
             if (sectorHasFogColor) {
                 return brightness * 11.0f;
             }
-            return (float)Math.Pow(2.0f, brightness / 10.0f);
+            return (float)Math.Pow(2.0f, brightness / 11.0f);
+        }
+
+        //mxd. returns true if sector has fog color
+        private bool getFogColor(Sector sector, out Color4 color) {
+            if (GZBuilder.GZGeneral.UDMF && sector.Fields.ContainsKey("fadecolor")) {
+                color = new Color4((int)sector.Fields["fadecolor"].Value);
+                return true;
+            } else if (General.Map.Data.MapInfo.HasOutsideFogColor && sector.CeilTexture == General.Map.Config.SkyFlatName) {
+                color = General.Map.Data.MapInfo.OutsideFogColor;
+                return true;
+            } else if (General.Map.Data.MapInfo.HasFadeColor) {
+                color = General.Map.Data.MapInfo.FadeColor;
+                return true;
+            }
+            color = new Color4(); //black
+            return false;
         }
 
 		// This calculates the highlight/selection color
diff --git a/Source/Core/Resources/Actions.cfg b/Source/Core/Resources/Actions.cfg
index a6c34c2c1e2b5cf418fe8da7aba8a57d586acdc1..427f71640ea03f0763623f4b971a824f0602708d 100644
--- a/Source/Core/Resources/Actions.cfg
+++ b/Source/Core/Resources/Actions.cfg
@@ -832,7 +832,7 @@ gztogglemodels
 {
     title = "Toggle models rendering";
 	category = "gzdoombuilder";
-	description = "Toggle MD3 models rendering.";
+	description = "Toggles models rendering.";
 	allowkeys = true;
 	allowmouse = true;
 	allowscroll = false;
@@ -886,4 +886,38 @@ gztogglefx
 	allowkeys = true;
 	allowmouse = true;
 	allowscroll = false;
+}
+
+//GZDOOMBUILDER MENU ACTIONS//
+gzreloadmodeldef
+{
+   title = "Reload MODELDEF";
+	category = "tools";
+	description = "Reloads MODELDEF. Useful when resource files have been changed outside of Doom Builder.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+	default = 131188;
+}
+
+gzreloadgldefs
+{
+   title = "Reload GLDEFS";
+	category = "tools";
+	description = "Reloads GLDEFS. Useful when resource files have been changed outside of Doom Builder.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+	default = 131189;
+}
+
+gzreloadmapinfo
+{
+   title = "Reload (Z)MAPINFO";
+	category = "tools";
+	description = "Reloads (Z)MAPINFO. Useful when resource files have been changed outside of Doom Builder.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+	default = 131190;
 }
\ No newline at end of file
diff --git a/Source/Core/VisualModes/VisualGeometry.cs b/Source/Core/VisualModes/VisualGeometry.cs
index 503784a57dbad1cdcd17a9e924e3392212bf0b62..25d0e0d1982cedc255a25ad1660d1a5b644e513a 100644
--- a/Source/Core/VisualModes/VisualGeometry.cs
+++ b/Source/Core/VisualModes/VisualGeometry.cs
@@ -84,7 +84,6 @@ namespace CodeImp.DoomBuilder.VisualModes
 
         //mxd
         private Vector3[] boundingBox;
-        //private Vector3D normal;
 		
 		#endregion
 
@@ -167,14 +166,14 @@ namespace CodeImp.DoomBuilder.VisualModes
 			triangles = vertices.Length / 3;
             
             //mxd
-            CalculateNormalsAndShading();
+            CalculateNormals();
 
 			if(sector != null) sector.NeedsUpdateGeo = true;
 		}
 
-        //mxd. Taken from OpenGl wiki 
-        protected void CalculateNormalsAndShading() {
-            if (vertices.Length > 0) {
+        //mxd. Normals calculation algorithm taken from OpenGl wiki 
+        protected void CalculateNormals() {
+            if (triangles > 0) {
                 int startIndex;
                 Vector3 U, V;
 
@@ -193,21 +192,6 @@ namespace CodeImp.DoomBuilder.VisualModes
                     p1.ny = p2.ny = p3.ny = -(U.Z * V.X - U.X * V.Z);
                     p1.nz = p2.nz = p3.nz = -(U.X * V.Y - U.Y * V.X);
 
-                    //doom-style walls shading
-                    //not very apropriate place to put this, but most convinient :)
-                    if (sidedef != null) {
-                        float valMod = 1.0f - Math.Abs((float)Math.Sin(sidedef.Angle)) * 0.07f; //0.07
-                        PixelColor pc = PixelColor.FromInt(p1.c);
-
-                        pc.r = (byte)((float)pc.r * valMod);
-                        pc.g = (byte)((float)pc.g * valMod);
-                        pc.b = (byte)((float)pc.b * valMod);
-
-                        int c = pc.ToInt();
-                        p1.c = c;
-                        p2.c = c;
-                        p3.c = c;
-                    }
                     vertices[startIndex] = p1;
                     vertices[startIndex + 1] = p2;
                     vertices[startIndex + 2] = p3;
diff --git a/Source/Core/VisualModes/VisualThing.cs b/Source/Core/VisualModes/VisualThing.cs
index 8b9c5efc41acc33b22a769f95642a8748617ae7c..dc4ec9ef3031b694fc024e58ba5ffa1cd5f7197e 100644
--- a/Source/Core/VisualModes/VisualThing.cs
+++ b/Source/Core/VisualModes/VisualThing.cs
@@ -38,6 +38,7 @@ using CodeImp.DoomBuilder.Rendering;
 
 //mxd
 using CodeImp.DoomBuilder.GZBuilder.Data;
+using CodeImp.DoomBuilder.GZBuilder.GZDoom;
 
 #endregion
 
@@ -93,6 +94,10 @@ namespace CodeImp.DoomBuilder.VisualModes
         private Vector3 position_v3;
         private float lightDelta; //used in light animation
         private Vector3[] boundingBox;
+        //gldefs light
+        private Vector3 lightOffset;
+        private int lightInterval;
+        private bool isGldefsLight;
 		
 		#endregion
 		
@@ -110,7 +115,14 @@ namespace CodeImp.DoomBuilder.VisualModes
         //mxd
         internal int VertexColor { get { return vertices.Length > 0 ? vertices[0].c : 0;} }
         public int CameraDistance3D { get { return cameraDistance3D; } }
-        public Vector3 Center { get { return new Vector3(position_v3.X, position_v3.Y, position_v3.Z + thingHeight / 2); } }
+        public Vector3 Center { 
+            get 
+            {
+                if (isGldefsLight)
+                    return position_v3 + lightOffset;
+                return new Vector3(position_v3.X, position_v3.Y, position_v3.Z + thingHeight / 2); 
+            } 
+        }
         public Vector3 PositionV3 { get { return position_v3; } }
         public Vector3[] BoundingBox { get { return boundingBox; } }
         //mxd. light properties
@@ -118,7 +130,7 @@ namespace CodeImp.DoomBuilder.VisualModes
         public float LightRadius { get { return lightRadius; } }
         public int LightRenderStyle { get { return lightRenderStyle; } }
         public Color4 LightColor { get { return lightColor; } }
-        public Vector4 LightPositionAndRadius { get { return new Vector4(Center, lightRadius);} }
+        //public Vector4 LightPositionAndRadius { get { return new Vector4(Center, lightRadius);} }
 
 		/// <summary>
 		/// Set to True to use billboarding for this thing. When using billboarding,
@@ -171,6 +183,7 @@ namespace CodeImp.DoomBuilder.VisualModes
             lightRenderStyle = -1;
             lightPrimaryRadius = -1;
             lightSecondaryRadius = -1;
+            lightInterval = -1;
             lightColor = new Color4();
             boundingBox = new Vector3[9];
 			
@@ -323,8 +336,16 @@ namespace CodeImp.DoomBuilder.VisualModes
                 //mxd. Check if thing is light
                 int light_id = Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, thing.Type);
                 if (light_id != -1) {
+                    isGldefsLight = false;
+                    lightInterval = -1;
                     updateLight(light_id);
                     UpdateBoundingBox(lightRadius, lightRadius * 2);
+
+                //check if we have light from GLDEFS
+                } else if (General.Map.Data.GldefsEntries.ContainsKey(thing.Type)) {
+                    isGldefsLight = true;
+                    updateGldefsLight();
+                    UpdateBoundingBox(lightRadius, lightRadius * 2);
                 } else {
                     if (thing.IsModel) {
                         updateBoundingBoxForModel();
@@ -336,6 +357,8 @@ namespace CodeImp.DoomBuilder.VisualModes
                     lightPrimaryRadius = -1;
                     lightSecondaryRadius = -1;
                     lightRenderStyle = -1;
+                    lightInterval = -1;
+                    isGldefsLight = false;
                 }
 
 				// Done
@@ -348,8 +371,6 @@ namespace CodeImp.DoomBuilder.VisualModes
             int light_id = Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, thing.Type);
             if (light_id != -1) {
                 updateLight(light_id);
-
-                //if (Array.IndexOf(GZBuilder.GZGeneral.GZ_ANIMATED_LIGHT_TYPES, lightType) != -1)
                 UpdateBoundingBox(lightRadius, lightRadius * 2);
             }
         }
@@ -398,8 +419,37 @@ namespace CodeImp.DoomBuilder.VisualModes
             UpdateLightRadius();
         }
 
+        //mxd
+        private void updateGldefsLight() {
+            GZDoomLight light = General.Map.Data.GldefsEntries[thing.Type];
+            float intensity_mod = General.Settings.GZDynamicLightIntensity;
+            float scale_mod = General.Settings.GZDynamicLightRadius;
+
+            //apply settings
+            lightRenderStyle = light.Subtractive ? (int)GZDoomLightRenderStyle.NEGATIVE : (int)GZDoomLightRenderStyle.NORMAL;
+            lightColor = new Color4((float)lightRenderStyle / 100.0f, light.Color.Red * intensity_mod, light.Color.Green * intensity_mod, light.Color.Blue * intensity_mod);
+            lightOffset = light.Offset;
+            lightType = light.Type;
+
+            if (lightType == (int)GZDoomLightType.SECTOR) {
+                lightPrimaryRadius = light.Interval * thing.Sector.Brightness / 5;
+            } else {
+                lightPrimaryRadius = light.PrimaryRadius * scale_mod;
+                lightSecondaryRadius = light.SecondaryRadius * scale_mod;
+            }
+
+            lightInterval = light.Interval;
+
+            updateLightRadius(lightInterval);
+        }
+
         //mxd
         public void UpdateLightRadius() {
+            updateLightRadius( (lightInterval != -1 ? lightInterval : thing.AngleDoom) );
+        }
+
+        //mxd
+        private void updateLightRadius(int interval) {
             if (lightType == -1) {
                 General.ErrorLogger.Add(ErrorType.Error, "Please check that thing is light before accessing it's PositionAndRadius! You can use lightType, which is -1 if thing isn't light");
                 return;
@@ -425,7 +475,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 
             //pulse
             if (lightType == (int)GZDoomLightType.PULSE) {
-                lightDelta = ((float)Math.Sin(time / (thing.AngleDoom * 4.0f)) + 1.0f) / 2.0f; //just playing by the eye here... in [0.0 ... 1.0] interval
+                lightDelta = ((float)Math.Sin(time / (interval * 4.0f)) + 1.0f) / 2.0f; //just playing by the eye here... in [0.0 ... 1.0] interval
                 lightRadius = rMin + diff * lightDelta;
             //flicker
             } else if (lightType == (int)GZDoomLightType.FLICKER) {
@@ -433,7 +483,7 @@ namespace CodeImp.DoomBuilder.VisualModes
                 float delta = (float)Math.Sin(time / 0.1f); //just playing by the eye here...
                 if (Math.Sign(delta) != Math.Sign(lightDelta)) {
                     lightDelta = delta;
-                    if (new Random().Next(0, 359) < thing.AngleDoom) 
+                    if (new Random().Next(0, 359) < interval) 
                         lightRadius = rMax;
                     else
                         lightRadius = rMin;
@@ -441,7 +491,7 @@ namespace CodeImp.DoomBuilder.VisualModes
             //random
             } else if (lightType == (int)GZDoomLightType.RANDOM) {
                 //float delta = (float)Math.Sin(time / (thing.AngleDoom));
-                float delta = (float)Math.Sin(time / (thing.AngleDoom * 9.0f)); //just playing by the eye here...
+                float delta = (float)Math.Sin(time / (interval * 9.0f)); //just playing by the eye here...
                 if (Math.Sign(delta) != Math.Sign(lightDelta))
                     lightRadius = rMin + (float)(new Random().Next(0, (int)(diff * 10))) / 10.0f;
                 lightDelta = delta;
diff --git a/Source/Core/Windows/ErrorsForm.cs b/Source/Core/Windows/ErrorsForm.cs
index cbe31f4e2213774df330d73a42f3fd3e55240f5c..3118481e6ec6d0a454364ecc8fd8e47e91017212 100644
--- a/Source/Core/Windows/ErrorsForm.cs
+++ b/Source/Core/Windows/ErrorsForm.cs
@@ -49,6 +49,8 @@ namespace CodeImp.DoomBuilder.Windows
 			FillList();
 			checkerrors.Start();
 			checkshow.Checked = General.Settings.ShowErrorsWindow;
+            //mxd
+            grid.Focus();
 		}
 
 		#endregion
diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs
index 1886316d797ac9de67b12a6f404710b9d924cce0..e80521c85dddd4a1225a73c289f98f6078080ff2 100644
--- a/Source/Core/Windows/MainForm.Designer.cs
+++ b/Source/Core/Windows/MainForm.Designer.cs
@@ -34,6 +34,7 @@ namespace CodeImp.DoomBuilder.Windows
             System.Windows.Forms.ToolStripSeparator toolStripSeparator12;
             System.Windows.Forms.ToolStripSeparator toolStripMenuItem4;
             System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
+            System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
             this.seperatorfileopen = new System.Windows.Forms.ToolStripSeparator();
             this.seperatorfilerecent = new System.Windows.Forms.ToolStripSeparator();
@@ -99,6 +100,9 @@ namespace CodeImp.DoomBuilder.Windows
             this.itemcreateprefab = new System.Windows.Forms.ToolStripMenuItem();
             this.menutools = new System.Windows.Forms.ToolStripMenuItem();
             this.itemreloadresources = new System.Windows.Forms.ToolStripMenuItem();
+            this.itemReloadModedef = new System.Windows.Forms.ToolStripMenuItem();
+            this.itemReloadGldefs = new System.Windows.Forms.ToolStripMenuItem();
+            this.itemReloadMapinfo = new System.Windows.Forms.ToolStripMenuItem();
             this.itemshowerrors = new System.Windows.Forms.ToolStripMenuItem();
             this.seperatortoolsresources = new System.Windows.Forms.ToolStripSeparator();
             this.configurationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -167,6 +171,7 @@ namespace CodeImp.DoomBuilder.Windows
             this.itemzoomfittoscreen = new System.Windows.Forms.ToolStripMenuItem();
             this.xposlabel = new System.Windows.Forms.ToolStripStatusLabel();
             this.yposlabel = new System.Windows.Forms.ToolStripStatusLabel();
+            this.warnsLabel = new System.Windows.Forms.ToolStripStatusLabel();
             this.panelinfo = new System.Windows.Forms.Panel();
             this.heightpanel1 = new System.Windows.Forms.Panel();
             this.vertexinfo = new CodeImp.DoomBuilder.Controls.VertexInfoPanel();
@@ -184,11 +189,13 @@ namespace CodeImp.DoomBuilder.Windows
             this.dockersspace = new System.Windows.Forms.Panel();
             this.dockerspanel = new CodeImp.DoomBuilder.Controls.DockersControl();
             this.dockerscollapser = new System.Windows.Forms.Timer(this.components);
+            this.warntimer = new System.Windows.Forms.Timer(this.components);
             toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
             toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator();
             toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator();
             toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator();
             toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+            toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
             this.menumain.SuspendLayout();
             this.toolbar.SuspendLayout();
             this.statusbar.SuspendLayout();
@@ -223,6 +230,12 @@ namespace CodeImp.DoomBuilder.Windows
             toolStripSeparator2.Name = "toolStripSeparator2";
             toolStripSeparator2.Size = new System.Drawing.Size(153, 6);
             // 
+            // toolStripSeparator3
+            // 
+            toolStripSeparator3.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
+            toolStripSeparator3.Name = "toolStripSeparator3";
+            toolStripSeparator3.Size = new System.Drawing.Size(6, 23);
+            // 
             // seperatorfileopen
             // 
             this.seperatorfileopen.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
@@ -760,6 +773,9 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             this.menutools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.itemreloadresources,
+            this.itemReloadModedef,
+            this.itemReloadGldefs,
+            this.itemReloadMapinfo,
             this.itemshowerrors,
             this.seperatortoolsresources,
             this.configurationToolStripMenuItem,
@@ -778,6 +794,30 @@ namespace CodeImp.DoomBuilder.Windows
             this.itemreloadresources.Text = "&Reload Resources";
             this.itemreloadresources.Click += new System.EventHandler(this.InvokeTaggedAction);
             // 
+            // itemReloadModedef
+            // 
+            this.itemReloadModedef.Name = "itemReloadModedef";
+            this.itemReloadModedef.Size = new System.Drawing.Size(196, 22);
+            this.itemReloadModedef.Tag = "builder_gzreloadmodeldef";
+            this.itemReloadModedef.Text = "Reload MODELDEF";
+            this.itemReloadModedef.Click += new System.EventHandler(this.InvokeTaggedAction);
+            // 
+            // itemReloadGldefs
+            // 
+            this.itemReloadGldefs.Name = "itemReloadGldefs";
+            this.itemReloadGldefs.Size = new System.Drawing.Size(196, 22);
+            this.itemReloadGldefs.Tag = "builder_gzreloadgldefs";
+            this.itemReloadGldefs.Text = "Reload GLDEFS";
+            this.itemReloadGldefs.Click += new System.EventHandler(this.InvokeTaggedAction);
+            // 
+            // itemReloadMapinfo
+            // 
+            this.itemReloadMapinfo.Name = "itemReloadMapinfo";
+            this.itemReloadMapinfo.Size = new System.Drawing.Size(196, 22);
+            this.itemReloadMapinfo.Tag = "builder_gzreloadmapinfo";
+            this.itemReloadMapinfo.Text = "Reload (Z)MAPINFO";
+            this.itemReloadMapinfo.Click += new System.EventHandler(this.InvokeTaggedAction);
+            // 
             // itemshowerrors
             // 
             this.itemshowerrors.Image = global::CodeImp.DoomBuilder.Properties.Resources.Warning;
@@ -1259,10 +1299,12 @@ namespace CodeImp.DoomBuilder.Windows
             toolStripSeparator1,
             this.zoomlabel,
             this.buttonzoom,
-            toolStripSeparator9,
+            toolStripSeparator3,
             this.xposlabel,
             this.poscommalabel,
-            this.yposlabel});
+            this.yposlabel,
+            toolStripSeparator9,
+            this.warnsLabel});
             this.statusbar.Location = new System.Drawing.Point(0, 670);
             this.statusbar.Name = "statusbar";
             this.statusbar.ShowItemToolTips = true;
@@ -1275,7 +1317,7 @@ namespace CodeImp.DoomBuilder.Windows
             this.statuslabel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
             this.statuslabel.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
             this.statuslabel.Name = "statuslabel";
-            this.statuslabel.Size = new System.Drawing.Size(396, 18);
+            this.statuslabel.Size = new System.Drawing.Size(309, 18);
             this.statuslabel.Spring = true;
             this.statuslabel.Text = "Initializing user interface...";
             this.statuslabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@@ -1507,6 +1549,20 @@ namespace CodeImp.DoomBuilder.Windows
             this.yposlabel.Text = "0";
             this.yposlabel.ToolTipText = "Current X, Y coordinates on map";
             // 
+            // warnsLabel
+            // 
+            this.warnsLabel.AutoSize = false;
+            this.warnsLabel.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.WarningOff;
+            this.warnsLabel.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+            this.warnsLabel.Name = "warnsLabel";
+            this.warnsLabel.Size = new System.Drawing.Size(44, 18);
+            this.warnsLabel.Text = "0";
+            this.warnsLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+            this.warnsLabel.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
+            this.warnsLabel.ToolTipText = "Click to open Errors and Warnings window";
+            this.warnsLabel.Click += new System.EventHandler(this.warnsLabel_Click);
+            // 
             // panelinfo
             // 
             this.panelinfo.Controls.Add(this.heightpanel1);
@@ -1682,6 +1738,11 @@ namespace CodeImp.DoomBuilder.Windows
             this.dockerscollapser.Interval = 200;
             this.dockerscollapser.Tick += new System.EventHandler(this.dockerscollapser_Tick);
             // 
+            // warntimer
+            // 
+            this.warntimer.Interval = 500;
+            this.warntimer.Tick += new System.EventHandler(this.warntimer_Tick);
+            // 
             // MainForm
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -1875,5 +1936,10 @@ namespace CodeImp.DoomBuilder.Windows
         private System.Windows.Forms.ToolStripButton buttontoggleanimatedlight;
         private System.Windows.Forms.ToolStripButton buttontogglefx;
         private System.Windows.Forms.ToolStripButton buttontogglefog;
+        private System.Windows.Forms.ToolStripStatusLabel warnsLabel;
+        private System.Windows.Forms.Timer warntimer;
+        private System.Windows.Forms.ToolStripMenuItem itemReloadModedef;
+        private System.Windows.Forms.ToolStripMenuItem itemReloadGldefs;
+        private System.Windows.Forms.ToolStripMenuItem itemReloadMapinfo;
 	}
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index da8ff7b3ccacc28085530eda184d0e43ad653857..22dd640312f15370c4a3e07491a09e7e6dad1f4b 100644
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -156,6 +156,9 @@ namespace CodeImp.DoomBuilder.Windows
 
 		// Updating
 		private int lockupdatecount;
+
+        //mxd
+        private bool warnStatus; //status of warnings panel icon
 		
 		#endregion
 
@@ -2281,7 +2284,13 @@ namespace CodeImp.DoomBuilder.Windows
 		private void UpdateToolsMenu()
 		{
 			// Enable/disable items
-			itemreloadresources.Enabled = (General.Map != null);
+            bool enabled = (General.Map != null);
+			itemreloadresources.Enabled = enabled;
+            
+            //mxd
+            itemReloadGldefs.Enabled = enabled;
+            itemReloadMapinfo.Enabled = enabled;
+            itemReloadModedef.Enabled = enabled;
 		}
 		
 		// Errors and Warnings
@@ -2291,6 +2300,8 @@ namespace CodeImp.DoomBuilder.Windows
 			ErrorsForm errform = new ErrorsForm();
 			errform.ShowDialog(this);
 			errform.Dispose();
+            //mxd
+            SetWarningsCount(0);
 		}
 		
 		// Game Configuration action
@@ -2670,6 +2681,39 @@ namespace CodeImp.DoomBuilder.Windows
 					break;
 			}
 		}
+
+        //mxd. Warnings panel
+        internal void SetWarningsCount(int count) {
+            if (count == 0) {
+                if (warnsLabel.Font.Bold) {
+                    warnsLabel.Font = new Font(warnsLabel.Font, FontStyle.Regular);
+                    warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.WarningOff;
+                }
+                warntimer.Stop();
+                warnStatus = false;
+            } else if (!warnsLabel.Font.Bold) {
+                warnsLabel.Font = new Font(warnsLabel.Font, FontStyle.Bold);
+                warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.Warning;
+                warnStatus = true;
+                warntimer.Start();
+            }
+            warnsLabel.Text = count.ToString();
+        }
+
+        //mxd
+        private void warnsLabel_Click(object sender, EventArgs e) {
+            ShowErrors();
+        }
+
+        //mxd
+        private void warntimer_Tick(object sender, EventArgs e) {
+            if (warnStatus) {
+                warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.WarningOff;
+            } else {
+                warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.Warning;
+            }
+            warnStatus = !warnStatus;
+        }
 		
 		#endregion
 		
diff --git a/Source/Core/Windows/MainForm.resx b/Source/Core/Windows/MainForm.resx
index 638918d509afea7953835961d1e32bbd8279107f..dcf537601d2b84b6814e424819a52c22c17195cc 100644
--- a/Source/Core/Windows/MainForm.resx
+++ b/Source/Core/Windows/MainForm.resx
@@ -132,6 +132,9 @@
   <metadata name="toolStripSeparator2.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>False</value>
   </metadata>
+  <metadata name="toolStripSeparator3.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
   <metadata name="menumain.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
@@ -195,30 +198,6 @@
   <metadata name="sectorinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
-  <metadata name="heightpanel1.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="vertexinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="labelcollapsedinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="buttontoggleinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="modename.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="linedefinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="thinginfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="sectorinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
   <metadata name="redrawtimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>319, 17</value>
   </metadata>
@@ -243,6 +222,9 @@
   <metadata name="dockerscollapser.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>781, 17</value>
   </metadata>
+  <metadata name="warntimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 56</value>
+  </metadata>
   <metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
diff --git a/Source/Core/Windows/ThingEditForm.cs b/Source/Core/Windows/ThingEditForm.cs
index 203736997b794530d10d9bdcf3d8c88e98ac55d0..dd925c396c6463723af01db7c90cf088b398fe21 100644
--- a/Source/Core/Windows/ThingEditForm.cs
+++ b/Source/Core/Windows/ThingEditForm.cs
@@ -30,6 +30,7 @@ using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.Editing;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Controls;
+using CodeImp.DoomBuilder.GZBuilder.Data;
 
 #endregion
 
@@ -243,20 +244,31 @@ namespace CodeImp.DoomBuilder.Windows
 			if(arg2label.Enabled) arg2.ForeColor = SystemColors.WindowText; else arg2.ForeColor = SystemColors.GrayText;
 			if(arg3label.Enabled) arg3.ForeColor = SystemColors.WindowText; else arg3.ForeColor = SystemColors.GrayText;
 			if(arg4label.Enabled) arg4.ForeColor = SystemColors.WindowText; else arg4.ForeColor = SystemColors.GrayText;
-			arg0.Setup(arginfo[0]);
-			arg1.Setup(arginfo[1]);
-			arg2.Setup(arginfo[2]);
-			arg3.Setup(arginfo[3]);
-			arg4.Setup(arginfo[4]);
+
+            arg0.Setup(arginfo[0]);
+            arg1.Setup(arginfo[1]);
+            arg2.Setup(arginfo[2]);
+            arg3.Setup(arginfo[3]);
+            arg4.Setup(arginfo[4]);
 
 			// Zero all arguments when linedef action 0 (normal) is chosen
 			if(!preventchanges && (showaction == 0))
 			{
-				arg0.SetValue(0);
-				arg1.SetValue(0);
-				arg2.SetValue(0);
-				arg3.SetValue(0);
-				arg4.SetValue(0);
+                //mxd. If thing is light, set default light settings
+                int[] args = GZDoomLight.GetDefaultLightSettings(thingtype.GetResult(1));
+                if (args != null) {
+                    arg0.SetValue(args[0]);
+                    arg1.SetValue(args[1]);
+                    arg2.SetValue(args[2]);
+                    arg3.SetValue(args[3]);
+                    arg4.SetValue(args[4]);
+                } else {
+                    arg0.SetValue(0);
+                    arg1.SetValue(0);
+                    arg2.SetValue(0);
+                    arg3.SetValue(0);
+                    arg4.SetValue(0);
+                }
 			}
 		}
 
diff --git a/Source/Core/ZDoom/ZDTextParser.cs b/Source/Core/ZDoom/ZDTextParser.cs
index 0e7a8a839742d44c4b48d6b1ad21254ed5c0620c..8cdddc1d27b2b68f91625ae16c74638580c9bac0 100644
--- a/Source/Core/ZDoom/ZDTextParser.cs
+++ b/Source/Core/ZDoom/ZDTextParser.cs
@@ -293,6 +293,36 @@ namespace CodeImp.DoomBuilder.ZDoom
 
 			return token.Trim();
 		}
+
+        //mxd
+        protected internal bool ReadSignedFloat(string token, ref float value) {
+            int sign = 1;
+            if (token == "-") {
+                sign = -1;
+                token = StripTokenQuotes(ReadToken());
+            }
+
+            float val;
+            bool success = float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val);
+            if (success)
+                value = val * sign;
+            return success;
+        }
+
+        //mxd
+        protected internal bool ReadSignedInt(string token, ref int value) {
+            int sign = 1;
+            if (token == "-") {
+                sign = -1;
+                token = StripTokenQuotes(ReadToken());
+            }
+
+            int val;
+            bool success = int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out val);
+            if (success)
+                value = val * sign;
+            return success;
+        }
 		
 		// This reports an error
 		protected internal void ReportError(string message)
diff --git a/Source/Plugins/ColorPicker/Resources/Actions.cfg b/Source/Plugins/ColorPicker/Resources/Actions.cfg
index 8a3185103581243861d5ff7f0febb832dada73ee..58021742cfd441125d6a8d6098948fd521505321 100644
--- a/Source/Plugins/ColorPicker/Resources/Actions.cfg
+++ b/Source/Plugins/ColorPicker/Resources/Actions.cfg
@@ -1,8 +1,8 @@
 togglelightpannel
 {
-    title = "Toggle color picker";
+    title = "Open color picker";
 	category = "tools";
-	description = "Select dynamic light thing(s) or sectors, then use this pannel to set light properties quickly.";
+	description = "Select dynamic light thing(s) or sector(s), then use this panel to set light properties quickly.";
 	allowkeys = true;
 	allowmouse = true;
 	allowscroll = false;
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualGeometrySidedef.cs
index d72e2bcf89481bfde900c0dcff843a7985ea6c46..b9f774d6233c048909f0d7b4d410333bc744fdae 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualGeometrySidedef.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualGeometrySidedef.cs
@@ -162,14 +162,15 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 		{
 			List<WallPolygon> polygons = new List<WallPolygon>(poly);
 			List<WorldVertex> verts = new List<WorldVertex>();
-			
+
 			// Go for all levels to build geometry
 			for(int i = sd.LightLevels.Count - 1; i >= 0; i--)
 			{
 				SectorLevel l = sd.LightLevels[i];
+
 				if((l != sd.Floor) && (l != sd.Ceiling) && (l.type != SectorLevelType.Floor))
 				{
-					// Go for all polygons
+                    // Go for all polygons
 					int num = polygons.Count;
 					for(int pi = 0; pi < num; pi++)
 					{
@@ -180,7 +181,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 						{
 							// Determine color
 							int lightlevel = lightabsolute ? lightvalue : l.brightnessbelow + lightvalue;
-							PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+                            //mxd
+                            //PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+							PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
 							PixelColor wallcolor = PixelColor.Modulate(l.colorbelow, wallbrightness);
 							np.color = wallcolor.WithAlpha(255).ToInt();
 							
@@ -226,7 +229,6 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 			return verts;
 		}
 		
-		
 		// This splits a polygon with a plane and returns the other part as a new polygon
 		// The polygon is expected to be convex and clockwise
 		protected WallPolygon SplitPoly(ref WallPolygon poly, Plane p, bool keepfront)
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs b/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs
index 4c3e0381d5e8ffad77fce0d0bc091896827b9887..d6c23c506916bce4dec31b658aa7f3dca0b1a2c0 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs
@@ -164,6 +164,11 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 		{
 			return renderer.CalculateBrightness(level);
 		}
+
+        //mxd. This calculates brightness level with doom-style shading
+        internal int CalculateBrightness(int level, Sidedef sd) {
+            return renderer.CalculateBrightness(level, sd);
+        }
 		
 		// This adds a selected object
 		internal void AddSelectedObject(IVisualEventReceiver obj)
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/VisualLower.cs b/Source/Plugins/GZDoomEditing/VisualModes/VisualLower.cs
index bd893fbe7a7520e7bdc27444fd5fb4f76b92b3b5..ac9aaf4596ed86817be378f78af959163f9369f6 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/VisualLower.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/VisualLower.cs
@@ -168,7 +168,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 			
 			// Determine initial color
 			int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
-			PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+			//mxd
+            //PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+            PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
 			PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
 			poly.color = wallcolor.WithAlpha(255).ToInt();
 			
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddle3D.cs b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddle3D.cs
index f491436b0713497075d504db74e36b23d883909c..c93cf53044b37015eba0614132aeb1b6f22e734f 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddle3D.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddle3D.cs
@@ -187,7 +187,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 				
 				// Determine initial color
 				int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
-				PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+				//mxd
+                //PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+                PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
 				PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
 				poly.color = wallcolor.WithAlpha(255).ToInt();
 
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleDouble.cs b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleDouble.cs
index 8d516efeff9ad326c1cc97db3384c975ec2fda2d..1afbddc9c4909caa4cbc126beae6ed0acfb438c2 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleDouble.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleDouble.cs
@@ -184,7 +184,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 				
 				// Determine initial color
 				int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
-				PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+				//mxd
+                //PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+                PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
 				PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
 				poly.color = wallcolor.WithAlpha(255).ToInt();
 				
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs
index 6cc008cd06d16e1c849d30cbab4688bd5db93544..a599cb9fa6d413c2e3a92b8b194ef1356a7323af 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs
@@ -179,7 +179,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 				
 				// Determine initial color
 				int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
-				PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+                //mxd
+				//PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+                PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
 				PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
 				poly.color = wallcolor.WithAlpha(255).ToInt();
 				
diff --git a/Source/Plugins/GZDoomEditing/VisualModes/VisualUpper.cs b/Source/Plugins/GZDoomEditing/VisualModes/VisualUpper.cs
index 31feaa0543a35f9cd5c26b7b9f98fea32be30ccf..0f4180818235916a764993e8aa19497c3a4f8e0f 100644
--- a/Source/Plugins/GZDoomEditing/VisualModes/VisualUpper.cs
+++ b/Source/Plugins/GZDoomEditing/VisualModes/VisualUpper.cs
@@ -169,7 +169,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
 			
 			// Determine initial color
 			int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
-			PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+			//mxd
+            //PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
+            PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
 			PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
 			poly.color = wallcolor.WithAlpha(255).ToInt();