Improvements to ObligatoryToken/ProhibitedToken

Now you can specify exactly how many times given instruction can occur
dev-time-step
krzys-h 2016-04-08 22:15:54 +02:00
parent 3e4fbe93a6
commit 7f38aca766
10 changed files with 143 additions and 115 deletions

View File

@ -611,13 +611,13 @@ msgstr ""
msgid "\\Face 1"
msgstr ""
msgid "\\Face 4"
msgid "\\Face 2"
msgstr ""
msgid "\\Face 3"
msgstr ""
msgid "\\Face 2"
msgid "\\Face 4"
msgstr ""
msgid "\\No eyeglasses"
@ -1519,10 +1519,11 @@ msgid "Unable to control enemy objects"
msgstr ""
#, c-format
msgid "\"%s\" missing in this exercise"
msgid "You have to use \"%s\" at least %d times in this exercise (used: %d)"
msgstr ""
msgid "Do not use in this exercise"
#, c-format
msgid "You have to use \"%s\" at most %d times in this exercise (used: %d)"
msgstr ""
msgid "Inappropriate bot"
@ -1738,6 +1739,9 @@ msgstr ""
msgid "Public required"
msgstr ""
msgid "expression expected after ="
msgstr ""
msgid "Dividing by zero"
msgstr ""

View File

@ -61,10 +61,6 @@ msgstr "Es fehlt eine offene eckige Klammer \" [ \""
msgid "\" ] \" missing"
msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \""
#, c-format
msgid "\"%s\" missing in this exercise"
msgstr "Es fehlt \"%s\" in Ihrem Programm"
msgid "..behind"
msgstr "..hinten"
@ -491,9 +487,6 @@ msgstr "Bildschirm\\Driver und Bildschirmauflösung"
msgid "Dividing by zero"
msgstr "Teilung durch Null"
msgid "Do not use in this exercise"
msgstr "In dieser Übung verboten"
msgid "Do you really want to destroy the selected building?"
msgstr "Wollen Sie das angewählte Gebäude wirklich zerstören ?"
@ -1715,6 +1708,14 @@ msgstr "Sie können unter Wasser nichts tragen"
msgid "You found a usable object"
msgstr "Sie haben ein brauchbares Objekt gefunden"
#, c-format
msgid "You have to use \"%s\" at least %d times in this exercise (used: %d)"
msgstr ""
#, c-format
msgid "You have to use \"%s\" at most %d times in this exercise (used: %d)"
msgstr ""
msgid "You must get on the spaceship to take off "
msgstr "Gehen Sie an Bord, bevor Sie abheben"
@ -1821,6 +1822,9 @@ msgstr ""
msgid "epsitec.com"
msgstr "www.epsitec.com"
msgid "expression expected after ="
msgstr ""
#~ msgid " "
#~ msgstr " "
@ -1830,6 +1834,9 @@ msgstr "www.epsitec.com"
#~ msgid " Missions on this level:"
#~ msgstr " Missionen des Userlevels:"
#~ msgid "\"%s\" missing in this exercise"
#~ msgstr "Es fehlt \"%s\" in Ihrem Programm"
#~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "3D-Geräusche\\Orten der Geräusche im Raum"
@ -1863,6 +1870,9 @@ msgstr "www.epsitec.com"
#~ msgid "Developed by :"
#~ msgstr "Entwickelt von:"
#~ msgid "Do not use in this exercise"
#~ msgstr "In dieser Übung verboten"
#, fuzzy
#~ msgid "Do you want to quit Colobot: Gold Edition?"
#~ msgstr "Wollen Sie COLOBOT schließen ?"

View File

@ -54,10 +54,6 @@ msgstr "\" [ \" attendu"
msgid "\" ] \" missing"
msgstr "\" ] \" attendu"
#, c-format
msgid "\"%s\" missing in this exercise"
msgstr "Il manque \"%s\" dans le programme"
msgid "..behind"
msgstr "..derrière"
@ -486,9 +482,6 @@ msgstr "Affichage\\Pilote et résolution d'affichage"
msgid "Dividing by zero"
msgstr "Division par zéro"
msgid "Do not use in this exercise"
msgstr "Interdit dans cet exercice"
msgid "Do you really want to destroy the selected building?"
msgstr "Voulez-vous vraiment détruire le bâtiment sélectionné ?"
@ -1701,6 +1694,14 @@ msgstr "Vous ne pouvez pas transporter un objet sous l'eau"
msgid "You found a usable object"
msgstr "Vous avez trouvé un objet utilisable"
#, c-format
msgid "You have to use \"%s\" at least %d times in this exercise (used: %d)"
msgstr ""
#, c-format
msgid "You have to use \"%s\" at most %d times in this exercise (used: %d)"
msgstr ""
msgid "You must get on the spaceship to take off "
msgstr "Vous devez embarquer pour pouvoir décoller"
@ -1806,6 +1807,9 @@ msgstr "colobot.info"
msgid "epsitec.com"
msgstr "epsitec.com"
msgid "expression expected after ="
msgstr ""
#~ msgid " "
#~ msgstr " "
@ -1815,6 +1819,9 @@ msgstr "epsitec.com"
#~ msgid " Missions on this level:"
#~ msgstr " Missions du niveau :"
#~ msgid "\"%s\" missing in this exercise"
#~ msgstr "Il manque \"%s\" dans le programme"
#~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace"
@ -1848,6 +1855,9 @@ msgstr "epsitec.com"
#~ msgid "Developed by :"
#~ msgstr "Développé par :"
#~ msgid "Do not use in this exercise"
#~ msgstr "Interdit dans cet exercice"
#, fuzzy
#~ msgid "Do you want to quit Colobot: Gold Edition?"
#~ msgstr "Voulez-vous quitter COLOBOT ?"

View File

@ -60,10 +60,6 @@ msgstr "Oczekiwane \" [ \""
msgid "\" ] \" missing"
msgstr "Brak \" ] \""
#, c-format
msgid "\"%s\" missing in this exercise"
msgstr "Brakuje \"%s\" w tym ćwiczeniu"
msgid "..behind"
msgstr "..za"
@ -492,9 +488,6 @@ msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości"
msgid "Dividing by zero"
msgstr "Dzielenie przez zero"
msgid "Do not use in this exercise"
msgstr "Do not use in this exercise"
msgid "Do you really want to destroy the selected building?"
msgstr "Czy na pewno chcesz zniszczyć zaznaczony budynek?"
@ -1709,6 +1702,14 @@ msgstr "Nie możesz przenosić przedmiotów pod wodą"
msgid "You found a usable object"
msgstr "Znaleziono użyteczny przedmiot"
#, c-format
msgid "You have to use \"%s\" at least %d times in this exercise (used: %d)"
msgstr "Musisz użyć \"%s\" przynajmniej %d razy w tym ćwiczeniu (użyto: %d)"
#, c-format
msgid "You have to use \"%s\" at most %d times in this exercise (used: %d)"
msgstr "Musisz użyć \"%s\" najwyżej %d razy w tym ćwiczeniu (użyto: %d)"
msgid "You must get on the spaceship to take off "
msgstr "Musisz być na statku kosmicznym aby nim odlecieć"
@ -1814,9 +1815,15 @@ msgstr "colobot.info"
msgid "epsitec.com"
msgstr "epsitec.com"
msgid "expression expected after ="
msgstr ""
#~ msgid " Drivers:"
#~ msgstr " Sterowniki:"
#~ msgid "\"%s\" missing in this exercise"
#~ msgstr "Brakuje \"%s\" w tym ćwiczeniu"
#~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "Dźwięk 3D\\Przestrzenne pozycjonowanie dźwięków"
@ -1844,6 +1851,9 @@ msgstr "epsitec.com"
#~ msgid "Details\\Visual quality of 3D objects"
#~ msgstr "Szczegóły\\Jakość wizualna obiektów 3D"
#~ msgid "Do not use in this exercise"
#~ msgstr "Do not use in this exercise"
#~ msgid "Do you want to quit Colobot: Gold Edition?"
#~ msgstr "Czy na pewno chcesz opuścić grę Colobot: Gold Edition?"

View File

@ -59,10 +59,6 @@ msgstr "Ожидалось \" [ \""
msgid "\" ] \" missing"
msgstr "Отсутствует \"]\" "
#, c-format
msgid "\"%s\" missing in this exercise"
msgstr "\"%s\" отсутствует в этом упражнении"
msgid "..behind"
msgstr "Сзади"
@ -484,9 +480,6 @@ msgstr "Устройство\\Драйвер и настройки разреш
msgid "Dividing by zero"
msgstr "Деление на ноль (запрещено!)"
msgid "Do not use in this exercise"
msgstr "Не используй в этом упражнении"
msgid "Do you really want to destroy the selected building?"
msgstr "Вы действительно хотите уничтожить выбранное здание?"
@ -1706,6 +1699,14 @@ msgstr "Вы не можете нести объекты под водой"
msgid "You found a usable object"
msgstr "Вы нашли рабочий объект"
#, c-format
msgid "You have to use \"%s\" at least %d times in this exercise (used: %d)"
msgstr ""
#, c-format
msgid "You have to use \"%s\" at most %d times in this exercise (used: %d)"
msgstr ""
msgid "You must get on the spaceship to take off "
msgstr "Вы должны быть на борту корабля, чтобы взлететь"
@ -1812,6 +1813,9 @@ msgstr ""
msgid "epsitec.com"
msgstr "www.epsitec.com"
msgid "expression expected after ="
msgstr ""
#~ msgid " "
#~ msgstr " "
@ -1821,6 +1825,9 @@ msgstr "www.epsitec.com"
#~ msgid " Missions on this level:"
#~ msgstr " Миссии на этом уровне:"
#~ msgid "\"%s\" missing in this exercise"
#~ msgstr "\"%s\" отсутствует в этом упражнении"
#~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "3D-звук\\Стерео звук"
@ -1854,6 +1861,9 @@ msgstr "www.epsitec.com"
#~ msgid "Developed by :"
#~ msgstr "Разработка :"
#~ msgid "Do not use in this exercise"
#~ msgstr "Не используй в этом упражнении"
#, fuzzy
#~ msgid "Do you want to quit Colobot: Gold Edition?"
#~ msgstr "Вы хотите закрыть COLOBOT?"

View File

@ -632,8 +632,8 @@ void InitializeRestext()
stringsErr[ERR_DELETEMOBILE] = TR("Bot destroyed");
stringsErr[ERR_DELETEBUILDING] = TR("Building destroyed");
stringsErr[ERR_ENEMY_OBJECT] = TR("Unable to control enemy objects");
stringsErr[ERR_OBLIGATORYTOKEN] = TR("\"%s\" missing in this exercise");
stringsErr[ERR_PROHIBITEDTOKEN] = TR("Do not use in this exercise");
stringsErr[ERR_OBLIGATORYTOKEN] = TR("You have to use \"%s\" at least %d times in this exercise (used: %d)");
stringsErr[ERR_PROHIBITEDTOKEN] = TR("You have to use \"%s\" at most %d times in this exercise (used: %d)");
stringsErr[ERR_WRONG_BOT] = TR("Inappropriate bot");
stringsErr[INFO_BUILD] = TR("Building completed");

View File

@ -2839,8 +2839,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
m_endTakeWinDelay = 2.0f;
m_endTakeLostDelay = 2.0f;
m_globalMagnifyDamage = 1.0f;
m_obligatoryTotal = 0;
m_prohibitedTotal = 0;
m_obligatoryTokens.clear();
m_mapShow = true;
m_mapImage = false;
m_mapFilename[0] = 0;
@ -3656,25 +3655,32 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
continue;
}
if (line->GetCommand() == "ObligatoryToken" && !resetObject) // NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
if (line->GetCommand() == "ObligatoryToken" && !resetObject)
{
int i = m_obligatoryTotal;
if (i < 100) //TODO: remove the limit
std::string token = line->GetParam("text")->AsString();
if (!line->GetParam("min")->IsDefined() && !line->GetParam("max")->IsDefined())
GetLogger()->Warn("ObligatoryToken without specifying min/max is provided only for backwards compatibility - instead, do this: ObligatoryToken text=\"%s\" min=1\n", token.c_str());
if (m_obligatoryTokens.count(token))
throw CLevelParserException("Incorrect ObligatoryToken specification - you cannot define a token twice");
m_obligatoryTokens[token].min = line->GetParam("min")->AsInt(line->GetParam("max")->IsDefined() ? -1 : 1); // BACKWARDS COMPATIBILITY: if neither min or max are defined, default to min=1
m_obligatoryTokens[token].max = line->GetParam("max")->AsInt(-1);
if (m_obligatoryTokens[token].min >= 0 && m_obligatoryTokens[token].max >= 0 && m_obligatoryTokens[token].min > m_obligatoryTokens[token].max)
{
strcpy(m_obligatoryToken[i], line->GetParam("text")->AsString().c_str());
m_obligatoryTotal ++;
throw CLevelParserException("Incorrect ObligatoryToken specification - min cannot be greater than max");
}
continue;
}
if (line->GetCommand() == "ProhibitedToken" && !resetObject) // NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
if (line->GetCommand() == "ProhibitedToken" && !resetObject) // NOTE: Kept only for backwards compatibility
{
int i = m_prohibitedTotal;
if (i < 100) //TODO: remove the limit
{
strcpy(m_prohibitedToken[i], line->GetParam("text")->AsString().c_str());
m_prohibitedTotal ++;
}
std::string token = line->GetParam("text")->AsString();
GetLogger()->Warn("ProhibitedToken is only provided for backwards compatibility - instead, do this: ObligatoryToken text=\"%s\" max=0\n", token.c_str());
if (m_obligatoryTokens.count(token))
throw CLevelParserException("Incorrect ObligatoryToken specification - you cannot define a token twice");
m_obligatoryTokens[token].min = -1;
m_obligatoryTokens[token].max = 0;
continue;
}
@ -5227,41 +5233,12 @@ Error CRobotMain::CheckEndMission(bool frame)
}
//! Returns the number of instructions required
int CRobotMain::GetObligatoryToken()
//! Returns the list instructions required in CBot program in level
const std::map<std::string, MinMax>& CRobotMain::GetObligatoryTokenList()
{
return m_obligatoryTotal;
return m_obligatoryTokens;
}
//! Returns the name of a required instruction
char* CRobotMain::GetObligatoryToken(int i)
{
return m_obligatoryToken[i];
}
//! Checks if an instruction is part of the obligatory list
int CRobotMain::IsObligatoryToken(const char* token)
{
for (int i = 0; i < m_obligatoryTotal; i++)
{
if (strcmp(token, m_obligatoryToken[i]) == 0)
return i;
}
return -1;
}
//! Checks if an instruction is not part of the banned list
bool CRobotMain::IsProhibitedToken(const char* token)
{
for (int i = 0; i < m_prohibitedTotal; i++)
{
if (strcmp(token, m_prohibitedToken[i]) == 0)
return false;
}
return true;
}
//! Indicates whether it is possible to control a driving robot
bool CRobotMain::GetTrainerPilot()
{

View File

@ -141,6 +141,12 @@ struct ShowLimit
float time = 0.0f;
};
struct MinMax
{
int min = -1;
int max = -1;
};
const int SATCOM_HUSTON = 0;
const int SATCOM_SAT = 1;
@ -199,10 +205,7 @@ public:
Error CheckEndMission(bool frame);
Error ProcessEndMissionTake();
Error ProcessEndMissionTakeForGroup(std::vector<CSceneEndCondition*>& endTakes);
int GetObligatoryToken();
char* GetObligatoryToken(int i);
int IsObligatoryToken(const char* token);
bool IsProhibitedToken(const char* token);
const std::map<std::string, MinMax>& GetObligatoryTokenList();
void UpdateMap();
bool GetShowMap();
@ -552,10 +555,7 @@ protected:
std::vector<std::unique_ptr<CAudioChangeCondition>> m_audioChange;
int m_obligatoryTotal = 0;
char m_obligatoryToken[100][20] = {};
int m_prohibitedTotal = 0;
char m_prohibitedToken[100][20] = {};
std::map<std::string, MinMax> m_obligatoryTokens;
//! Enabled buildings
int m_build = 0;

View File

@ -161,46 +161,52 @@ bool CScript::CheckToken()
m_error = CBot::CBotNoErr;
m_title[0] = 0;
m_mainFunction[0] = 0;
m_token[0] = 0;
m_token.clear();
m_bCompile = false;
std::vector<bool> used(m_main->GetObligatoryToken(), false);
std::map<std::string, int> used;
std::map<std::string, int> cursor1;
std::map<std::string, int> cursor2;
auto tokens = CBot::CBotToken::CompileTokens(m_script.get());
CBot::CBotToken* bt = tokens.get();
while ( bt != nullptr )
{
std::string token = bt->GetString();
int cursor1 = bt->GetStart();
int cursor2 = bt->GetEnd();
int i = m_main->IsObligatoryToken(token.c_str());
if ( i != -1 )
{
used[i] = true; // token used
}
// Store only the last occurrence of the token
cursor1[token] = bt->GetStart();
cursor2[token] = bt->GetEnd();
if ( !m_main->IsProhibitedToken(token.c_str()) )
{
m_error = static_cast<CBot::CBotError>(ERR_PROHIBITEDTOKEN);
m_cursor1 = cursor1;
m_cursor2 = cursor2;
strcpy(m_title, "<prohibited>");
m_mainFunction[0] = 0;
return false;
}
used[token]++;
bt = bt->GetNext();
}
// At least once every obligatory instruction?
for (unsigned int i = 0; i < used.size(); i++)
for (const auto& it : m_main->GetObligatoryTokenList())
{
if (!used[i]) // token not used?
Error error = ERR_OK;
int allowed = 0;
if (it.second.max >= 0 && used[it.first] > it.second.max)
{
strcpy(m_token, m_main->GetObligatoryToken(i));
m_error = static_cast<CBot::CBotError>(ERR_OBLIGATORYTOKEN);
strcpy(m_title, "<obligatory>");
error = ERR_PROHIBITEDTOKEN;
allowed = it.second.max;
m_cursor1 = cursor1[it.first];
m_cursor2 = cursor2[it.first];
}
if (it.second.min >= 0 && used[it.first] < it.second.min)
{
error = ERR_OBLIGATORYTOKEN;
allowed = it.second.min;
}
if (error != ERR_OK)
{
m_token = it.first;
m_tokenUsed = used[it.first];
m_tokenAllowed = allowed;
m_error = static_cast<CBot::CBotError>(error);
strcpy(m_title, "<incorrect instructions>");
m_mainFunction[0] = 0;
return false;
}
@ -788,11 +794,11 @@ void CScript::GetError(std::string& error)
}
else
{
if ( m_error == static_cast<CBot::CBotError>(ERR_OBLIGATORYTOKEN) )
if ( m_error == static_cast<CBot::CBotError>(ERR_OBLIGATORYTOKEN) || m_error == static_cast<CBot::CBotError>(ERR_PROHIBITEDTOKEN) )
{
std::string s;
GetResource(RES_ERR, m_error, s);
error = StrUtils::Format(s.c_str(), m_token);
error = StrUtils::Format(s.c_str(), m_token.c_str(), m_tokenAllowed, m_tokenUsed);
}
else if ( m_error < 1000 )
{

View File

@ -122,7 +122,8 @@ protected:
char m_title[50] = {}; // script title
char m_mainFunction[50] = {};
char m_filename[50] = {}; // file name
char m_token[50] = {}; // missing instruction
std::string m_token = ""; // missing instruction
int m_tokenUsed = 0, m_tokenAllowed = 0;
CBot::CBotError m_error = CBot::CBotNoErr; // error (0=ok)
int m_cursor1 = 0;
int m_cursor2 = 0;