about summary refs log tree commit diff
diff options
context:
space:
mode:
authoroy <Tom_Adams@web.de>2011-07-09 01:09:06 +0200
committeroy <Tom_Adams@web.de>2011-07-09 01:09:06 +0200
commit7bc07b613f9fed3dcef26f63332ea68db1e1f381 (patch)
treed357af2b1d1db1dd6d5d62874326c739890402a4
parentf44094490549a46781a7d85a137ddf748021d00f (diff)
downloadzcatch-7bc07b613f9fed3dcef26f63332ea68db1e1f381.tar.gz
zcatch-7bc07b613f9fed3dcef26f63332ea68db1e1f381.zip
added auto mapping feature by LordSkelethom
-rw-r--r--data/editor/desert_main.rules227
-rw-r--r--data/editor/grass_main.rules225
-rw-r--r--data/editor/jungle_main.rules220
-rw-r--r--data/editor/winter_main.rules177
-rw-r--r--src/game/editor/auto_map.cpp202
-rw-r--r--src/game/editor/auto_map.h54
-rw-r--r--src/game/editor/editor.cpp12
-rw-r--r--src/game/editor/editor.h19
-rw-r--r--src/game/editor/io.cpp3
-rw-r--r--src/game/editor/layer_tiles.cpp24
-rw-r--r--src/game/editor/popups.cpp44
11 files changed, 1194 insertions, 13 deletions
diff --git a/data/editor/desert_main.rules b/data/editor/desert_main.rules
new file mode 100644
index 00000000..0102a197
--- /dev/null
+++ b/data/editor/desert_main.rules
@@ -0,0 +1,227 @@
+[Desert]
+Index 1
+BaseTile
+
+#random
+Index 2
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 3
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+#top
+Index 16
+Pos 0 -1 EMPTY
+
+#right 
+Index 17
+Pos 1 0 EMPTY
+
+#bottom
+Index 18
+Pos 0 1 EMPTY
+
+#left
+Index 19
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 33
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 32
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 35
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 34
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 51
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 50
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 49
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 48
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+
+[Mine]
+Index 81
+BaseTile
+
+#random
+Index 82
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 83
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 84
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 85
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 86
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 100
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 101
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 102
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 117
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 118
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 133
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 134
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+#top
+Index 96
+Pos 0 -1 EMPTY
+
+#right 
+Index 97
+Pos 1 0 EMPTY
+
+#bottom
+Index 98
+Pos 0 1 EMPTY
+
+#left
+Index 99
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 113
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 112
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 115
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 114
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 131
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 130
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 129
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 128
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
diff --git a/data/editor/grass_main.rules b/data/editor/grass_main.rules
new file mode 100644
index 00000000..b909eb0e
--- /dev/null
+++ b/data/editor/grass_main.rules
@@ -0,0 +1,225 @@
+[Grass]
+Index 1
+BaseTile
+
+#random bones
+Index 2
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 3
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 66
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 67
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 68
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+#---------
+
+#top
+Index 16
+Pos 0 -1 EMPTY
+
+#right
+Index 21
+Pos 1 0 EMPTY
+
+#bottom
+Index 52
+Pos 0 1 EMPTY
+
+#left
+Index 20
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 5
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 4
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 36
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 37
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 54
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 53
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 49
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 48
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+
+#right bottom
+Index 22
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+Pos 0 1 FULL
+
+#left bottom
+Index 38
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+Pos 0 1 FULL
+
+#top corner right 2
+Index 33
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+
+#top corner left 2
+Index 32
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+
+[Cave]
+Index 13
+BaseTile
+
+#random bones
+Index 29
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 42
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 43
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 44
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 45
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+#---------
+
+#top
+Index 26
+Pos 0 -1 EMPTY
+
+#right
+Index 25
+Pos 1 0 EMPTY
+
+#bottom
+Index 10
+Pos 0 1 EMPTY
+
+#left
+Index 24
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 9
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 8
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 40
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 41
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 12
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 11
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 27
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 28
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
diff --git a/data/editor/jungle_main.rules b/data/editor/jungle_main.rules
new file mode 100644
index 00000000..3b967020
--- /dev/null
+++ b/data/editor/jungle_main.rules
@@ -0,0 +1,220 @@
+[Jungle]
+Index 1
+BaseTile
+
+#random bricks
+Index 66
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 67
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+#top
+Index 16
+Pos 0 -1 EMPTY
+
+Index 96
+Pos 0 -1 EMPTY
+Random 4
+
+Index 97
+Pos 0 -1 EMPTY
+Random 4
+
+Index 98
+Pos 0 -1 EMPTY
+Random 4
+
+#right 
+Index 21
+Pos 1 0 EMPTY
+
+#bottom
+Index 52
+Pos 0 1 EMPTY
+
+Index 99
+Pos 0 1 EMPTY
+Random 4
+
+Index 100
+Pos 0 1 EMPTY
+Random 4
+
+Index 101
+Pos 0 1 EMPTY
+Random 4
+
+#left
+Index 21 XFLIP
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 5
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 5 XFLIP
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 37 XFLIP
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 37
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 54
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 54 XFLIP
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 48 XFLIP
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 48
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+
+#right bottom
+Index 22
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+Pos 0 1 FULL
+
+#left bottom
+Index 22 XFLIP
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+Pos 0 1 FULL
+
+#top corner right 2
+Index 33
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+
+#top corner left 2
+Index 32
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+
+[Jungle dark]
+Index 13
+BaseTile
+
+#random bricks
+Index 42
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 43
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 44
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 45
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+#---------
+
+#top
+Index 26
+Pos 0 -1 EMPTY
+
+#right 
+Index 25
+Pos 1 0 EMPTY
+
+#bottom
+Index 10
+Pos 0 1 EMPTY
+
+#left
+Index 24
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 9
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 8
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 40
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 41
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 12
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 11
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 27
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 28
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
diff --git a/data/editor/winter_main.rules b/data/editor/winter_main.rules
new file mode 100644
index 00000000..eaeaec8e
--- /dev/null
+++ b/data/editor/winter_main.rules
@@ -0,0 +1,177 @@
+[Winter]
+Index 1
+BaseTile
+
+#top
+Index 17
+Pos 0 -1 EMPTY
+
+Index 18
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 17
+
+Index 19
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 18
+
+#bottom
+Index 97
+Pos 0 1 EMPTY
+
+Index 98
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 97
+
+Index 99
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 98
+
+#right
+Index 2 XFLIP
+Pos 1 0 EMPTY
+
+#left
+Index 2
+Pos -1 0 EMPTY
+
+#corner top right
+Index 20
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+Index 24
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos -1 0 INDEX 17
+
+#corner top left
+Index 16
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom right
+Index 100
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#corner bottom left
+Index 96
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#inside corner top right
+Index 8
+Pos 0 1 FULL
+Pos -1 0 FULL
+Pos -1 1 EMPTY
+
+#inside corner top left
+Index 7
+Pos 0 1 FULL
+Pos 1 0 FULL
+Pos 1 1 EMPTY
+
+#inside corner bottom right
+Index 4
+Pos 0 -1 FULL
+Pos -1 0 FULL
+Pos -1 -1 EMPTY
+
+#inside corner bottom left
+Index 3
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos 1 -1 EMPTY
+
+#one tile height
+Index 113
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+
+Index 114
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 113
+
+Index 115
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 114
+
+#one tile height right
+Index 116
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+Index 120
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos -1 0 INDEX 113
+
+#one tile height left
+Index 112
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#one tile height link right
+Index 6
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+Pos -1 1 EMPTY
+
+#one tile height link left
+Index 5
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+Pos 1 1 EMPTY
+
+[Winter dark]
+Index 177
+BaseTile
+
+#bottom
+Index 194
+Pos 0 1 EMPTY
+
+Index 195
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 194
+
+Index 196
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 195
+
+#right
+Index 178 XFLIP
+Pos 1 0 EMPTY
+
+#left
+Index 178
+Pos -1 0 EMPTY
+
+#corner bottom right
+Index 197
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#corner bottom left
+Index 193
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#inside corner top right
+Index 180
+Pos 0 1 FULL
+Pos -1 0 FULL
+Pos -1 1 EMPTY
+
+#inside corner top left
+Index 179
+Pos 0 1 FULL
+Pos 1 0 FULL
+Pos 1 1 EMPTY
diff --git a/src/game/editor/auto_map.cpp b/src/game/editor/auto_map.cpp
new file mode 100644
index 00000000..528e459b
--- /dev/null
+++ b/src/game/editor/auto_map.cpp
@@ -0,0 +1,202 @@
+#include <stdio.h>	// sscanf
+
+#include <engine/console.h>
+#include <engine/storage.h>
+#include <engine/shared/linereader.h>
+
+#include "auto_map.h"
+#include "editor.h"
+
+CAutoMapper::CAutoMapper(CEditor *pEditor)
+{
+	m_pEditor = pEditor;
+	m_FileLoaded = false;
+}
+
+void CAutoMapper::Load(const char* pTileName)
+{
+	char aPath[256];
+	str_format(aPath, sizeof(aPath), "editor/%s.rules", pTileName);
+	IOHANDLE RulesFile = m_pEditor->Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_ALL);
+	if(!RulesFile)
+		return;
+	
+	CLineReader LineReader;
+	LineReader.Init(RulesFile);
+		
+	CConfiguration *pCurrentConf = 0;
+	CIndexRule *pCurrentIndex = 0;
+		
+	char aBuf[256];
+		
+	// read each line
+	while(char *pLine = LineReader.Get())
+	{
+		// skip blank/empty lines as well as comments
+		if(str_length(pLine) > 0 && pLine[0] != '#' && pLine[0] != '\n' && pLine[0] != '\r'
+			&& pLine[0] != '\t' && pLine[0] != '\v' && pLine[0] != ' ')
+		{
+			if(pLine[0]== '[')
+			{
+				// new configuration, get the name
+				pLine++;
+					
+				CConfiguration NewConf;
+				int ID = m_lConfigs.add(NewConf);
+				pCurrentConf = &m_lConfigs[ID];
+					
+				str_copy(pCurrentConf->m_aName, pLine, str_length(pLine));
+			}
+			else
+			{
+				if(!str_comp_num(pLine, "Index", 5))
+				{
+					// new index
+					int ID = 0;
+					char aFlip[128] = "";
+						
+					sscanf(pLine, "Index %d %127s", &ID, aFlip);
+						
+					CIndexRule NewIndexRule;
+					NewIndexRule.m_ID = ID;
+					NewIndexRule.m_Flag = 0;
+					NewIndexRule.m_RandomValue = 0;
+					NewIndexRule.m_BaseTile = false;
+						
+					if(str_length(aFlip) > 0)
+					{
+						if(!str_comp(aFlip, "XFLIP"))
+							NewIndexRule.m_Flag = TILEFLAG_VFLIP;
+						else if(!str_comp(aFlip, "YFLIP"))
+							NewIndexRule.m_Flag = TILEFLAG_HFLIP;
+					}
+						
+					// add the index rule object and make it current
+					int ArrayID = pCurrentConf->m_aIndexRules.add(NewIndexRule);
+					pCurrentIndex = &pCurrentConf->m_aIndexRules[ArrayID];
+				}
+				else if(!str_comp_num(pLine, "BaseTile", 8) && pCurrentIndex)
+				{
+					pCurrentIndex->m_BaseTile = true;
+				}
+				else if(!str_comp_num(pLine, "Pos", 3) && pCurrentIndex)
+				{
+					int x = 0, y = 0;
+					char aValue[128];
+					int Value = CPosRule::EMPTY;
+					bool IndexValue = false;
+						
+					sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue);
+						
+					if(!str_comp(aValue, "FULL"))
+						Value = CPosRule::FULL;
+					else if(!str_comp_num(aValue, "INDEX", 5))
+					{
+						sscanf(pLine, "Pos %*d %*d INDEX %d", &Value);
+						IndexValue = true;
+					}
+
+					CPosRule NewPosRule = {x, y, Value, IndexValue};
+					pCurrentIndex->m_aRules.add(NewPosRule);
+				}
+				else if(!str_comp_num(pLine, "Random", 6) && pCurrentIndex)
+				{
+					sscanf(pLine, "Random %d", &pCurrentIndex->m_RandomValue);
+				}
+			}
+		}
+	}
+		
+	io_close(RulesFile);
+		
+	str_format(aBuf, sizeof(aBuf),"loaded %s", aPath);
+	m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf);
+		
+	m_FileLoaded = true;
+}
+
+const char* CAutoMapper::GetConfigName(int Index)
+{
+	if(Index < 0 || Index >= m_lConfigs.size())
+		return "";
+
+	return m_lConfigs[Index].m_aName;
+}
+
+void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID)
+{
+	if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size())
+		return;
+	
+	CConfiguration *pConf = &m_lConfigs[ConfigID];
+	
+	if(!pConf->m_aIndexRules.size())
+		return;
+	
+	int BaseTile = 1;
+	
+	// find base tile if there is one
+	for(int i = 0; i < pConf->m_aIndexRules.size(); ++i)
+	{
+		if(pConf->m_aIndexRules[i].m_BaseTile)
+		{
+			BaseTile = pConf->m_aIndexRules[i].m_ID;
+			break;
+		}
+	}
+	
+	// auto map !
+	int MaxIndex = pLayer->m_Width*pLayer->m_Height;
+	for(int y = 0; y < pLayer->m_Height; y++)
+		for(int x = 0; x < pLayer->m_Width; x++)
+		{
+			CTile *pTile = &(pLayer->m_pTiles[y*pLayer->m_Width+x]);
+			if(pTile->m_Index == 0)
+				continue;
+
+			pTile->m_Index = BaseTile;
+			m_pEditor->m_Map.m_Modified = true;
+
+			if(y == 0 || y == pLayer->m_Height-1 || x == 0 || x == pLayer->m_Width-1)
+				continue;
+				
+			for(int i = 0; i < pConf->m_aIndexRules.size(); ++i)
+			{
+				if(pConf->m_aIndexRules[i].m_BaseTile)
+					continue;
+
+				bool RespectRules = true;
+				for(int j = 0; j < pConf->m_aIndexRules[i].m_aRules.size() && RespectRules; ++j)
+				{
+					CPosRule *pRule = &pConf->m_aIndexRules[i].m_aRules[j];
+					int CheckIndex = (y+pRule->m_Y)*pLayer->m_Width+(x+pRule->m_X);
+							
+					if(CheckIndex < 0 || CheckIndex >= MaxIndex)
+						RespectRules = false;
+					else
+					{
+ 						if(pRule->m_IndexValue)
+						{
+							if(pLayer->m_pTiles[CheckIndex].m_Index != pRule->m_Value)
+								RespectRules = false;
+						}
+						else
+						{
+							if(pLayer->m_pTiles[CheckIndex].m_Index > 0 && pRule->m_Value == CPosRule::EMPTY)
+								RespectRules = false;
+									
+							if(pLayer->m_pTiles[CheckIndex].m_Index == 0 && pRule->m_Value == CPosRule::FULL)
+								RespectRules = false;
+						}
+					}
+				}
+					
+				if(RespectRules &&
+					(pConf->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pConf->m_aIndexRules[i].m_RandomValue)  == 1))
+				{
+					pTile->m_Index = pConf->m_aIndexRules[i].m_ID;
+					pTile->m_Flags = pConf->m_aIndexRules[i].m_Flag;
+				}
+			}
+		}
+}
diff --git a/src/game/editor/auto_map.h b/src/game/editor/auto_map.h
new file mode 100644
index 00000000..4f4cf92e
--- /dev/null
+++ b/src/game/editor/auto_map.h
@@ -0,0 +1,54 @@
+#ifndef GAME_EDITOR_ED_AUTO_MAP_H
+#define GAME_EDITOR_ED_AUTO_MAP_H
+
+#include <base/tl/array.h>
+
+class CAutoMapper
+{
+	struct CPosRule
+	{
+		int m_X;
+		int m_Y;
+		int m_Value;
+		bool m_IndexValue;
+		
+		enum
+		{
+			EMPTY=0,
+			FULL
+		};
+	};
+
+	struct CIndexRule
+	{
+		int m_ID;
+		array<CPosRule> m_aRules;
+		int m_Flag;
+		int m_RandomValue;
+		bool m_BaseTile;
+	};
+
+	struct CConfiguration
+	{
+		array<CIndexRule> m_aIndexRules;
+		char m_aName[128];
+	};
+	
+public:
+	CAutoMapper(class CEditor *pEditor);
+	
+	void Load(const char* pTileName);
+	void Proceed(class CLayerTiles *pLayer, int ConfigID);
+
+	int ConfigNamesNum() { return m_lConfigs.size(); }
+	const char* GetConfigName(int Index);
+	
+	const bool IsLoaded() { return m_FileLoaded; }
+private:
+	array<CConfiguration> m_lConfigs;
+	class CEditor *m_pEditor;
+	bool m_FileLoaded;
+};
+
+
+#endif
diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp
index bc00c4a2..907552dc 100644
--- a/src/game/editor/editor.cpp
+++ b/src/game/editor/editor.cpp
@@ -8,20 +8,20 @@
 #include <engine/client.h>
 #include <engine/console.h>
 #include <engine/graphics.h>
-#include <engine/textrender.h>
 #include <engine/input.h>
 #include <engine/keys.h>
 #include <engine/storage.h>
+#include <engine/textrender.h>
 
-#include <game/client/ui.h>
 #include <game/gamecore.h>
+#include <game/localization.h>
+#include <game/client/lineinput.h>
 #include <game/client/render.h>
+#include <game/client/ui.h>
 #include <game/generated/client_data.h>
 
+#include "auto_map.h"
 #include "editor.h"
-#include <game/client/lineinput.h>
-
-#include <game/localization.h>
 
 int CEditor::ms_CheckerTexture;
 int CEditor::ms_BackgroundTexture;
@@ -1899,6 +1899,7 @@ void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser)
 	*pImg = ImgInfo;
 	pImg->m_External = External;
 	pEditor->ExtractName(pFileName, pImg->m_aName, sizeof(pImg->m_aName));
+	pImg->m_AutoMapper.Load(pImg->m_aName);
 	pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
 	pEditor->SortImages();
 	for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i)
@@ -1930,6 +1931,7 @@ void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
 	pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
 	pImg->m_External = 1;	// external by default
 	str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName));
+	pImg->m_AutoMapper.Load(pImg->m_aName);
 	pEditor->m_Map.m_lImages.add(pImg);
 	pEditor->SortImages();
 	if(pEditor->m_SelectedImage > -1 && pEditor->m_SelectedImage < pEditor->m_Map.m_lImages.size())
diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h
index c7779954..353b0774 100644
--- a/src/game/editor/editor.h
+++ b/src/game/editor/editor.h
@@ -3,23 +3,26 @@
 #ifndef GAME_EDITOR_EDITOR_H
 #define GAME_EDITOR_EDITOR_H
 
-#include <base/system.h>
+#include <math.h>
+
 #include <base/math.h>
-#include <base/tl/array.h>
+#include <base/system.h>
+
 #include <base/tl/algorithm.h>
+#include <base/tl/array.h>
 #include <base/tl/sorted_array.h>
 #include <base/tl/string.h>
 
-#include <math.h>
+#include <game/client/ui.h>
 #include <game/mapitems.h>
 #include <game/client/render.h>
 
-#include <engine/shared/datafile.h>
 #include <engine/shared/config.h>
+#include <engine/shared/datafile.h>
 #include <engine/editor.h>
 #include <engine/graphics.h>
 
-#include <game/client/ui.h>
+#include "auto_map.h"
 
 typedef void (*INDEX_MODIFY_FUNC)(int *pIndex);
 
@@ -230,6 +233,7 @@ public:
 	CEditor *m_pEditor;
 
 	CEditorImage(CEditor *pEditor)
+	: m_AutoMapper(pEditor)
 	{
 		m_pEditor = pEditor;
 		m_TexID = -1;
@@ -249,6 +253,7 @@ public:
 	int m_External;
 	char m_aName[128];
 	unsigned char m_aTileFlags[256];
+	class CAutoMapper m_AutoMapper;
 };
 
 class CEditorMap
@@ -684,6 +689,7 @@ public:
 	static int PopupSelectGametileOp(CEditor *pEditor, CUIRect View);
 	static int PopupImage(CEditor *pEditor, CUIRect View);
 	static int PopupMenuFile(CEditor *pEditor, CUIRect View);
+	static int PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View);
 
 	static void CallbackOpenMap(const char *pFileName, int StorageType, void *pUser);
 	static void CallbackAppendMap(const char *pFileName, int StorageType, void *pUser);
@@ -694,6 +700,9 @@ public:
 
 	void PopupSelectGametileOpInvoke(float x, float y);
 	int PopupSelectGameTileOpResult();
+	
+	void PopupSelectConfigAutoMapInvoke(float x, float y);
+	int PopupSelectConfigAutoMapResult();
 
 	vec4 ButtonColorMul(const void *pID);
 
diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp
index 7207e49f..987404b8 100644
--- a/src/game/editor/io.cpp
+++ b/src/game/editor/io.cpp
@@ -449,6 +449,9 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 				if(pName)
 					str_copy(pImg->m_aName, pName, 128);
 
+				// load auto mapper file
+				pImg->m_AutoMapper.Load(pImg->m_aName);
+
 				m_lImages.add(pImg);
 
 				// unload image
diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp
index b792eda9..81944636 100644
--- a/src/game/editor/layer_tiles.cpp
+++ b/src/game/editor/layer_tiles.cpp
@@ -360,14 +360,32 @@ void CLayerTiles::ShowInfo()
 int CLayerTiles::RenderProperties(CUIRect *pToolBox)
 {
 	CUIRect Button;
-	pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
-
+	
 	bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty();
-	if(m_pEditor->m_Map.m_pGameLayer == this)
+	if(m_pEditor->m_Map.m_pGameLayer != this)
+	{
+		if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size() && m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.IsLoaded())
+		{
+			static int s_AutoMapperButton = 0;
+			pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
+			if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Auto map", 0, &Button, 0, ""))
+				m_pEditor->PopupSelectConfigAutoMapInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY());
+			
+			int Result = m_pEditor->PopupSelectConfigAutoMapResult();
+			if(Result > -1)
+			{
+				m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.Proceed(this, Result);
+				return 1;
+			}
+		}
+	}
+	else
 		InGameGroup = false;
 
 	if(InGameGroup)
 	{
+		pToolBox->HSplitBottom(2.0f, pToolBox, 0);
+		pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
 		static int s_ColclButton = 0;
 		if(m_pEditor->DoButton_Editor(&s_ColclButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer"))
 			m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY());
diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp
index 3ae29725..0a691fdf 100644
--- a/src/game/editor/popups.cpp
+++ b/src/game/editor/popups.cpp
@@ -1,10 +1,14 @@
 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
+
+#include <base/tl/array.h>
+
 #include <engine/console.h>
 #include <engine/graphics.h>
 #include <engine/input.h>
 #include <engine/keys.h>
 #include <engine/storage.h>
+
 #include "editor.h"
 
 
@@ -737,3 +741,43 @@ int CEditor::PopupSelectGameTileOpResult()
 	s_GametileOpSelected = -1;
 	return Result;
 }
+
+static int s_AutoMapConfigSelected = -1;
+
+int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View)
+{
+	CLayerTiles *pLayer = static_cast<CLayerTiles*>(pEditor->GetSelectedLayer(0));
+	CUIRect Button;
+	static int s_AutoMapperConfigButtons[256];
+	CAutoMapper *pAutoMapper = &pEditor->m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper;
+	
+	for(int i = 0; i < pAutoMapper->ConfigNamesNum(); ++i)
+	{
+		View.HSplitTop(2.0f, 0, &View);
+		View.HSplitTop(12.0f, &Button, &View);
+		if(pEditor->DoButton_Editor(&s_AutoMapperConfigButtons[i], pAutoMapper->GetConfigName(i), 0, &Button, 0, 0))
+			s_AutoMapConfigSelected = i;
+	}
+
+	return 0;
+}
+
+void CEditor::PopupSelectConfigAutoMapInvoke(float x, float y)
+{
+	static int s_AutoMapConfigSelectID = 0;
+	s_AutoMapConfigSelected = -1;
+	CLayerTiles *pLayer = static_cast<CLayerTiles*>(GetSelectedLayer(0));
+	if(pLayer && pLayer->m_Image >= 0 && pLayer->m_Image < m_Map.m_lImages.size() &&
+		m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum())
+		UiInvokePopupMenu(&s_AutoMapConfigSelectID, 0, x, y, 120.0f, 12.0f+14.0f*m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum(), PopupSelectConfigAutoMap);
+}
+
+int CEditor::PopupSelectConfigAutoMapResult()
+{
+	if(s_AutoMapConfigSelected < 0)
+		return -1;
+	
+	int Result = s_AutoMapConfigSelected;
+	s_AutoMapConfigSelected = -1;
+	return Result;
+}