diff --git a/src/base/system.c b/src/base/system.c index 2e256b219..73d50b16e 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -1856,6 +1856,19 @@ int str_format(char *buffer, int buffer_size, const char *format, ...) return ret; } +char *str_trim_words(char *str, int words) +{ + while (words && *str) + { + if (isspace(*str) && !isspace(*(str + 1))) + { + words--; + } + str++; + } + return str; +} + /* makes sure that the string only contains the characters between 32 and 127 */ diff --git a/src/base/system.h b/src/base/system.h index a892b7bc9..a68a29f9c 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -784,6 +784,22 @@ int str_length(const char *str); */ int str_format(char *buffer, int buffer_size, const char *format, ...); +/* + Function: str_trim_words + Trims specific number of words at the start of a string. + + Parameters: + str - String to trim the words from. + words - Count of words to trim. + + Returns: + Trimmed string + + Remarks: + - The strings are treated as zero-termineted strings. +*/ +char *str_trim_words(char *str, int words); + /* Function: str_sanitize_strong Replaces all characters below 32 and above 127 with whitespace. diff --git a/src/game/editor/auto_map.cpp b/src/game/editor/auto_map.cpp index e7857bf29..5448b1265 100644 --- a/src/game/editor/auto_map.cpp +++ b/src/game/editor/auto_map.cpp @@ -25,6 +25,7 @@ void CAutoMapper::Load(const char* pTileName) LineReader.Init(RulesFile); CConfiguration *pCurrentConf = 0; + CRun *pCurrentRun = 0; CIndexRule *pCurrentIndex = 0; char aBuf[256]; @@ -40,116 +41,208 @@ void CAutoMapper::Load(const char* pTileName) { // new configuration, get the name pLine++; - CConfiguration NewConf; - int ID = m_lConfigs.add(NewConf); - pCurrentConf = &m_lConfigs[ID]; - + int ConfigurationID = m_lConfigs.add(NewConf); + pCurrentConf = &m_lConfigs[ConfigurationID]; str_copy(pCurrentConf->m_aName, pLine, str_length(pLine)); + + // add start run + CRun NewRun; + int RunID = pCurrentConf->m_aRuns.add(NewRun); + pCurrentRun = &pCurrentConf->m_aRuns[RunID]; } - else + else if(!str_comp_num(pLine, "NewRun", 6)) { - if(!str_comp_num(pLine, "Index", 5)) + // add new run + CRun NewRun; + int RunID = pCurrentConf->m_aRuns.add(NewRun); + pCurrentRun = &pCurrentConf->m_aRuns[RunID]; + } + else if(!str_comp_num(pLine, "Index", 5)) + { + // new index + int ID = 0; + char aOrientation1[128] = ""; + char aOrientation2[128] = ""; + char aOrientation3[128] = ""; + + sscanf(pLine, "Index %d %127s %127s %127s", &ID, aOrientation1, aOrientation2, aOrientation3); + + CIndexRule NewIndexRule; + NewIndexRule.m_ID = ID; + NewIndexRule.m_Flag = 0; + NewIndexRule.m_RandomValue = 0; + NewIndexRule.m_DefaultRule = true; + + if(str_length(aOrientation1) > 0) { - // new index - int ID = 0; - char aOrientation1[128] = ""; - char aOrientation2[128] = ""; - char aOrientation3[128] = ""; - - sscanf(pLine, "Index %d %127s %127s %127s", &ID, aOrientation1, aOrientation2, aOrientation3); - - CIndexRule NewIndexRule; - NewIndexRule.m_ID = ID; - NewIndexRule.m_Flag = 0; - NewIndexRule.m_RandomValue = 0; - NewIndexRule.m_DefaultRule = true; - - 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; - } - - 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; - } - - if(str_length(aOrientation3) > 0) - { - 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; - } - - // add the index rule object and make it current - int ArrayID = pCurrentConf->m_aIndexRules.add(NewIndexRule); - pCurrentIndex = &pCurrentConf->m_aIndexRules[ArrayID]; + 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; } - else if(!str_comp_num(pLine, "Pos", 3) && pCurrentIndex) + + if(str_length(aOrientation2) > 0) { - int x = 0, y = 0; - char aValue[128]; - int Value = CPosRule::EMPTY; - bool IndexValue = false; + 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; + } - sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue); + if(str_length(aOrientation3) > 0) + { + 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; + } - 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; + // add the index rule object and make it current + int IndexRuleID = pCurrentRun->m_aIndexRules.add(NewIndexRule); + pCurrentIndex = &pCurrentRun->m_aIndexRules[IndexRuleID]; + } + else if(!str_comp_num(pLine, "Pos", 3) && pCurrentIndex) + { + int x = 0, y = 0; + char aValue[128]; + int Value = CPosRule::NORULE; + array NewIndexList; + + sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue); + + if(!str_comp(aValue, "EMPTY")) + { + Value = CPosRule::EMPTY; + } + else if(!str_comp(aValue, "FULL")) + { + Value = CPosRule::FULL; + } + 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) { + 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; + NewIndexInfo.m_Flag = 0; + + if(!str_comp(aOrientation1, "OR")) { + NewIndexList.add(NewIndexInfo); + pWord += 2; + continue; + } else if(str_length(aOrientation1) > 0) { + if(!str_comp(aOrientation1, "XFLIP")) + NewIndexInfo.m_Flag |= TILEFLAG_VFLIP; + else if(!str_comp(aOrientation1, "YFLIP")) + NewIndexInfo.m_Flag |= TILEFLAG_HFLIP; + else if(!str_comp(aOrientation1, "ROTATE")) + NewIndexInfo.m_Flag |= TILEFLAG_ROTATE; + } else { + NewIndexList.add(NewIndexInfo); + break; + } + + if(!str_comp(aOrientation2, "OR")) { + NewIndexList.add(NewIndexInfo); + pWord += 3; + continue; + } else if(str_length(aOrientation2) > 0) { + 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 { + NewIndexList.add(NewIndexInfo); + break; + } + + if(!str_comp(aOrientation3, "OR")) { + NewIndexList.add(NewIndexInfo); + pWord += 4; + continue; + } else if(str_length(aOrientation3) > 0) { + 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 { + NewIndexList.add(NewIndexInfo); + break; + } + + if(!str_comp(aOrientation4, "OR")) { + NewIndexList.add(NewIndexInfo); + pWord += 5; + continue; + } else { + NewIndexList.add(NewIndexInfo); + break; + } } + } - CPosRule NewPosRule = {x, y, Value, IndexValue}; + if(Value != CPosRule::NORULE) { + CPosRule NewPosRule = {x, y, Value, NewIndexList}; pCurrentIndex->m_aRules.add(NewPosRule); } - else if(!str_comp_num(pLine, "Random", 6) && pCurrentIndex) - { - sscanf(pLine, "Random %d", &pCurrentIndex->m_RandomValue); - } - else if(!str_comp_num(pLine, "NoDefaultRule", 13) && pCurrentIndex) - { - pCurrentIndex->m_DefaultRule = false; - } + } + else if(!str_comp_num(pLine, "Random", 6) && pCurrentIndex) + { + sscanf(pLine, "Random %d", &pCurrentIndex->m_RandomValue); + } + else if(!str_comp_num(pLine, "NoDefaultRule", 13) && pCurrentIndex) + { + pCurrentIndex->m_DefaultRule = false; } } } // add default rule for Pos 0 0 if there is none - for (int h = 0; h < m_lConfigs.size(); ++h) + for (int g = 0; g < m_lConfigs.size(); ++g) { - for(int i = 0; i < m_lConfigs[h].m_aIndexRules.size(); ++i) + for (int h = 0; h < m_lConfigs[g].m_aRuns.size(); ++h) { - bool Found = false; - for(int j = 0; j < m_lConfigs[h].m_aIndexRules[i].m_aRules.size(); ++j) + for(int i = 0; i < m_lConfigs[g].m_aRuns[h].m_aIndexRules.size(); ++i) { - CPosRule *pRule = &m_lConfigs[h].m_aIndexRules[i].m_aRules[j]; - if(pRule && pRule->m_X == 0 && pRule->m_Y == 0) + bool Found = false; + for(int j = 0; j < m_lConfigs[g].m_aRuns[h].m_aIndexRules[i].m_aRules.size(); ++j) { - Found = true; - break; + CPosRule *pRule = &m_lConfigs[g].m_aRuns[h].m_aIndexRules[i].m_aRules[j]; + if(pRule && pRule->m_X == 0 && pRule->m_Y == 0) + { + Found = true; + break; + } + } + if(!Found && m_lConfigs[g].m_aRuns[h].m_aIndexRules[i].m_DefaultRule) + { + array NewIndexList; + CPosRule NewPosRule = {0, 0, CPosRule::FULL, NewIndexList}; + m_lConfigs[g].m_aRuns[h].m_aIndexRules[i].m_aRules.add(NewPosRule); } - } - if(!Found && m_lConfigs[h].m_aIndexRules[i].m_DefaultRule) - { - CPosRule NewPosRule = {0, 0, CPosRule::FULL, false}; - m_lConfigs[h].m_aIndexRules[i].m_aRules.add(NewPosRule); } } } @@ -177,74 +270,93 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) CConfiguration *pConf = &m_lConfigs[ConfigID]; - if(!pConf->m_aIndexRules.size()) - return; + // for every run: copy tiles, automap, overwrite tiles + for(int h = 0; h < pConf->m_aRuns.size(); ++h) { + CRun *pRun = &pConf->m_aRuns[h]; + CLayerTiles newLayer(pLayer->m_Width, pLayer->m_Height); - 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; - } - - // 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 = &(newLayer.m_pTiles[y*pLayer->m_Width+x]); - 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) + // copy tiles + for(int y = 0; y < pLayer->m_Height; y++) { + for(int x = 0; x < pLayer->m_Width; x++) { - 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; - } + 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; } } - 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; + // 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 = &(newLayer.m_pTiles[y*pLayer->m_Width+x]); + m_pEditor->m_Map.m_Modified = true; + + for(int i = 0; i < pRun->m_aIndexRules.size(); ++i) + { + bool RespectRules = true; + for(int j = 0; j < pRun->m_aIndexRules[i].m_aRules.size() && RespectRules; ++j) + { + CPosRule *pRule = &pRun->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_Value == CPosRule::EMPTY) + { + if(pLayer->m_pTiles[CheckIndex].m_Index > 0) + RespectRules = false; + } + else if(pRule->m_Value == CPosRule::FULL) + { + if(pLayer->m_pTiles[CheckIndex].m_Index == 0) + RespectRules = false; + } + else if(pRule->m_Value == CPosRule::INDEX) + { + bool PosRuleTest = false; + for(int i = 0; i < pRule->m_aIndexList.size(); ++i) { + if(pLayer->m_pTiles[CheckIndex].m_Index == pRule->m_aIndexList[i].m_ID && (!pRule->m_aIndexList[i].m_Flag || pLayer->m_pTiles[CheckIndex].m_Flags == pRule->m_aIndexList[i].m_Flag)) + PosRuleTest = true; + } + if(!PosRuleTest) + RespectRules = false; + } + else if(pRule->m_Value == CPosRule::NOTINDEX) + { + bool PosRuleTest = true; + for(int i = 0; i < pRule->m_aIndexList.size(); ++i) { + if(pLayer->m_pTiles[CheckIndex].m_Index == pRule->m_aIndexList[i].m_ID && (!pRule->m_aIndexList[i].m_Flag || pLayer->m_pTiles[CheckIndex].m_Flags == pRule->m_aIndexList[i].m_Flag)) + PosRuleTest = false; + } + if(!PosRuleTest) + RespectRules = false; + } + } + } + + if(RespectRules && + (pRun->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pRun->m_aIndexRules[i].m_RandomValue) == 1)) + { + pTile->m_Index = pRun->m_aIndexRules[i].m_ID; + pTile->m_Flags = pRun->m_aIndexRules[i].m_Flag; + } + } + } + + // overwrite tiles + 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; + } } + } } diff --git a/src/game/editor/auto_map.h b/src/game/editor/auto_map.h index 759573642..78700abb4 100644 --- a/src/game/editor/auto_map.h +++ b/src/game/editor/auto_map.h @@ -5,17 +5,26 @@ class CAutoMapper { + struct CIndexInfo + { + int m_ID; + int m_Flag; + }; + struct CPosRule { int m_X; int m_Y; int m_Value; - bool m_IndexValue; + array m_aIndexList; enum { - EMPTY=0, - FULL + NORULE=0, + EMPTY, + FULL, + INDEX, + NOTINDEX }; }; @@ -28,9 +37,14 @@ class CAutoMapper bool m_DefaultRule; }; - struct CConfiguration + struct CRun { array m_aIndexRules; + }; + + struct CConfiguration + { + array m_aRuns; char m_aName[128]; };