ddnet/src/game/editor/auto_map.cpp

542 lines
15 KiB
C++
Raw Normal View History

2022-02-14 23:22:52 +00:00
#include <cinttypes>
#include <cstdio> // sscanf
#include <engine/console.h>
#include <engine/shared/linereader.h>
#include <engine/storage.h>
#include "auto_map.h"
#include "editor.h"
// Based on triple32inc from https://github.com/skeeto/hash-prospector/tree/79a6074062a84907df6e45b756134b74e2956760
static uint32_t HashUInt32(uint32_t Num)
{
Num++;
Num ^= Num >> 17;
Num *= 0xed5ad4bbu;
Num ^= Num >> 11;
Num *= 0xac4c1b51u;
Num ^= Num >> 15;
Num *= 0x31848babu;
Num ^= Num >> 14;
return Num;
}
#define HASH_MAX 65536
static int HashLocation(uint32_t Seed, uint32_t Run, uint32_t Rule, uint32_t X, uint32_t Y)
{
const uint32_t Prime = 31;
uint32_t Hash = 1;
Hash = Hash * Prime + HashUInt32(Seed);
Hash = Hash * Prime + HashUInt32(Run);
Hash = Hash * Prime + HashUInt32(Rule);
Hash = Hash * Prime + HashUInt32(X);
Hash = Hash * Prime + HashUInt32(Y);
Hash = HashUInt32(Hash * Prime); // Just to double-check that values are well-distributed
return Hash % HASH_MAX;
}
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 | IOFLAG_SKIP_BOM, IStorage::TYPE_ALL);
if(!RulesFile)
return;
2011-08-11 08:59:14 +00:00
CLineReader LineReader;
LineReader.Init(RulesFile);
2011-08-11 08:59:14 +00:00
CConfiguration *pCurrentConf = 0;
2015-02-19 23:15:09 +00:00
CRun *pCurrentRun = 0;
CIndexRule *pCurrentIndex = 0;
2011-08-11 08:59:14 +00:00
char aBuf[256];
2011-08-11 08:59:14 +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++;
CConfiguration NewConf;
NewConf.m_aName[0] = '\0';
NewConf.m_StartX = 0;
NewConf.m_StartY = 0;
NewConf.m_EndX = 0;
NewConf.m_EndY = 0;
2015-02-19 23:15:09 +00:00
int ConfigurationID = m_lConfigs.add(NewConf);
pCurrentConf = &m_lConfigs[ConfigurationID];
str_copy(pCurrentConf->m_aName, pLine, str_length(pLine));
2015-02-19 23:15:09 +00:00
// add start run
CRun NewRun;
2018-07-19 15:09:29 +00:00
NewRun.m_AutomapCopy = true;
2015-02-19 23:15:09 +00:00
int RunID = pCurrentConf->m_aRuns.add(NewRun);
pCurrentRun = &pCurrentConf->m_aRuns[RunID];
}
else if(str_startswith(pLine, "NewRun") && pCurrentConf)
{
2015-02-19 23:15:09 +00:00
// add new run
CRun NewRun;
2018-07-19 15:09:29 +00:00
NewRun.m_AutomapCopy = true;
2015-02-19 23:15:09 +00:00
int RunID = pCurrentConf->m_aRuns.add(NewRun);
pCurrentRun = &pCurrentConf->m_aRuns[RunID];
}
else if(str_startswith(pLine, "Index") && pCurrentRun)
2015-02-19 23:15:09 +00:00
{
// new index
int ID = 0;
char aOrientation1[128] = "";
char aOrientation2[128] = "";
char aOrientation3[128] = "";
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
sscanf(pLine, "Index %d %127s %127s %127s", &ID, aOrientation1, aOrientation2, aOrientation3);
2013-12-27 17:32:58 +00:00
2015-02-19 23:15:09 +00:00
CIndexRule NewIndexRule;
NewIndexRule.m_ID = ID;
NewIndexRule.m_Flag = 0;
2019-07-08 21:08:42 +00:00
NewIndexRule.m_RandomProbability = 1.0f;
2015-02-19 23:15:09 +00:00
NewIndexRule.m_DefaultRule = true;
2019-04-26 19:36:49 +00:00
NewIndexRule.m_SkipEmpty = false;
2018-08-11 01:01:25 +00:00
NewIndexRule.m_SkipFull = false;
2014-09-27 08:11:28 +00:00
2015-02-19 23:15:09 +00:00
if(str_length(aOrientation1) > 0)
{
if(!str_comp(aOrientation1, "XFLIP"))
NewIndexRule.m_Flag |= TILEFLAG_VFLIP;
else if(!str_comp(aOrientation1, "YFLIP"))
NewIndexRule.m_Flag |= TILEFLAG_HFLIP;
else if(!str_comp(aOrientation1, "ROTATE"))
NewIndexRule.m_Flag |= TILEFLAG_ROTATE;
}
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
if(str_length(aOrientation2) > 0)
{
if(!str_comp(aOrientation2, "XFLIP"))
NewIndexRule.m_Flag |= TILEFLAG_VFLIP;
else if(!str_comp(aOrientation2, "YFLIP"))
NewIndexRule.m_Flag |= TILEFLAG_HFLIP;
else if(!str_comp(aOrientation2, "ROTATE"))
NewIndexRule.m_Flag |= TILEFLAG_ROTATE;
}
2015-02-19 23:15:09 +00:00
if(str_length(aOrientation3) > 0)
{
2015-02-19 23:15:09 +00:00
if(!str_comp(aOrientation3, "XFLIP"))
NewIndexRule.m_Flag |= TILEFLAG_VFLIP;
else if(!str_comp(aOrientation3, "YFLIP"))
NewIndexRule.m_Flag |= TILEFLAG_HFLIP;
else if(!str_comp(aOrientation3, "ROTATE"))
NewIndexRule.m_Flag |= TILEFLAG_ROTATE;
}
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
// add the index rule object and make it current
int IndexRuleID = pCurrentRun->m_aIndexRules.add(NewIndexRule);
pCurrentIndex = &pCurrentRun->m_aIndexRules[IndexRuleID];
}
else if(str_startswith(pLine, "Pos") && pCurrentIndex)
2015-02-19 23:15:09 +00:00
{
int x = 0, y = 0;
char aValue[128];
int Value = CPosRule::NORULE;
array<CIndexInfo> NewIndexList;
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue);
2015-02-19 21:54:47 +00:00
2015-02-19 23:15:09 +00:00
if(!str_comp(aValue, "EMPTY"))
{
Value = CPosRule::INDEX;
2018-08-09 21:45:04 +00:00
CIndexInfo NewIndexInfo = {0, 0, false};
NewIndexList.add(NewIndexInfo);
2015-02-19 23:15:09 +00:00
}
else if(!str_comp(aValue, "FULL"))
{
Value = CPosRule::NOTINDEX;
2018-08-09 21:45:04 +00:00
CIndexInfo NewIndexInfo1 = {0, 0, false};
//CIndexInfo NewIndexInfo2 = {-1, 0};
NewIndexList.add(NewIndexInfo1);
//NewIndexList.add(NewIndexInfo2);
2015-02-19 23:15:09 +00:00
}
else if(!str_comp(aValue, "INDEX") || !str_comp(aValue, "NOTINDEX"))
{
if(!str_comp(aValue, "INDEX"))
Value = CPosRule::INDEX;
else
Value = CPosRule::NOTINDEX;
int pWord = 4;
while(true)
{
2015-02-19 23:15:09 +00:00
int ID = 0;
char aOrientation1[128] = "";
char aOrientation2[128] = "";
char aOrientation3[128] = "";
char aOrientation4[128] = "";
sscanf(str_trim_words(pLine, pWord), "%d %127s %127s %127s %127s", &ID, aOrientation1, aOrientation2, aOrientation3, aOrientation4);
CIndexInfo NewIndexInfo;
NewIndexInfo.m_ID = ID;
2018-08-09 21:45:04 +00:00
NewIndexInfo.m_Flag = 0;
NewIndexInfo.m_TestFlag = false;
2015-02-19 23:15:09 +00:00
if(!str_comp(aOrientation1, "OR"))
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
pWord += 2;
continue;
}
else if(str_length(aOrientation1) > 0)
{
2018-08-09 21:45:04 +00:00
NewIndexInfo.m_TestFlag = true;
2015-02-19 23:15:09 +00:00
if(!str_comp(aOrientation1, "XFLIP"))
2018-07-26 12:49:43 +00:00
NewIndexInfo.m_Flag = TILEFLAG_VFLIP;
2015-02-19 23:15:09 +00:00
else if(!str_comp(aOrientation1, "YFLIP"))
2018-07-26 12:49:43 +00:00
NewIndexInfo.m_Flag = TILEFLAG_HFLIP;
2015-02-19 23:15:09 +00:00
else if(!str_comp(aOrientation1, "ROTATE"))
2018-07-26 12:49:43 +00:00
NewIndexInfo.m_Flag = TILEFLAG_ROTATE;
2018-07-19 15:09:29 +00:00
else if(!str_comp(aOrientation1, "NONE"))
NewIndexInfo.m_Flag = 0;
2018-08-09 21:45:04 +00:00
else
NewIndexInfo.m_TestFlag = false;
}
else
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
break;
}
2015-02-19 21:54:47 +00:00
if(!str_comp(aOrientation2, "OR"))
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
pWord += 3;
continue;
}
else if(str_length(aOrientation2) > 0 && NewIndexInfo.m_Flag != 0)
{
2015-02-19 23:15:09 +00:00
if(!str_comp(aOrientation2, "XFLIP"))
NewIndexInfo.m_Flag |= TILEFLAG_VFLIP;
else if(!str_comp(aOrientation2, "YFLIP"))
NewIndexInfo.m_Flag |= TILEFLAG_HFLIP;
else if(!str_comp(aOrientation2, "ROTATE"))
NewIndexInfo.m_Flag |= TILEFLAG_ROTATE;
}
else
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
break;
}
2015-02-19 21:54:47 +00:00
if(!str_comp(aOrientation3, "OR"))
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
pWord += 4;
continue;
}
else if(str_length(aOrientation3) > 0 && NewIndexInfo.m_Flag != 0)
{
2015-02-19 23:15:09 +00:00
if(!str_comp(aOrientation3, "XFLIP"))
NewIndexInfo.m_Flag |= TILEFLAG_VFLIP;
else if(!str_comp(aOrientation3, "YFLIP"))
NewIndexInfo.m_Flag |= TILEFLAG_HFLIP;
else if(!str_comp(aOrientation3, "ROTATE"))
NewIndexInfo.m_Flag |= TILEFLAG_ROTATE;
}
else
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
break;
2015-02-19 21:54:47 +00:00
}
if(!str_comp(aOrientation4, "OR"))
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
pWord += 5;
continue;
}
else
{
2015-02-19 23:15:09 +00:00
NewIndexList.add(NewIndexInfo);
break;
}
2015-02-19 21:54:47 +00:00
}
}
2015-02-19 23:15:09 +00:00
if(Value != CPosRule::NORULE)
{
2015-02-19 23:15:09 +00:00
CPosRule NewPosRule = {x, y, Value, NewIndexList};
pCurrentIndex->m_aRules.add(NewPosRule);
2018-08-11 01:01:25 +00:00
2019-04-26 19:36:49 +00:00
pCurrentConf->m_StartX = minimum(pCurrentConf->m_StartX, NewPosRule.m_X);
pCurrentConf->m_StartY = minimum(pCurrentConf->m_StartY, NewPosRule.m_Y);
pCurrentConf->m_EndX = maximum(pCurrentConf->m_EndX, NewPosRule.m_X);
pCurrentConf->m_EndY = maximum(pCurrentConf->m_EndY, NewPosRule.m_Y);
if(x == 0 && y == 0)
{
2019-04-26 19:36:49 +00:00
for(int i = 0; i < NewIndexList.size(); ++i)
{
if(Value == CPosRule::INDEX && NewIndexList[i].m_ID == 0)
pCurrentIndex->m_SkipFull = true;
else
pCurrentIndex->m_SkipEmpty = true;
}
2018-08-11 01:01:25 +00:00
}
}
}
else if(str_startswith(pLine, "Random") && pCurrentIndex)
2015-02-19 23:15:09 +00:00
{
float Value;
char Specifier = ' ';
sscanf(pLine, "Random %f%c", &Value, &Specifier);
if(Specifier == '%')
{
2019-07-08 21:08:42 +00:00
pCurrentIndex->m_RandomProbability = Value / 100.0f;
}
else
{
2019-07-08 21:08:42 +00:00
pCurrentIndex->m_RandomProbability = 1.0f / Value;
}
2015-02-19 23:15:09 +00:00
}
else if(str_startswith(pLine, "NoDefaultRule") && pCurrentIndex)
2015-02-19 23:15:09 +00:00
{
pCurrentIndex->m_DefaultRule = false;
}
else if(str_startswith(pLine, "NoLayerCopy") && pCurrentRun)
2018-07-19 15:09:29 +00:00
{
pCurrentRun->m_AutomapCopy = false;
}
}
}
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
for(int g = 0; g < m_lConfigs.size(); ++g)
2013-12-28 00:09:47 +00:00
{
for(int h = 0; h < m_lConfigs[g].m_aRuns.size(); ++h)
2013-12-28 00:09:47 +00:00
{
2015-02-19 23:15:09 +00:00
for(int i = 0; i < m_lConfigs[g].m_aRuns[h].m_aIndexRules.size(); ++i)
2013-12-28 00:09:47 +00:00
{
2018-08-11 01:01:25 +00:00
CIndexRule *pIndexRule = &m_lConfigs[g].m_aRuns[h].m_aIndexRules[i];
2015-02-19 23:15:09 +00:00
bool Found = false;
2018-08-11 01:01:25 +00:00
for(int j = 0; j < pIndexRule->m_aRules.size(); ++j)
2013-12-28 12:59:14 +00:00
{
2018-08-11 01:01:25 +00:00
CPosRule *pRule = &pIndexRule->m_aRules[j];
2015-02-19 23:15:09 +00:00
if(pRule && pRule->m_X == 0 && pRule->m_Y == 0)
{
Found = true;
break;
}
}
2018-08-11 01:01:25 +00:00
if(!Found && pIndexRule->m_DefaultRule)
2015-02-19 23:15:09 +00:00
{
array<CIndexInfo> NewIndexList;
2018-08-09 21:45:04 +00:00
CIndexInfo NewIndexInfo = {0, 0, false};
NewIndexList.add(NewIndexInfo);
CPosRule NewPosRule = {0, 0, CPosRule::NOTINDEX, NewIndexList};
2019-04-26 19:36:49 +00:00
pIndexRule->m_aRules.add(NewPosRule);
pIndexRule->m_SkipEmpty = true;
pIndexRule->m_SkipFull = false;
}
if(pIndexRule->m_SkipEmpty && pIndexRule->m_SkipFull)
{
pIndexRule->m_SkipEmpty = false;
2018-08-11 01:01:25 +00:00
pIndexRule->m_SkipFull = false;
2013-12-28 12:59:14 +00:00
}
2013-12-28 00:09:47 +00:00
}
}
}
io_close(RulesFile);
2011-08-11 08:59:14 +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
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::ProceedLocalized(CLayerTiles *pLayer, int ConfigID, int Seed, int X, int Y, int Width, int Height)
{
if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size())
return;
if(Width < 0)
Width = pLayer->m_Width;
if(Height < 0)
Height = pLayer->m_Height;
CConfiguration *pConf = &m_lConfigs[ConfigID];
2019-01-10 14:39:11 +00:00
int CommitFromX = clamp(X + pConf->m_StartX, 0, pLayer->m_Width);
int CommitFromY = clamp(Y + pConf->m_StartY, 0, pLayer->m_Height);
int CommitToX = clamp(X + Width + pConf->m_EndX, 0, pLayer->m_Width);
int CommitToY = clamp(Y + Height + pConf->m_EndY, 0, pLayer->m_Height);
int UpdateFromX = clamp(X + 3 * pConf->m_StartX, 0, pLayer->m_Width);
int UpdateFromY = clamp(Y + 3 * pConf->m_StartY, 0, pLayer->m_Height);
int UpdateToX = clamp(X + Width + 3 * pConf->m_EndX, 0, pLayer->m_Width);
int UpdateToY = clamp(Y + Height + 3 * pConf->m_EndY, 0, pLayer->m_Height);
CLayerTiles *pUpdateLayer = new CLayerTiles(UpdateToX - UpdateFromX, UpdateToY - UpdateFromY);
for(int y = UpdateFromY; y < UpdateToY; y++)
{
for(int x = UpdateFromX; x < UpdateToX; x++)
{
CTile *in = &pLayer->m_pTiles[y * pLayer->m_Width + x];
CTile *out = &pUpdateLayer->m_pTiles[(y - UpdateFromY) * pUpdateLayer->m_Width + x - UpdateFromX];
out->m_Index = in->m_Index;
out->m_Flags = in->m_Flags;
}
}
Proceed(pUpdateLayer, ConfigID, Seed, UpdateFromX, UpdateFromY);
for(int y = CommitFromY; y < CommitToY; y++)
{
for(int x = CommitFromX; x < CommitToX; x++)
{
CTile *in = &pUpdateLayer->m_pTiles[(y - UpdateFromY) * pUpdateLayer->m_Width + x - UpdateFromX];
CTile *out = &pLayer->m_pTiles[y * pLayer->m_Width + x];
out->m_Index = in->m_Index;
out->m_Flags = in->m_Flags;
}
}
delete pUpdateLayer;
}
void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID, int Seed, int SeedOffsetX, int SeedOffsetY)
{
if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size())
return;
2011-08-11 08:59:14 +00:00
if(Seed == 0)
Seed = rand();
CConfiguration *pConf = &m_lConfigs[ConfigID];
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
// for every run: copy tiles, automap, overwrite tiles
for(int h = 0; h < pConf->m_aRuns.size(); ++h)
{
2015-02-19 23:15:09 +00:00
CRun *pRun = &pConf->m_aRuns[h];
2013-12-28 00:09:47 +00:00
2018-07-26 16:26:12 +00:00
// don't make copy if it's requested
2018-07-26 16:59:29 +00:00
CLayerTiles *pReadLayer;
if(pRun->m_AutomapCopy)
2018-07-26 20:58:05 +00:00
{
2018-07-26 16:26:12 +00:00
pReadLayer = new CLayerTiles(pLayer->m_Width, pLayer->m_Height);
2013-12-28 00:09:47 +00:00
for(int y = 0; y < pLayer->m_Height; y++)
{
2018-07-26 16:26:12 +00:00
for(int x = 0; x < pLayer->m_Width; x++)
{
CTile *in = &pLayer->m_pTiles[y * pLayer->m_Width + x];
CTile *out = &pReadLayer->m_pTiles[y * pLayer->m_Width + x];
2018-07-26 16:26:12 +00:00
out->m_Index = in->m_Index;
out->m_Flags = in->m_Flags;
}
2015-02-19 23:15:09 +00:00
}
2013-12-28 00:09:47 +00:00
}
else
{
pReadLayer = pLayer;
}
2013-12-28 00:09:47 +00:00
2015-02-19 23:15:09 +00:00
// auto map
for(int y = 0; y < pLayer->m_Height; y++)
{
2015-02-19 23:15:09 +00:00
for(int x = 0; x < pLayer->m_Width; x++)
{
CTile *pTile = &(pLayer->m_pTiles[y * pLayer->m_Width + x]);
2015-02-19 23:15:09 +00:00
m_pEditor->m_Map.m_Modified = true;
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
for(int i = 0; i < pRun->m_aIndexRules.size(); ++i)
{
2019-04-26 19:36:49 +00:00
CIndexRule *pIndexRule = &pRun->m_aIndexRules[i];
if(pIndexRule->m_SkipEmpty && pTile->m_Index == 0) // skip empty tiles
continue;
if(pIndexRule->m_SkipFull && pTile->m_Index != 0) // skip full tiles
2018-08-11 01:01:25 +00:00
continue;
2015-02-19 23:15:09 +00:00
bool RespectRules = true;
2018-08-11 01:01:25 +00:00
for(int j = 0; j < pIndexRule->m_aRules.size() && RespectRules; ++j)
{
2018-08-11 01:01:25 +00:00
CPosRule *pRule = &pIndexRule->m_aRules[j];
int CheckIndex, CheckFlags;
int CheckX = x + pRule->m_X;
int CheckY = y + pRule->m_Y;
if(CheckX >= 0 && CheckX < pLayer->m_Width && CheckY >= 0 && CheckY < pLayer->m_Height)
{
int CheckTile = CheckY * pLayer->m_Width + CheckX;
2018-07-26 20:58:05 +00:00
CheckIndex = pReadLayer->m_pTiles[CheckTile].m_Index;
CheckFlags = pReadLayer->m_pTiles[CheckTile].m_Flags & (TILEFLAG_ROTATE | TILEFLAG_VFLIP | TILEFLAG_HFLIP);
}
else
{
CheckIndex = -1;
CheckFlags = 0;
}
2015-07-09 00:08:14 +00:00
if(pRule->m_Value == CPosRule::INDEX)
2015-02-19 21:54:47 +00:00
{
2018-07-27 05:51:16 +00:00
RespectRules = false;
for(int k = 0; k < pRule->m_aIndexList.size(); ++k)
{
if(CheckIndex == pRule->m_aIndexList[k].m_ID && (!pRule->m_aIndexList[k].m_TestFlag || CheckFlags == pRule->m_aIndexList[k].m_Flag))
2018-07-27 05:51:16 +00:00
{
RespectRules = true;
break;
}
2015-02-19 23:15:09 +00:00
}
}
else if(pRule->m_Value == CPosRule::NOTINDEX)
{
for(int k = 0; k < pRule->m_aIndexList.size(); ++k)
{
if(CheckIndex == pRule->m_aIndexList[k].m_ID && (!pRule->m_aIndexList[k].m_TestFlag || CheckFlags == pRule->m_aIndexList[k].m_Flag))
2018-07-27 05:51:16 +00:00
{
RespectRules = false;
break;
}
2015-02-19 21:54:47 +00:00
}
}
}
2011-08-11 08:59:14 +00:00
2015-02-19 23:15:09 +00:00
if(RespectRules &&
2019-07-08 21:08:42 +00:00
(pIndexRule->m_RandomProbability >= 1.0f || HashLocation(Seed, h, i, x + SeedOffsetX, y + SeedOffsetY) < HASH_MAX * pIndexRule->m_RandomProbability))
2015-02-19 23:15:09 +00:00
{
2019-04-26 19:36:49 +00:00
pTile->m_Index = pIndexRule->m_ID;
2018-08-11 01:01:25 +00:00
pTile->m_Flags = pIndexRule->m_Flag;
2015-02-19 23:15:09 +00:00
}
}
}
2013-12-28 00:09:47 +00:00
}
2018-07-26 16:26:12 +00:00
// clean-up
2018-07-26 20:58:05 +00:00
if(pRun->m_AutomapCopy)
2018-07-26 16:26:12 +00:00
delete pReadLayer;
2015-02-19 23:15:09 +00:00
}
}