2011-07-08 23:09:06 +00:00
|
|
|
#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;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
CLineReader LineReader;
|
|
|
|
LineReader.Init(RulesFile);
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
CConfiguration *pCurrentConf = 0;
|
|
|
|
CIndexRule *pCurrentIndex = 0;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
char aBuf[256];
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
// 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++;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
CConfiguration NewConf;
|
|
|
|
int ID = m_lConfigs.add(NewConf);
|
|
|
|
pCurrentConf = &m_lConfigs[ID];
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
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] = "";
|
2013-12-27 17:32:58 +00:00
|
|
|
char aFlip2[128] = "";
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2013-12-27 17:32:58 +00:00
|
|
|
sscanf(pLine, "Index %d %127s %127s", &ID, aFlip, aFlip2);
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
CIndexRule NewIndexRule;
|
|
|
|
NewIndexRule.m_ID = ID;
|
|
|
|
NewIndexRule.m_Flag = 0;
|
|
|
|
NewIndexRule.m_RandomValue = 0;
|
|
|
|
NewIndexRule.m_BaseTile = false;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
if(str_length(aFlip) > 0)
|
|
|
|
{
|
|
|
|
if(!str_comp(aFlip, "XFLIP"))
|
2013-12-27 17:32:58 +00:00
|
|
|
NewIndexRule.m_Flag |= TILEFLAG_VFLIP;
|
2011-07-08 23:09:06 +00:00
|
|
|
else if(!str_comp(aFlip, "YFLIP"))
|
2013-12-27 17:32:58 +00:00
|
|
|
NewIndexRule.m_Flag |= TILEFLAG_HFLIP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(str_length(aFlip2) > 0)
|
|
|
|
{
|
|
|
|
if(!str_comp(aFlip2, "XFLIP"))
|
|
|
|
NewIndexRule.m_Flag |= TILEFLAG_VFLIP;
|
|
|
|
else if(!str_comp(aFlip2, "YFLIP"))
|
|
|
|
NewIndexRule.m_Flag |= TILEFLAG_HFLIP;
|
2011-07-08 23:09:06 +00:00
|
|
|
}
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2013-12-28 00:09:47 +00:00
|
|
|
// add default rule for Pos 0 0 if there is none
|
|
|
|
if(pCurrentIndex)
|
|
|
|
{
|
|
|
|
bool Found = false;
|
|
|
|
for(int i = 0; i < pCurrentIndex->m_aRules.size(); ++i)
|
|
|
|
{
|
|
|
|
CPosRule *pRule = &pCurrentIndex->m_aRules[i];
|
|
|
|
if(pRule->m_X == 0 && pRule->m_Y == 0)
|
|
|
|
{
|
|
|
|
Found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!Found)
|
|
|
|
{
|
|
|
|
CPosRule NewPosRule = {0, 0, CPosRule::FULL, false};
|
|
|
|
pCurrentIndex->m_aRules.add(NewPosRule);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
// 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;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue);
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2013-12-28 00:09:47 +00:00
|
|
|
// add default rule for Pos 0 0 if there is none
|
|
|
|
if(pCurrentIndex)
|
|
|
|
{
|
|
|
|
bool Found = false;
|
|
|
|
for(int i = 0; i < pCurrentIndex->m_aRules.size(); ++i)
|
|
|
|
{
|
|
|
|
CPosRule *pRule = &pCurrentIndex->m_aRules[i];
|
|
|
|
if(pRule->m_X == 0 && pRule->m_Y == 0)
|
|
|
|
{
|
|
|
|
Found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!Found)
|
|
|
|
{
|
|
|
|
CPosRule NewPosRule = {0, 0, CPosRule::FULL, false};
|
|
|
|
pCurrentIndex->m_aRules.add(NewPosRule);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
io_close(RulesFile);
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf),"loaded %s", aPath);
|
|
|
|
m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf);
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
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;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
CConfiguration *pConf = &m_lConfigs[ConfigID];
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
if(!pConf->m_aIndexRules.size())
|
|
|
|
return;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
int BaseTile = 1;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2013-12-28 00:09:47 +00:00
|
|
|
CLayerTiles newLayer(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 *in = &pLayer->m_pTiles[y*pLayer->m_Width+x];
|
|
|
|
CTile *out = &newLayer.m_pTiles[y*pLayer->m_Width+x];
|
|
|
|
out->m_Index = in->m_Index;
|
|
|
|
out->m_Flags = in->m_Flags;
|
|
|
|
}
|
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
// 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++)
|
|
|
|
{
|
2013-12-28 00:09:47 +00:00
|
|
|
CTile *pTile = &(newLayer.m_pTiles[y*pLayer->m_Width+x]);
|
|
|
|
if(pTile->m_Index != 0)
|
|
|
|
pTile->m_Index = BaseTile;
|
2011-07-08 23:09:06 +00:00
|
|
|
m_pEditor->m_Map.m_Modified = true;
|
|
|
|
|
|
|
|
if(y == 0 || y == pLayer->m_Height-1 || x == 0 || x == pLayer->m_Width-1)
|
|
|
|
continue;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
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);
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
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;
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
if(pLayer->m_pTiles[CheckIndex].m_Index == 0 && pRule->m_Value == CPosRule::FULL)
|
|
|
|
RespectRules = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-11 08:59:14 +00:00
|
|
|
|
2011-07-08 23:09:06 +00:00
|
|
|
if(RespectRules &&
|
2011-08-11 08:59:14 +00:00
|
|
|
(pConf->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pConf->m_aIndexRules[i].m_RandomValue) == 1))
|
2011-07-08 23:09:06 +00:00
|
|
|
{
|
|
|
|
pTile->m_Index = pConf->m_aIndexRules[i].m_ID;
|
|
|
|
pTile->m_Flags = pConf->m_aIndexRules[i].m_Flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-28 00:09:47 +00:00
|
|
|
|
|
|
|
for(int y = 0; y < pLayer->m_Height; y++)
|
|
|
|
for(int x = 0; x < pLayer->m_Width; x++)
|
|
|
|
{
|
|
|
|
CTile *in = &newLayer.m_pTiles[y*pLayer->m_Width+x];
|
|
|
|
CTile *out = &pLayer->m_pTiles[y*pLayer->m_Width+x];
|
|
|
|
out->m_Index = in->m_Index;
|
|
|
|
out->m_Flags = in->m_Flags;
|
|
|
|
}
|
2011-07-08 23:09:06 +00:00
|
|
|
}
|