diff --git a/client/ClientCommandManager.cpp b/client/ClientCommandManager.cpp index a5e1790da..194f8c94c 100644 --- a/client/ClientCommandManager.cpp +++ b/client/ClientCommandManager.cpp @@ -42,7 +42,34 @@ #include -void ClientCommandManager::handleGoSolo() +void ClientCommandManager::handleQuitCommand() +{ + exit(EXIT_SUCCESS); +} + +void ClientCommandManager::handleSaveCommand(std::istringstream & singleWordBuffer) +{ + if(!CSH->client) + { + printCommandMessage("Game is not in playing state"); + return; + } + + std::string saveFilename; + singleWordBuffer >> saveFilename; + CSH->client->save(saveFilename); + printCommandMessage("Game saved as: " + saveFilename); +} + +void ClientCommandManager::handleLoadCommand(std::istringstream& singleWordBuffer) +{ + // TODO: this code should end the running game and manage to call startGame instead + //std::string fname; + //singleWordBuffer >> fname; + //CSH->client->loadGame(fname); +} + +void ClientCommandManager::handleGoSoloCommand() { Settings session = settings.write["session"]; @@ -80,21 +107,33 @@ void ClientCommandManager::handleGoSolo() session["aiSolo"].Bool() = !session["aiSolo"].Bool(); } -void ClientCommandManager::handleControlAi(const std::string &colorName) +void ClientCommandManager::handleAutoskipCommand() { + Settings session = settings.write["session"]; + session["autoSkip"].Bool() = !session["autoSkip"].Bool(); +} + +void ClientCommandManager::handleControlaiCommand(std::istringstream& singleWordBuffer) +{ + std::string colorName; + singleWordBuffer >> colorName; + boost::to_lower(colorName); + boost::unique_lock un(*CPlayerInterface::pim); if(!CSH->client) { printCommandMessage("Game is not in playing state"); return; } + PlayerColor color; if(LOCPLINT) color = LOCPLINT->playerID; + for(auto & elem : CSH->client->gameState()->players) { - if(elem.second.human || (colorName.length() && - elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName))) + if(elem.second.human || + (colorName.length() && elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName))) { continue; } @@ -102,386 +141,319 @@ void ClientCommandManager::handleControlAi(const std::string &colorName) CSH->client->removeGUI(); CSH->client->installNewPlayerInterface(std::make_shared(elem.first), elem.first); } + GH.totalRedraw(); if(color != PlayerColor::NEUTRAL) giveTurn(color); } -void ClientCommandManager::processCommand(const std::string &message, bool calledFromIngameConsole) +void ClientCommandManager::handleSetBattleAICommand(std::istringstream& singleWordBuffer) { - std::istringstream singleWordBuffer; - singleWordBuffer.str(message); - std::string commandName; - singleWordBuffer >> commandName; - currentCallFromIngameConsole = calledFromIngameConsole; + std::string aiName; + singleWordBuffer >> aiName; - if(message==std::string("die, fool")) + printCommandMessage("Will try loading that AI to see if it is correct name...\n"); + try { - exit(EXIT_SUCCESS); + if(auto ai = CDynLibHandler::getNewBattleAI(aiName)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game + { + Settings neutralAI = settings.write["server"]["neutralAI"]; + neutralAI->String() = aiName; + printCommandMessage("Setting changed, from now the battle ai will be " + aiName + "!\n"); + } } - else if(commandName == "redraw") + catch(std::exception &e) { - GH.totalRedraw(); + printCommandMessage("Failed opening " + aiName + ": " + e.what(), ELogLevel::WARN); + printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN); } - else if(commandName == "screen") - { - printCommandMessage("Screenbuf points to "); +} - if(screenBuf == screen) - printCommandMessage("screen", ELogLevel::ERROR); - else if(screenBuf == screen2) - printCommandMessage("screen2", ELogLevel::ERROR); +void ClientCommandManager::handleRedrawCommand() +{ + GH.totalRedraw(); +} + +void ClientCommandManager::handleScreenCommand() +{ + printCommandMessage("Screenbuf points to "); + + if(screenBuf == screen) + printCommandMessage("screen", ELogLevel::ERROR); + else if(screenBuf == screen2) + printCommandMessage("screen2", ELogLevel::ERROR); + else + printCommandMessage("?!?", ELogLevel::ERROR); + + SDL_SaveBMP(screen, "Screen_c.bmp"); + SDL_SaveBMP(screen2, "Screen2_c.bmp"); +} + +void ClientCommandManager::handleNotDialogCommand() +{ + LOCPLINT->showingDialog->setn(false); +} + +void ClientCommandManager::handleGuiCommand() +{ + for(const auto & child : GH.listInt) + { + const auto childPtr = child.get(); + if(const CIntObject * obj = dynamic_cast(childPtr)) + printInfoAboutInterfaceObject(obj, 0); else - printCommandMessage("?!?", ELogLevel::ERROR); - - SDL_SaveBMP(screen, "Screen_c.bmp"); - SDL_SaveBMP(screen2, "Screen2_c.bmp"); + printCommandMessage(std::string(typeid(childPtr).name()) + "\n"); } - else if(commandName == "save") +} + +void ClientCommandManager::handleConvertTextCommand() +{ + logGlobal->info("Searching for available maps"); + std::unordered_set mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident) { - if(!CSH->client) - { - printCommandMessage("Game is not in playing state"); - return; - } - std::string fname; - singleWordBuffer >> fname; - CSH->client->save(fname); - } -// else if(commandName=="load") -// { -// // TODO: this code should end the running game and manage to call startGame instead -// std::string fname; -// singleWordBuffer >> fname; -// CSH->client->loadGame(fname); -// } - else if(message=="convert txt") + return ident.getType() == EResType::MAP; + }); + + std::unordered_set campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident) { - logGlobal->info("Searching for available maps"); - std::unordered_set mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident) - { - return ident.getType() == EResType::MAP; - }); + return ident.getType() == EResType::CAMPAIGN; + }); - std::unordered_set campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident) - { - return ident.getType() == EResType::CAMPAIGN; - }); + CMapService mapService; - CMapService mapService; - - logGlobal->info("Loading maps for export"); - for (auto const & mapName : mapList) - { - try - { - // load and drop loaded map - we only need loader to run over all maps - mapService.loadMap(mapName); - } - catch(std::exception & e) - { - logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what()); - } - } - - logGlobal->info("Loading campaigns for export"); - for (auto const & campaignName : campaignList) - { - CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName())); - for (auto const & part : state.camp->mapPieces) - delete state.getMap(part.first); - } - - VLC->generaltexth->dumpAllTexts(); - } - else if(message=="get config") + logGlobal->info("Loading maps for export"); + for (auto const & mapName : mapList) { - printCommandMessage("Command accepted.\t"); - - const boost::filesystem::path outPath = - VCMIDirs::get().userExtractedPath() / "configuration"; - - boost::filesystem::create_directories(outPath); - - const std::vector contentNames = {"heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills"}; - - for(auto contentName : contentNames) - { - auto & content = (*VLC->modh->content)[contentName]; - - auto contentOutPath = outPath / contentName; - boost::filesystem::create_directories(contentOutPath); - - for(auto & iter : content.modData) - { - const JsonNode & modData = iter.second.modData; - - for(auto & nameAndObject : modData.Struct()) - { - const JsonNode & object = nameAndObject.second; - - std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first); - - boost::algorithm::replace_all(name,":","_"); - - const boost::filesystem::path filePath = contentOutPath / (name + ".json"); - boost::filesystem::ofstream file(filePath); - file << object.toJson(); - } - } - } - - printCommandMessage("\rExtracting done :)\n"); - printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n"); - } -#if SCRIPTING_ENABLED - else if(message=="get scripts") - { - printCommandMessage("Command accepted.\t"); - - const boost::filesystem::path outPath = - VCMIDirs::get().userExtractedPath() / "scripts"; - - boost::filesystem::create_directories(outPath); - - for(auto & kv : VLC->scriptHandler->objects) - { - std::string name = kv.first; - boost::algorithm::replace_all(name,":","_"); - - const scripting::ScriptImpl * script = kv.second.get(); - boost::filesystem::path filePath = outPath / (name + ".lua"); - boost::filesystem::ofstream file(filePath); - file << script->getSource(); - } - printCommandMessage("\rExtracting done :)\n"); - printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n"); - } -#endif - else if(message=="get txt") - { - printCommandMessage("Command accepted.\t"); - - const boost::filesystem::path outPath = - VCMIDirs::get().userExtractedPath(); - - auto list = - CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident) - { - return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/"); - }); - - for (auto & filename : list) - { - const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT"); - - boost::filesystem::create_directories(filePath.parent_path()); - - boost::filesystem::ofstream file(filePath); - auto text = CResourceHandler::get()->load(filename)->readAll(); - - file.write((char*)text.first.get(), text.second); - } - - printCommandMessage("\rExtracting done :)\n"); - printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n"); - } - else if(commandName == "crash") - { - int *ptr = nullptr; - *ptr = 666; - //disaster! - } - else if(commandName == "mp" && adventureInt) - { - if(const CGHeroInstance *h = adventureInt->curHero()) - printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n"); - } - else if(commandName == "bonuses") - { - bool jsonFormat = (message == "bonuses json"); - auto format = [jsonFormat](const BonusList & b) -> std::string - { - if(jsonFormat) - return b.toJsonNode().toJson(true); - std::ostringstream ss; - ss << b; - return ss.str(); - }; - printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n"); - printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n"); - - printCommandMessage("\nInherited bonuses:\n"); - TCNodes parents; - adventureInt->curArmy()->getParents(parents); - for(const CBonusSystemNode *parent : parents) - { - printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n"); - } - } - else if(commandName == "not dialog") - { - LOCPLINT->showingDialog->setn(false); - } - else if(commandName == "gui") - { - for(auto & child : GH.listInt) - { - const auto childPtr = child.get(); - if(const CIntObject * obj = dynamic_cast(childPtr)) - printInfoAboutInterfaceObject(obj, 0); - else - printCommandMessage(std::string(typeid(childPtr).name()) + "\n"); - } - } - else if(commandName == "tell") - { - std::string what; - int id1, id2; - singleWordBuffer >> what >> id1 >> id2; - if(what == "hs") - { - for(const CGHeroInstance *h : LOCPLINT->cb->getHeroesInfo()) - if(h->type->getIndex() == id1) - if(const CArtifactInstance *a = h->getArt(ArtifactPosition(id2))) - printCommandMessage(a->nodeName()); - } - } - else if (commandName == "set") - { - std::string what, value; - singleWordBuffer >> what; - - Settings config = settings.write["session"][what]; - - singleWordBuffer >> value; - - if (value == "on") - { - config->Bool() = true; - printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO); - } - else if (value == "off") - { - config->Bool() = false; - printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO); - } - } - else if(commandName == "unlock") - { - std::string mxname; - singleWordBuffer >> mxname; - if(mxname == "pim" && LOCPLINT) - LOCPLINT->pim->unlock(); - } - else if(commandName == "def2bmp") - { - std::string URI; - singleWordBuffer >> URI; - std::unique_ptr anim = std::make_unique(URI); - anim->preload(); - anim->exportBitmaps(VCMIDirs::get().userExtractedPath()); - } - else if(commandName == "extract") - { - std::string URI; - singleWordBuffer >> URI; - - if (CResourceHandler::get()->existsResource(ResourceID(URI))) - { - const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI; - - auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll(); - - boost::filesystem::create_directories(outPath.parent_path()); - boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary); - outFile.write((char*)data.first.get(), data.second); - } - else - printCommandMessage("File not found!", ELogLevel::ERROR); - } - else if(commandName == "setBattleAI") - { - std::string fname; - singleWordBuffer >> fname; - printCommandMessage("Will try loading that AI to see if it is correct name...\n"); try { - if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game + // load and drop loaded map - we only need loader to run over all maps + mapService.loadMap(mapName); + } + catch(std::exception & e) + { + logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what()); + } + } + + logGlobal->info("Loading campaigns for export"); + for (auto const & campaignName : campaignList) + { + CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName())); + for (auto const & part : state.camp->mapPieces) + delete state.getMap(part.first); + } + + VLC->generaltexth->dumpAllTexts(); +} + +void ClientCommandManager::handleGetConfigCommand() +{ + printCommandMessage("Command accepted.\t"); + + const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "configuration"; + + boost::filesystem::create_directories(outPath); + + const std::vector contentNames = { "heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills" }; + + for(auto contentName : contentNames) + { + auto& content = (*VLC->modh->content)[contentName]; + + auto contentOutPath = outPath / contentName; + boost::filesystem::create_directories(contentOutPath); + + for(auto& iter : content.modData) + { + const JsonNode& modData = iter.second.modData; + + for(auto& nameAndObject : modData.Struct()) { - Settings neutralAI = settings.write["server"]["neutralAI"]; - neutralAI->String() = fname; - printCommandMessage("Setting changed, from now the battle ai will be " + fname + "!\n"); + const JsonNode& object = nameAndObject.second; + + std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first); + + boost::algorithm::replace_all(name, ":", "_"); + + const boost::filesystem::path filePath = contentOutPath / (name + ".json"); + boost::filesystem::ofstream file(filePath); + file << object.toJson(); } } - catch(std::exception &e) - { - printCommandMessage("Failed opening " + fname + ": " + e.what(), ELogLevel::WARN); - printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN); - } } - else if(commandName == "autoskip") - { - Settings session = settings.write["session"]; - session["autoSkip"].Bool() = !session["autoSkip"].Bool(); - } - else if(commandName == "gosolo") - { - ClientCommandManager::handleGoSolo(); - } - else if(commandName == "controlai") - { - std::string colorName; - singleWordBuffer >> colorName; - boost::to_lower(colorName); - ClientCommandManager::handleControlAi(colorName); + printCommandMessage("\rExtracting done :)\n"); + printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n"); +} + +void ClientCommandManager::handleGetScriptsCommand() +{ +#if SCRIPTING_ENABLED + printCommandMessage("Command accepted.\t"); + + const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "scripts"; + + boost::filesystem::create_directories(outPath); + + for(auto & kv : VLC->scriptHandler->objects) + { + std::string name = kv.first; + boost::algorithm::replace_all(name,":","_"); + + const scripting::ScriptImpl * script = kv.second.get(); + boost::filesystem::path filePath = outPath / (name + ".lua"); + boost::filesystem::ofstream file(filePath); + file << script->getSource(); + } + printCommandMessage("\rExtracting done :)\n"); + printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n"); +#endif +} + +void ClientCommandManager::handleGetTextCommand() +{ + printCommandMessage("Command accepted.\t"); + + const boost::filesystem::path outPath = + VCMIDirs::get().userExtractedPath(); + + auto list = + CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident) + { + return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/"); + }); + + for (auto & filename : list) + { + const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT"); + + boost::filesystem::create_directories(filePath.parent_path()); + + boost::filesystem::ofstream file(filePath); + auto text = CResourceHandler::get()->load(filename)->readAll(); + + file.write((char*)text.first.get(), text.second); + } + + printCommandMessage("\rExtracting done :)\n"); + printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n"); +} + +void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBuffer) +{ + std::string URI; + singleWordBuffer >> URI; + std::unique_ptr anim = std::make_unique(URI); + anim->preload(); + anim->exportBitmaps(VCMIDirs::get().userExtractedPath()); +} + +void ClientCommandManager::handleExtractCommand(std::istringstream& singleWordBuffer) +{ + std::string URI; + singleWordBuffer >> URI; + + if(CResourceHandler::get()->existsResource(ResourceID(URI))) + { + const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI; + + auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll(); + + boost::filesystem::create_directories(outPath.parent_path()); + boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary); + outFile.write((char*)data.first.get(), data.second); } else + printCommandMessage("File not found!", ELogLevel::ERROR); +} + +void ClientCommandManager::handleBonusesCommand(std::istringstream & singleWordBuffer) +{ + if(currentCallFromIngameConsole) { - if (!commandName.empty() && !vstd::iswithin(commandName[0], 0, ' ')) // filter-out debugger/IDE noise - printCommandMessage("Command not found :(", ELogLevel::ERROR); + printCommandMessage("Output for this command is too large for ingame chat! Please run it from client console.\n"); + return; + } + + std::string outputFormat; + singleWordBuffer >> outputFormat; + + auto format = [outputFormat](const BonusList & b) -> std::string + { + if(outputFormat == "json") + return b.toJsonNode().toJson(true); + + std::ostringstream ss; + ss << b; + return ss.str(); + }; + printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n"); + printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n"); + + printCommandMessage("\nInherited bonuses:\n"); + TCNodes parents; + adventureInt->curArmy()->getParents(parents); + for(const CBonusSystemNode *parent : parents) + { + printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n"); } } -void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier) +void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffer) { - YourTurn yt; - yt.player = colorIdentifier; - yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle; + std::string what; + int id1, id2; + singleWordBuffer >> what >> id1 >> id2; - ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState()); - yt.visit(visitor); + if(what == "hs") + { + for(const CGHeroInstance* h : LOCPLINT->cb->getHeroesInfo()) + if(h->type->getIndex() == id1) + if(const CArtifactInstance* a = h->getArt(ArtifactPosition(id2))) + printCommandMessage(a->nodeName()); + } } -void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level) +void ClientCommandManager::handleMpCommand() { - std::stringstream sbuffer; - sbuffer << std::string(level, '\t'); + if(const CGHeroInstance* h = adventureInt->curHero()) + printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n"); +} - sbuffer << typeid(*obj).name() << " *** "; - if (obj->active) +void ClientCommandManager::handleSetCommand(std::istringstream& singleWordBuffer) +{ + std::string what, value; + singleWordBuffer >> what; + + Settings config = settings.write["session"][what]; + + singleWordBuffer >> value; + + if(value == "on") { -#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text - PRINT(LCLICK, 'L'); - PRINT(RCLICK, 'R'); - PRINT(HOVER, 'H'); - PRINT(MOVE, 'M'); - PRINT(KEYBOARD, 'K'); - PRINT(TIME, 'T'); - PRINT(GENERAL, 'A'); - PRINT(WHEEL, 'W'); - PRINT(DOUBLECLICK, 'D'); -#undef PRINT + config->Bool() = true; + printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO); } - else - sbuffer << "inactive"; - sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y; - sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")"; - printCommandMessage(sbuffer.str(), ELogLevel::INFO); + else if(value == "off") + { + config->Bool() = false; + printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO); + } +} - for(const CIntObject *child : obj->children) - printInfoAboutInterfaceObject(child, level+1); +void ClientCommandManager::handleUnlockCommand(std::istringstream& singleWordBuffer) +{ + std::string mxname; + singleWordBuffer >> mxname; + if(mxname == "pim" && LOCPLINT) + LOCPLINT->pim->unlock(); +} + +void ClientCommandManager::handleCrashCommand() +{ + int* ptr = nullptr; + *ptr = 666; + //disaster! } void ClientCommandManager::printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType) @@ -520,3 +492,131 @@ void ClientCommandManager::printCommandMessage(const std::string &commandMessage } } } + +void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level) +{ + std::stringstream sbuffer; + sbuffer << std::string(level, '\t'); + + sbuffer << typeid(*obj).name() << " *** "; + if (obj->active) + { +#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text + PRINT(LCLICK, 'L'); + PRINT(RCLICK, 'R'); + PRINT(HOVER, 'H'); + PRINT(MOVE, 'M'); + PRINT(KEYBOARD, 'K'); + PRINT(TIME, 'T'); + PRINT(GENERAL, 'A'); + PRINT(WHEEL, 'W'); + PRINT(DOUBLECLICK, 'D'); +#undef PRINT + } + else + sbuffer << "inactive"; + sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y; + sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")"; + printCommandMessage(sbuffer.str(), ELogLevel::INFO); + + for(const CIntObject *child : obj->children) + printInfoAboutInterfaceObject(child, level+1); +} + +void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier) +{ + YourTurn yt; + yt.player = colorIdentifier; + yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle; + + ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState()); + yt.visit(visitor); +} + +void ClientCommandManager::processCommand(const std::string & message, bool calledFromIngameConsole) +{ + // split the message into individual words + std::istringstream singleWordBuffer; + singleWordBuffer.str(message); + + // get command name, to be used for single word commands + std::string commandName; + singleWordBuffer >> commandName; + + currentCallFromIngameConsole = calledFromIngameConsole; + + if(message == std::string("die, fool")) + handleQuitCommand(); + + else if(commandName == "save") + handleSaveCommand(singleWordBuffer); + + else if(commandName=="load") + handleLoadCommand(singleWordBuffer); // not implemented + + else if(commandName == "gosolo") + handleGoSoloCommand(); + + else if(commandName == "autoskip") + handleAutoskipCommand(); + + else if(commandName == "controlai") + handleControlaiCommand(singleWordBuffer); + + else if(commandName == "setBattleAI") + handleSetBattleAICommand(singleWordBuffer); + + else if(commandName == "redraw") + handleRedrawCommand(); + + else if(commandName == "screen") + handleScreenCommand(); + + else if(commandName == "not dialog") + handleNotDialogCommand(); + + else if(commandName == "gui") + handleGuiCommand(); + + else if(message=="convert txt") + handleConvertTextCommand(); + + else if(message=="get config") + handleGetConfigCommand(); + + else if(message=="get scripts") + handleGetScriptsCommand(); + + else if(message=="get txt") + handleGetTextCommand(); + + else if(commandName == "def2bmp") + handleDef2bmpCommand(singleWordBuffer); + + else if(commandName == "extract") + handleExtractCommand(singleWordBuffer); + + else if(commandName == "bonuses") + handleBonusesCommand(singleWordBuffer); + + else if(commandName == "tell") + handleTellCommand(singleWordBuffer); + + else if(commandName == "mp" && adventureInt) + handleMpCommand(); + + else if (commandName == "set") + handleSetCommand(singleWordBuffer); + + else if(commandName == "unlock") + handleUnlockCommand(singleWordBuffer); + + else if(commandName == "crash") + handleCrashCommand(); + + else + { + if (!commandName.empty() && !vstd::iswithin(commandName[0], 0, ' ')) // filter-out debugger/IDE noise + printCommandMessage("Command not found :(", ELogLevel::ERROR); + } +} diff --git a/client/ClientCommandManager.h b/client/ClientCommandManager.h index 14ce180af..ea7ca321f 100644 --- a/client/ClientCommandManager.h +++ b/client/ClientCommandManager.h @@ -17,15 +17,85 @@ class CIntObject; class ClientCommandManager //take mantis #2292 issue about account if thinking about handling cheats from command-line { - bool currentCallFromIngameConsole = false; + bool currentCallFromIngameConsole = false; // commands can come from 2 sources: ingame console (chat) and client console + + // Quits the game (die, fool command) + void handleQuitCommand(); - void giveTurn(const PlayerColor &color); - void printInfoAboutInterfaceObject(const CIntObject *obj, int level); + // Saves current game under the given filename + void handleSaveCommand(std::istringstream & singleWordBuffer); + + // Loads a game with the given filename + void handleLoadCommand(std::istringstream & singleWordBuffer); + + // AI takes over until the end of turn (unlike original H3 currently causes AI to take over until typed again) + void handleGoSoloCommand(); + + // Toggles autoskip mode on and off. In this mode, player turns are automatically skipped and only AI moves. + // However, GUI is still present and allows to observe AI moves. After this option is activated, you need to end first turn manually. + // Press [Shift] before your turn starts to not skip it. + void handleAutoskipCommand(); + + // Gives you control over specified AI player. If none is specified gives you control over all AI players + void handleControlaiCommand(std::istringstream& singleWordBuffer); + + // Change battle AI used by neutral creatures to the one specified. Persists through game quit + void handleSetBattleAICommand(std::istringstream& singleWordBuffer); + + // Redraw the current screen + void handleRedrawCommand(); + + // Prints information about current screen, and saves both screens as .bmp in root folder + void handleScreenCommand(); + + // Set the state indicating if dialog box is active to "no" + void handleNotDialogCommand(); + + // Displays tree view of currently present VCMI common GUI elements + void handleGuiCommand(); + + // Dumps all game text, maps text and campaign maps text into Client log between BEGIN TEXT EXPORT and END TEXT EXPORT + void handleConvertTextCommand(); + + // Saves current game configuration into extracted/configuration folder + void handleGetConfigCommand(); + + // Dumps all scripts in Extracted/Scripts + void handleGetScriptsCommand(); + + // Dumps all .txt files from DATA into Extracted/DATA + void handleGetTextCommand(); + + // Extract .def animation as BMP files + void handleDef2bmpCommand(std::istringstream& singleWordBuffer); + + // Export file into Extracted directory + void handleExtractCommand(std::istringstream& singleWordBuffer); + + // Print in console the current bonuses for curent army + void handleBonusesCommand(std::istringstream & singleWordBuffer); + + // Get what artifact is present on artifact slot with specified ID for hero with specified ID + void handleTellCommand(std::istringstream& singleWordBuffer); + + // Show current movement points, max movement points on land / max movement points on water. + void handleMpCommand(); + + // set - sets special temporary settings that reset on game quit. + void handleSetCommand(std::istringstream& singleWordBuffer); + + // Unlocks specific mutex known in VCMI code as "pim" + void handleUnlockCommand(std::istringstream& singleWordBuffer); + + // Crashes the game forcing an exception + void handleCrashCommand(); + + // Prints in Chat the given message void printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType = ELogLevel::NOT_SET); - void handleGoSolo(); - void handleControlAi(const std::string &colorName); + void printInfoAboutInterfaceObject(const CIntObject *obj, int level); + void giveTurn(const PlayerColor &color); public: ClientCommandManager() = default; - void processCommand(const std::string &message, bool calledFromIngameConsole); + void processCommand(const std::string & message, bool calledFromIngameConsole); };