1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-24 03:47:18 +02:00

Win/loss condition texts use MetaString

This commit is contained in:
Ivan Savenko 2023-06-18 13:51:11 +03:00
parent 56d69e790b
commit d51fe62804
16 changed files with 230 additions and 180 deletions

View File

@ -188,7 +188,7 @@ void AIGateway::showShipyardDialog(const IShipyard * obj)
void AIGateway::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult)
{
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf);
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString());
NET_EVENT_HANDLER;
logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.getStr(), player, player.getStr(), (victoryLossCheckResult.victory() ? "won" : "lost"));

View File

@ -202,7 +202,7 @@ void VCAI::showShipyardDialog(const IShipyard * obj)
void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult)
{
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf);
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString());
NET_EVENT_HANDLER;
logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.getStr(), player, player.getStr(), (victoryLossCheckResult.victory() ? "won" : "lost"));
if(player == playerID)

View File

@ -1585,9 +1585,9 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
{
if (victoryLossCheckResult.loss() && cb->getPlayerStatus(playerID) == EPlayerStatus::INGAME) //enemy has lost
{
std::string str = CGI->generaltexth->translate(victoryLossCheckResult.messageToSelf);
boost::algorithm::replace_first(str, "%s", CGI->generaltexth->capColors[player.getNum()]);
showInfoDialog(str, std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(CComponent::flag, player.getNum(), 0)));
MetaString message = victoryLossCheckResult.messageToSelf;
message.appendLocalString(EMetaText::COLOR, player.getNum());
showInfoDialog(message.toString(), std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(CComponent::flag, player.getNum(), 0)));
}
}
}

View File

@ -210,9 +210,9 @@ void InfoCard::changeSelection()
iconsMapSizes->setFrame(mapInfo->getMapSizeIconId());
const CMapHeader * header = mapInfo->mapHeader.get();
iconsVictoryCondition->setFrame(header->victoryIconIndex);
labelVictoryConditionText->setText(header->victoryMessage);
labelVictoryConditionText->setText(header->victoryMessage.toString());
iconsLossCondition->setFrame(header->defeatIconIndex);
labelLossConditionText->setText(header->defeatMessage);
labelLossConditionText->setText(header->defeatMessage.toString());
flagbox->recreate();
labelDifficulty->setText(CGI->generaltexth->arraytxt[142 + mapInfo->mapHeader->difficulty]);
iconDifficulty->setSelected(SEL->getCurrentDifficulty());

View File

@ -54,7 +54,7 @@ bool mapSorter::operator()(const std::shared_ptr<CMapInfo> aaa, const std::share
return (a->version < b->version);
break;
case _loscon: //by loss conditions
return (a->defeatMessage < b->defeatMessage);
return (a->defeatIconIndex < b->defeatIconIndex);
break;
case _playerAm: //by player amount
int playerAmntB, humenPlayersB, playerAmntA, humenPlayersA;
@ -89,7 +89,7 @@ bool mapSorter::operator()(const std::shared_ptr<CMapInfo> aaa, const std::share
return (a->width < b->width);
break;
case _viccon: //by victory conditions
return (a->victoryMessage < b->victoryMessage);
return (a->victoryIconIndex < b->victoryIconIndex);
break;
case _name: //by name
return boost::ilexicographical_compare(a->name, b->name);

View File

@ -2035,10 +2035,10 @@ bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(const PlayerColor & player) const
{
const std::string & messageWonSelf = VLC->generaltexth->allTexts[659];
const std::string & messageWonOther = VLC->generaltexth->allTexts[5];
const std::string & messageLostSelf = VLC->generaltexth->allTexts[7];
const std::string & messageLostOther = VLC->generaltexth->allTexts[8];
const MetaString messageWonSelf = MetaString::createFromTextID("core.genrltxt.659");
const MetaString messageWonOther = MetaString::createFromTextID("core.genrltxt.5");
const MetaString messageLostSelf = MetaString::createFromTextID("core.genrltxt.7");
const MetaString messageLostOther = MetaString::createFromTextID("core.genrltxt.8");
auto evaluateEvent = [=](const EventCondition & condition)
{

View File

@ -10,6 +10,7 @@
#pragma once
#include "CCreatureSet.h"
#include "MetaString.h"
#include "int3.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -101,12 +102,12 @@ struct DLL_LINKAGE InfoAboutTown : public InfoAboutArmy
class DLL_LINKAGE EVictoryLossCheckResult
{
public:
static EVictoryLossCheckResult victory(std::string toSelf, std::string toOthers)
static EVictoryLossCheckResult victory(MetaString toSelf, MetaString toOthers)
{
return EVictoryLossCheckResult(VICTORY, toSelf, toOthers);
}
static EVictoryLossCheckResult defeat(std::string toSelf, std::string toOthers)
static EVictoryLossCheckResult defeat(MetaString toSelf, MetaString toOthers)
{
return EVictoryLossCheckResult(DEFEAT, toSelf, toOthers);
}
@ -140,8 +141,8 @@ public:
return EVictoryLossCheckResult(-intValue, messageToOthers, messageToSelf);
}
std::string messageToSelf;
std::string messageToOthers;
MetaString messageToSelf;
MetaString messageToOthers;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -157,7 +158,7 @@ private:
VICTORY= +1
};
EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers):
EVictoryLossCheckResult(si32 intValue, MetaString toSelf, MetaString toOthers):
messageToSelf(toSelf),
messageToOthers(toOthers),
intValue(intValue)

View File

@ -22,18 +22,38 @@
VCMI_LIB_NAMESPACE_BEGIN
MetaString MetaString::createFromRawString(const std::string & value)
{
MetaString result;
result.appendRawString(value);
return result;
}
MetaString MetaString::createFromTextID(const std::string & value)
{
MetaString result;
result.appendTextID(value);
return result;
}
void MetaString::appendLocalString(EMetaText type, ui32 serial)
{
message.push_back(EMessage::APPEND_LOCAL_STRING);
localStrings.emplace_back(type, serial);
}
void MetaString::appendRawString(std::string value)
void MetaString::appendRawString(const std::string & value)
{
message.push_back(EMessage::APPEND_RAW_STRING);
exactStrings.push_back(value);
}
void MetaString::appendTextID(const std::string & value)
{
message.push_back(EMessage::APPEND_TEXTID_STRING);
stringsTextID.push_back(value);
}
void MetaString::appendNumber(int64_t value)
{
message.push_back(EMessage::APPEND_NUMBER);
@ -52,6 +72,12 @@ void MetaString::replaceRawString(const std::string &txt)
exactStrings.push_back(txt);
}
void MetaString::replaceTextID(const std::string & value)
{
message.push_back(EMessage::REPLACE_TEXTID_STRING);
stringsTextID.push_back(value);
}
void MetaString::replaceNumber(int64_t txt)
{
message.push_back(EMessage::REPLACE_NUMBER);
@ -68,6 +94,7 @@ void MetaString::clear()
{
exactStrings.clear();
localStrings.clear();
stringsTextID.clear();
message.clear();
numbers.clear();
}
@ -167,93 +194,94 @@ DLL_LINKAGE std::string MetaString::toString() const
size_t exSt = 0;
size_t loSt = 0;
size_t nums = 0;
size_t textID = 0;
dst.clear();
for(const auto & elem : message)
{
switch(elem)
{
case EMessage::APPEND_RAW_STRING:
dst += exactStrings[exSt++];
break;
case EMessage::APPEND_LOCAL_STRING:
{
std::string hlp = getLocalString(localStrings[loSt++]);
dst += hlp;
}
break;
case EMessage::APPEND_NUMBER:
dst += std::to_string(numbers[nums++]);
break;
case EMessage::REPLACE_RAW_STRING:
boost::replace_first(dst, "%s", exactStrings[exSt++]);
break;
case EMessage::REPLACE_LOCAL_STRING:
{
std::string hlp = getLocalString(localStrings[loSt++]);
boost::replace_first(dst, "%s", hlp);
}
break;
case EMessage::REPLACE_NUMBER:
boost::replace_first(dst, "%d", std::to_string(numbers[nums++]));
break;
case EMessage::REPLACE_POSITIVE_NUMBER:
boost::replace_first(dst, "%+d", '+' + std::to_string(numbers[nums++]));
break;
default:
logGlobal->error("MetaString processing error! Received message of type %d", static_cast<int>(elem));
assert(0);
break;
case EMessage::APPEND_RAW_STRING:
dst += exactStrings[exSt++];
break;
case EMessage::APPEND_LOCAL_STRING:
dst += getLocalString(localStrings[loSt++]);
break;
case EMessage::APPEND_TEXTID_STRING:
dst += VLC->generaltexth->translate(stringsTextID[textID++]);
break;
case EMessage::APPEND_NUMBER:
dst += std::to_string(numbers[nums++]);
break;
case EMessage::REPLACE_RAW_STRING:
boost::replace_first(dst, "%s", exactStrings[exSt++]);
break;
case EMessage::REPLACE_LOCAL_STRING:
boost::replace_first(dst, "%s", getLocalString(localStrings[loSt++]));
break;
case EMessage::REPLACE_TEXTID_STRING:
boost::replace_first(dst, "%s", VLC->generaltexth->translate(stringsTextID[textID++]));
break;
case EMessage::REPLACE_NUMBER:
boost::replace_first(dst, "%d", std::to_string(numbers[nums++]));
break;
case EMessage::REPLACE_POSITIVE_NUMBER:
boost::replace_first(dst, "%+d", '+' + std::to_string(numbers[nums++]));
break;
default:
logGlobal->error("MetaString processing error! Received message of type %d", static_cast<int>(elem));
assert(0);
break;
}
}
return dst;
}
DLL_LINKAGE std::string MetaString::buildList () const
DLL_LINKAGE std::string MetaString::buildList() const
{
size_t exSt = 0;
size_t loSt = 0;
size_t nums = 0;
size_t textID = 0;
std::string lista;
for (int i = 0; i < message.size(); ++i)
for(int i = 0; i < message.size(); ++i)
{
if (i > 0 && (message[i] == EMessage::APPEND_RAW_STRING || message[i] == EMessage::APPEND_LOCAL_STRING))
if(i > 0 && (message[i] == EMessage::APPEND_RAW_STRING || message[i] == EMessage::APPEND_LOCAL_STRING))
{
if (exSt == exactStrings.size() - 1)
if(exSt == exactStrings.size() - 1)
lista += VLC->generaltexth->allTexts[141]; //" and "
else
lista += ", ";
}
switch (message[i])
switch(message[i])
{
case EMessage::APPEND_RAW_STRING:
lista += exactStrings[exSt++];
break;
case EMessage::APPEND_LOCAL_STRING:
{
std::string hlp = getLocalString (localStrings[loSt++]);
lista += hlp;
}
lista += getLocalString(localStrings[loSt++]);
break;
case EMessage::APPEND_TEXTID_STRING:
lista += VLC->generaltexth->translate(stringsTextID[textID++]);
break;
case EMessage::APPEND_NUMBER:
lista += std::to_string(numbers[nums++]);
break;
case EMessage::REPLACE_RAW_STRING:
lista.replace (lista.find("%s"), 2, exactStrings[exSt++]);
lista.replace(lista.find("%s"), 2, exactStrings[exSt++]);
break;
case EMessage::REPLACE_LOCAL_STRING:
{
std::string hlp = getLocalString (localStrings[loSt++]);
lista.replace (lista.find("%s"), 2, hlp);
}
lista.replace(lista.find("%s"), 2, getLocalString(localStrings[loSt++]));
break;
case EMessage::REPLACE_TEXTID_STRING:
lista.replace(lista.find("%s"), 2, VLC->generaltexth->translate(stringsTextID[textID++]));
break;
case EMessage::REPLACE_NUMBER:
lista.replace (lista.find("%d"), 2, std::to_string(numbers[nums++]));
lista.replace(lista.find("%d"), 2, std::to_string(numbers[nums++]));
break;
default:
logGlobal->error("MetaString processing error! Received message of type %d",int(message[i]));
logGlobal->error("MetaString processing error! Received message of type %d", int(message[i]));
}
}
return lista;
}

View File

@ -15,6 +15,7 @@ class CreatureID;
class CStackBasicDescriptor;
using TQuantity = si32;
/// Strings classes that can be used as replacement in MetaString
enum class EMetaText : uint8_t
{
GENERAL_TXT = 1,
@ -37,6 +38,8 @@ enum class EMetaText : uint8_t
JK_TXT
};
/// Class for string formatting tools that also support transfer over network with localization using language of local install
/// Can be used to compose resulting text from multiple line segments and with placeholder replacement
class DLL_LINKAGE MetaString
{
private:
@ -44,9 +47,11 @@ private:
{
APPEND_RAW_STRING,
APPEND_LOCAL_STRING,
APPEND_TEXTID_STRING,
APPEND_NUMBER,
REPLACE_RAW_STRING,
REPLACE_LOCAL_STRING,
REPLACE_TEXTID_STRING,
REPLACE_NUMBER,
REPLACE_POSITIVE_NUMBER
};
@ -55,22 +60,32 @@ private:
std::vector<std::pair<EMetaText,ui32> > localStrings;
std::vector<std::string> exactStrings;
std::vector<std::string> stringsTextID;
std::vector<int64_t> numbers;
std::string getLocalString(const std::pair<EMetaText, ui32> & txt) const;
public:
/// Creates MetaString and appends provided raw string to it
static MetaString createFromRawString(const std::string & value);
/// Creates MetaString and appends provided text ID string to it
static MetaString createFromTextID(const std::string & value);
/// Appends local string to resulting string
void appendLocalString(EMetaText type, ui32 serial);
/// Appends raw string, without translation to resulting string
void appendRawString(std::string value);
void appendRawString(const std::string & value);
/// Appends text ID that will be translated in output
void appendTextID(const std::string & value);
/// Appends specified number to resulting string
void appendNumber(int64_t value);
/// Replaces first '%s' placeholder in string with specified local string
void replaceLocalString(EMetaText type, ui32 serial);
/// Replaces first '%s' placeholder in string with specified fixed, untranslated string
void replaceRawString(const std::string &txt);
void replaceRawString(const std::string & txt);
/// Repalces first '%s' placeholder with string ID that will be translated in output
void replaceTextID(const std::string & value);
/// Replaces first '%d' placeholder in string with specified number
void replaceNumber(int64_t txt);
/// Replaces first '%+d' placeholder in string with specified number using '+' sign as prefix
@ -79,13 +94,13 @@ public:
/// Replaces first '%s' placeholder with singular or plural name depending on creatures count
void replaceCreatureName(const CreatureID & id, TQuantity count);
/// Replaces first '%s' placeholder with singular or plural name depending on creatures count
void replaceCreatureName(const CStackBasicDescriptor &stack);
void replaceCreatureName(const CStackBasicDescriptor & stack);
/// erases any existing content in the string
void clear();
///used to handle loot from creature bank
std::string buildList () const;
std::string buildList() const;
/// Convert all stored values into a single, user-readable string
std::string toString() const;
@ -97,6 +112,7 @@ public:
{
h & exactStrings;
h & localStrings;
h & stringsTextID;
h & message;
h & numbers;
}

View File

@ -398,17 +398,17 @@ void CMap::checkForObjectives()
switch (cond.condition)
{
case EventCondition::HAVE_ARTIFACT:
boost::algorithm::replace_first(event.onFulfill, "%s", VLC->arth->objects[cond.objectType]->getNameTranslated());
event.onFulfill.replaceTextID(VLC->artifacts()->getByIndex(cond.objectType)->getNameTextID());
break;
case EventCondition::HAVE_CREATURES:
boost::algorithm::replace_first(event.onFulfill, "%s", VLC->creh->objects[cond.objectType]->getNameSingularTranslated());
boost::algorithm::replace_first(event.onFulfill, "%d", std::to_string(cond.value));
event.onFulfill.replaceTextID(VLC->creatures()->getByIndex(cond.objectType)->getNameSingularTextID());
event.onFulfill.replaceNumber(cond.value);
break;
case EventCondition::HAVE_RESOURCES:
boost::algorithm::replace_first(event.onFulfill, "%s", VLC->generaltexth->restypes[cond.objectType]);
boost::algorithm::replace_first(event.onFulfill, "%d", std::to_string(cond.value));
event.onFulfill.replaceLocalString(EMetaText::RES_NAMES, cond.objectType);
event.onFulfill.replaceNumber(cond.value);
break;
case EventCondition::HAVE_BUILDING:
@ -424,10 +424,10 @@ void CMap::checkForObjectives()
{
const auto * town = dynamic_cast<const CGTownInstance *>(cond.object);
if (town)
boost::algorithm::replace_first(event.onFulfill, "%s", town->getNameTranslated());
event.onFulfill.replaceRawString(town->getNameTranslated());
const auto * hero = dynamic_cast<const CGHeroInstance *>(cond.object);
if (hero)
boost::algorithm::replace_first(event.onFulfill, "%s", hero->getNameTranslated());
event.onFulfill.replaceRawString(hero->getNameTranslated());
}
break;
@ -439,7 +439,7 @@ void CMap::checkForObjectives()
{
const auto * hero = dynamic_cast<const CGHeroInstance *>(cond.object);
if (hero)
boost::algorithm::replace_first(event.onFulfill, "%s", hero->getNameTranslated());
event.onFulfill.replaceRawString(hero->getNameTranslated());
}
break;
case EventCondition::TRANSPORT:
@ -499,7 +499,6 @@ void CMap::removeQuestInstance(CQuest * quest)
}
void CMap::setUniqueInstanceName(CGObjectInstance * obj)
{
//this gives object unique name even if objects are removed later

View File

@ -96,29 +96,29 @@ void CMapHeader::setupEvents()
//Victory condition - defeat all
TriggeredEvent standardVictory;
standardVictory.effect.type = EventEffect::VICTORY;
standardVictory.effect.toOtherMessage = "core.genrltxt.5";
standardVictory.effect.toOtherMessage.appendTextID("core.genrltxt.5");
standardVictory.identifier = "standardVictory";
standardVictory.description.clear(); // TODO: display in quest window
standardVictory.onFulfill = "core.genrltxt.659";
standardVictory.onFulfill.appendTextID("core.genrltxt.659");
standardVictory.trigger = EventExpression(victoryCondition);
//Loss condition - 7 days without town
TriggeredEvent standardDefeat;
standardDefeat.effect.type = EventEffect::DEFEAT;
standardDefeat.effect.toOtherMessage = "core.genrltxt.8";
standardDefeat.effect.toOtherMessage.appendTextID("core.genrltxt.8");
standardDefeat.identifier = "standardDefeat";
standardDefeat.description.clear(); // TODO: display in quest window
standardDefeat.onFulfill = "core.genrltxt.7";
standardDefeat.onFulfill.appendTextID("core.genrltxt.7");
standardDefeat.trigger = EventExpression(defeatCondition);
triggeredEvents.push_back(standardVictory);
triggeredEvents.push_back(standardDefeat);
victoryIconIndex = 11;
victoryMessage = VLC->generaltexth->victoryConditions[0];
victoryMessage.appendTextID("core.vcdesc.0");
defeatIconIndex = 3;
defeatMessage = VLC->generaltexth->lossCondtions[0];
defeatMessage.appendTextID("core.lcdesc.0");
}
CMapHeader::CMapHeader() : version(EMapFormat::VCMI), height(72), width(72),

View File

@ -13,6 +13,7 @@
#include "../CModVersion.h"
#include "../LogicalExpression.h"
#include "../int3.h"
#include "../MetaString.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -159,7 +160,7 @@ struct DLL_LINKAGE EventEffect
si8 type;
/// message that will be sent to other players
std::string toOtherMessage;
MetaString toOtherMessage;
template <typename Handler>
void serialize(Handler & h, const int version)
@ -178,10 +179,10 @@ struct DLL_LINKAGE TriggeredEvent
std::string identifier;
/// string-description, for use in UI (capture town to win)
std::string description;
MetaString description;
/// Message that will be displayed when this event is triggered (You captured town. You won!)
std::string onFulfill;
MetaString onFulfill;
/// Effect of this event. TODO: refactor into something more flexible
EventEffect effect;
@ -229,8 +230,8 @@ public:
/// maximum level for heroes. This is the default value.
ui8 levelLimit;
std::string victoryMessage;
std::string defeatMessage;
MetaString victoryMessage;
MetaString defeatMessage;
ui16 victoryIconIndex;
ui16 defeatIconIndex;

View File

@ -300,6 +300,8 @@ enum class ELossConditionType : uint8_t
void CMapLoaderH3M::readVictoryLossConditions()
{
mapHeader->triggeredEvents.clear();
mapHeader->victoryMessage.clear();
mapHeader->defeatMessage.clear();
auto vicCondition = static_cast<EVictoryConditionType>(reader->readUInt8());
@ -309,18 +311,18 @@ void CMapLoaderH3M::readVictoryLossConditions()
TriggeredEvent standardVictory;
standardVictory.effect.type = EventEffect::VICTORY;
standardVictory.effect.toOtherMessage = "core.genrltxt.5";
standardVictory.effect.toOtherMessage.appendTextID("core.genrltxt.5");
standardVictory.identifier = "standardVictory";
standardVictory.description.clear(); // TODO: display in quest window
standardVictory.onFulfill = "core.genrltxt.659";
standardVictory.onFulfill.appendTextID("core.genrltxt.659");
standardVictory.trigger = EventExpression(victoryCondition);
TriggeredEvent standardDefeat;
standardDefeat.effect.type = EventEffect::DEFEAT;
standardDefeat.effect.toOtherMessage = "core.genrltxt.8";
standardDefeat.effect.toOtherMessage.appendTextID("core.genrltxt.8");
standardDefeat.identifier = "standardDefeat";
standardDefeat.description.clear(); // TODO: display in quest window
standardDefeat.onFulfill = "core.genrltxt.7";
standardDefeat.onFulfill.appendTextID("core.genrltxt.7");
standardDefeat.trigger = EventExpression(defeatCondition);
// Specific victory conditions
@ -329,7 +331,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
// create normal condition
mapHeader->triggeredEvents.push_back(standardVictory);
mapHeader->victoryIconIndex = 11;
mapHeader->victoryMessage = VLC->generaltexth->victoryConditions[0];
mapHeader->victoryMessage.appendTextID("core.vcdesc.0");
}
else
{
@ -339,7 +341,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
specialVictory.description.clear(); // TODO: display in quest window
mapHeader->victoryIconIndex = static_cast<ui16>(vicCondition);
mapHeader->victoryMessage = VLC->generaltexth->victoryConditions[static_cast<size_t>(vicCondition) + 1];
mapHeader->victoryMessage.appendTextID(TextIdentifier("core.vcdesc", static_cast<size_t>(vicCondition) + 1).get());
bool allowNormalVictory = reader->readBool();
bool appliesToAI = reader->readBool();
@ -368,8 +370,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
EventCondition cond(EventCondition::HAVE_ARTIFACT);
cond.objectType = reader->readArtifact();
specialVictory.effect.toOtherMessage = "core.genrltxt.281";
specialVictory.onFulfill = "core.genrltxt.280";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.281");
specialVictory.onFulfill.appendTextID("core.genrltxt.280");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -379,8 +381,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = reader->readCreature();
cond.value = reader->readInt32();
specialVictory.effect.toOtherMessage = "core.genrltxt.277";
specialVictory.onFulfill = "core.genrltxt.6";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.277");
specialVictory.onFulfill.appendTextID("core.genrltxt.6");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -390,8 +392,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = reader->readUInt8();
cond.value = reader->readInt32();
specialVictory.effect.toOtherMessage = "core.genrltxt.279";
specialVictory.onFulfill = "core.genrltxt.278";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.279");
specialVictory.onFulfill.appendTextID("core.genrltxt.278");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -405,8 +407,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = BuildingID::FORT + reader->readUInt8();
oper.expressions.emplace_back(cond);
specialVictory.effect.toOtherMessage = "core.genrltxt.283";
specialVictory.onFulfill = "core.genrltxt.282";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.283");
specialVictory.onFulfill.appendTextID("core.genrltxt.282");
specialVictory.trigger = EventExpression(oper);
break;
}
@ -418,8 +420,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
if(cond.position.z > 2)
cond.position = int3(-1, -1, -1);
specialVictory.effect.toOtherMessage = "core.genrltxt.285";
specialVictory.onFulfill = "core.genrltxt.284";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.285");
specialVictory.onFulfill.appendTextID("core.genrltxt.284");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -429,8 +431,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = Obj::HERO;
cond.position = reader->readInt3();
specialVictory.effect.toOtherMessage = "core.genrltxt.253";
specialVictory.onFulfill = "core.genrltxt.252";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.253");
specialVictory.onFulfill.appendTextID("core.genrltxt.252");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -440,8 +442,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = Obj::TOWN;
cond.position = reader->readInt3();
specialVictory.effect.toOtherMessage = "core.genrltxt.250";
specialVictory.onFulfill = "core.genrltxt.249";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.250");
specialVictory.onFulfill.appendTextID("core.genrltxt.249");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -451,8 +453,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = Obj::MONSTER;
cond.position = reader->readInt3();
specialVictory.effect.toOtherMessage = "core.genrltxt.287";
specialVictory.onFulfill = "core.genrltxt.286";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.287");
specialVictory.onFulfill.appendTextID("core.genrltxt.286");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -462,8 +464,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
oper.expressions.emplace_back(EventCondition(EventCondition::CONTROL, 0, Obj::CREATURE_GENERATOR1));
oper.expressions.emplace_back(EventCondition(EventCondition::CONTROL, 0, Obj::CREATURE_GENERATOR4));
specialVictory.effect.toOtherMessage = "core.genrltxt.289";
specialVictory.onFulfill = "core.genrltxt.288";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.289");
specialVictory.onFulfill.appendTextID("core.genrltxt.288");
specialVictory.trigger = EventExpression(oper);
break;
}
@ -472,8 +474,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
EventCondition cond(EventCondition::CONTROL);
cond.objectType = Obj::MINE;
specialVictory.effect.toOtherMessage = "core.genrltxt.291";
specialVictory.onFulfill = "core.genrltxt.290";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.291");
specialVictory.onFulfill.appendTextID("core.genrltxt.290");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -483,8 +485,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.objectType = reader->readUInt8();
cond.position = reader->readInt3();
specialVictory.effect.toOtherMessage = "core.genrltxt.293";
specialVictory.onFulfill = "core.genrltxt.292";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.293");
specialVictory.onFulfill.appendTextID("core.genrltxt.292");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -493,8 +495,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
EventCondition cond(EventCondition::DESTROY);
cond.objectType = Obj::MONSTER;
specialVictory.effect.toOtherMessage = "Defeat all monsters"; // Eliminate all monsters on the map
specialVictory.onFulfill = "You have defeated all of the monsters plaguing this land!";
specialVictory.effect.toOtherMessage.appendRawString("Defeat all monsters"); // Eliminate all monsters on the map
specialVictory.onFulfill.appendRawString("You have defeated all of the monsters plaguing this land!");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -503,8 +505,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
EventCondition cond(EventCondition::DAYS_PASSED);
cond.value = reader->readUInt32();
specialVictory.effect.toOtherMessage = "Survive beyond a time limit"; // Survive by month %d, week %d, day %d.
specialVictory.onFulfill = "You have managed to survive!";
specialVictory.effect.toOtherMessage.appendRawString("Survive beyond a time limit"); // Survive by month %d, week %d, day %d.
specialVictory.onFulfill.appendRawString("You have managed to survive!");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -526,8 +528,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
// if normal victory allowed - add one more quest
if(allowNormalVictory)
{
mapHeader->victoryMessage += " / ";
mapHeader->victoryMessage += VLC->generaltexth->victoryConditions[0];
mapHeader->victoryMessage.appendRawString(" / ");
mapHeader->victoryMessage.appendTextID("core.vcdesc.0");
mapHeader->triggeredEvents.push_back(standardVictory);
}
mapHeader->triggeredEvents.push_back(specialVictory);
@ -538,18 +540,17 @@ void CMapLoaderH3M::readVictoryLossConditions()
if(lossCond == ELossConditionType::LOSSSTANDARD)
{
mapHeader->defeatIconIndex = 3;
mapHeader->defeatMessage = VLC->generaltexth->lossCondtions[0];
mapHeader->defeatMessage.appendTextID("core.lcdesc.0");
}
else
{
TriggeredEvent specialDefeat;
specialDefeat.effect.type = EventEffect::DEFEAT;
specialDefeat.effect.toOtherMessage = "core.genrltxt.5";
specialDefeat.effect.toOtherMessage.appendTextID("core.genrltxt.5");
specialDefeat.identifier = "specialDefeat";
specialDefeat.description.clear(); // TODO: display in quest window
mapHeader->defeatIconIndex = static_cast<ui16>(lossCond);
mapHeader->defeatMessage = VLC->generaltexth->lossCondtions[static_cast<size_t>(lossCond) + 1];
switch(lossCond)
{
@ -561,8 +562,10 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.position = reader->readInt3();
noneOf.expressions.emplace_back(cond);
specialDefeat.onFulfill = "core.genrltxt.251";
specialDefeat.onFulfill.appendTextID("core.genrltxt.251");
specialDefeat.trigger = EventExpression(noneOf);
mapHeader->defeatMessage.appendTextID("core.lcdesc.1");
break;
}
case ELossConditionType::LOSSHERO:
@ -573,8 +576,10 @@ void CMapLoaderH3M::readVictoryLossConditions()
cond.position = reader->readInt3();
noneOf.expressions.emplace_back(cond);
specialDefeat.onFulfill = "core.genrltxt.253";
specialDefeat.onFulfill.appendTextID("core.genrltxt.253");
specialDefeat.trigger = EventExpression(noneOf);
mapHeader->defeatMessage.appendTextID("core.lcdesc.2");
break;
}
case ELossConditionType::TIMEEXPIRES:
@ -582,8 +587,10 @@ void CMapLoaderH3M::readVictoryLossConditions()
EventCondition cond(EventCondition::DAYS_PASSED);
cond.value = reader->readUInt16();
specialDefeat.onFulfill = "core.genrltxt.254";
specialDefeat.onFulfill.appendTextID("core.genrltxt.254");
specialDefeat.trigger = EventExpression(cond);
mapHeader->defeatMessage.appendTextID("core.lcdesc.3");
break;
}
}

View File

@ -423,10 +423,10 @@ void CMapFormatJson::serializeHeader(JsonSerializeFormat & handler)
handler.serializeLIC("allowedHeroes", &HeroTypeID::decode, &HeroTypeID::encode, VLC->heroh->getDefaultAllowed(), mapHeader->allowedHeroes);
handler.serializeString("victoryString", mapHeader->victoryMessage);
// handler.serializeString("victoryString", mapHeader->victoryMessage);
handler.serializeInt("victoryIconIndex", mapHeader->victoryIconIndex);
handler.serializeString("defeatString", mapHeader->defeatMessage);
// handler.serializeString("defeatString", mapHeader->defeatMessage);
handler.serializeInt("defeatIconIndex", mapHeader->defeatIconIndex);
}
@ -683,10 +683,10 @@ void CMapFormatJson::readTriggeredEvent(TriggeredEvent & event, const JsonNode &
{
using namespace TriggeredEventsDetail;
event.onFulfill = source["message"].String();
event.description = source["description"].String();
// event.onFulfill = source["message"].String();
// event.description = source["description"].String();
event.effect.type = vstd::find_pos(typeNames, source["effect"]["type"].String());
event.effect.toOtherMessage = source["effect"]["messageToSend"].String();
// event.effect.toOtherMessage = source["effect"]["messageToSend"].String();
event.trigger = EventExpression(source["condition"], JsonToCondition); // logical expression
}
@ -704,16 +704,16 @@ void CMapFormatJson::writeTriggeredEvent(const TriggeredEvent & event, JsonNode
{
using namespace TriggeredEventsDetail;
if(!event.onFulfill.empty())
dest["message"].String() = event.onFulfill;
// if(!event.onFulfill.empty())
// dest["message"].String() = event.onFulfill;
if(!event.description.empty())
dest["description"].String() = event.description;
// if(!event.description.empty())
// dest["description"].String() = event.description;
dest["effect"]["type"].String() = typeNames.at(static_cast<size_t>(event.effect.type));
if(!event.effect.toOtherMessage.empty())
dest["effect"]["messageToSend"].String() = event.effect.toOtherMessage;
// if(!event.effect.toOtherMessage.empty())
// dest["effect"]["messageToSend"].String() = event.effect.toOtherMessage;
dest["condition"] = event.trigger.toJson(ConditionToJson);
}

View File

@ -166,8 +166,8 @@ MapSettings::MapSettings(MapController & ctrl, QWidget *parent) :
};
//victory & loss messages
ui->victoryMessageEdit->setText(QString::fromStdString(controller.map()->victoryMessage));
ui->defeatMessageEdit->setText(QString::fromStdString(controller.map()->defeatMessage));
ui->victoryMessageEdit->setText(QString::fromStdString(controller.map()->victoryMessage.toString()));
ui->defeatMessageEdit->setText(QString::fromStdString(controller.map()->defeatMessage.toString()));
//victory & loss conditions
const std::array<std::string, 8> conditionStringsWin = {
@ -550,8 +550,8 @@ void MapSettings::on_pushButton_clicked()
//victory & loss messages
controller.map()->victoryMessage = ui->victoryMessageEdit->text().toStdString();
controller.map()->defeatMessage = ui->defeatMessageEdit->text().toStdString();
controller.map()->victoryMessage = MetaString::createFromRawString(ui->victoryMessageEdit->text().toStdString());
controller.map()->defeatMessage = MetaString::createFromRawString(ui->defeatMessageEdit->text().toStdString());
//victory & loss conditions
EventCondition victoryCondition(EventCondition::STANDARD_WIN);
@ -561,19 +561,19 @@ void MapSettings::on_pushButton_clicked()
//Victory condition - defeat all
TriggeredEvent standardVictory;
standardVictory.effect.type = EventEffect::VICTORY;
standardVictory.effect.toOtherMessage = "core.genrltxt.5";
standardVictory.effect.toOtherMessage.appendTextID("core.genrltxt.5");
standardVictory.identifier = "standardVictory";
standardVictory.description.clear(); // TODO: display in quest window
standardVictory.onFulfill = "core.genrltxt.659";
standardVictory.onFulfill.appendTextID("core.genrltxt.659");
standardVictory.trigger = EventExpression(victoryCondition);
//Loss condition - 7 days without town
TriggeredEvent standardDefeat;
standardDefeat.effect.type = EventEffect::DEFEAT;
standardDefeat.effect.toOtherMessage = "core.genrltxt.8";
standardDefeat.effect.toOtherMessage.appendTextID("core.genrltxt.8");
standardDefeat.identifier = "standardDefeat";
standardDefeat.description.clear(); // TODO: display in quest window
standardDefeat.onFulfill = "core.genrltxt.7";
standardDefeat.onFulfill.appendTextID("core.genrltxt.7");
standardDefeat.trigger = EventExpression(defeatCondition);
controller.map()->triggeredEvents.clear();
@ -583,7 +583,7 @@ void MapSettings::on_pushButton_clicked()
{
controller.map()->triggeredEvents.push_back(standardVictory);
controller.map()->victoryIconIndex = 11;
controller.map()->victoryMessage = VLC->generaltexth->victoryConditions[0];
controller.map()->victoryMessage.appendTextID(VLC->generaltexth->victoryConditions[0]);
}
else
{
@ -595,7 +595,7 @@ void MapSettings::on_pushButton_clicked()
specialVictory.description.clear(); // TODO: display in quest window
controller.map()->victoryIconIndex = vicCondition;
controller.map()->victoryMessage = VLC->generaltexth->victoryConditions[size_t(vicCondition) + 1];
controller.map()->victoryMessage.appendTextID(VLC->generaltexth->victoryConditions[size_t(vicCondition) + 1]);
switch(vicCondition)
{
@ -603,8 +603,8 @@ void MapSettings::on_pushButton_clicked()
EventCondition cond(EventCondition::HAVE_ARTIFACT);
assert(victoryTypeWidget);
cond.objectType = victoryTypeWidget->currentData().toInt();
specialVictory.effect.toOtherMessage = "core.genrltxt.281";
specialVictory.onFulfill = "core.genrltxt.280";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.281");
specialVictory.onFulfill.appendTextID("core.genrltxt.280");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -614,8 +614,8 @@ void MapSettings::on_pushButton_clicked()
assert(victoryTypeWidget);
cond.objectType = victoryTypeWidget->currentData().toInt();
cond.value = victoryValueWidget->text().toInt();
specialVictory.effect.toOtherMessage = "core.genrltxt.277";
specialVictory.onFulfill = "core.genrltxt.276";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.277");
specialVictory.onFulfill.appendTextID("core.genrltxt.276");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -625,8 +625,8 @@ void MapSettings::on_pushButton_clicked()
assert(victoryTypeWidget);
cond.objectType = victoryTypeWidget->currentData().toInt();
cond.value = victoryValueWidget->text().toInt();
specialVictory.effect.toOtherMessage = "core.genrltxt.279";
specialVictory.onFulfill = "core.genrltxt.278";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.279");
specialVictory.onFulfill.appendTextID("core.genrltxt.278");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -638,8 +638,8 @@ void MapSettings::on_pushButton_clicked()
int townIdx = victorySelectWidget->currentData().toInt();
if(townIdx > -1)
cond.position = controller.map()->objects[townIdx]->pos;
specialVictory.effect.toOtherMessage = "core.genrltxt.283";
specialVictory.onFulfill = "core.genrltxt.282";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.283");
specialVictory.onFulfill.appendTextID("core.genrltxt.282");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -650,8 +650,8 @@ void MapSettings::on_pushButton_clicked()
cond.objectType = Obj::TOWN;
int townIdx = victoryTypeWidget->currentData().toInt();
cond.position = controller.map()->objects[townIdx]->pos;
specialVictory.effect.toOtherMessage = "core.genrltxt.250";
specialVictory.onFulfill = "core.genrltxt.249";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.250");
specialVictory.onFulfill.appendTextID("core.genrltxt.249");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -662,8 +662,8 @@ void MapSettings::on_pushButton_clicked()
cond.objectType = Obj::HERO;
int heroIdx = victoryTypeWidget->currentData().toInt();
cond.position = controller.map()->objects[heroIdx]->pos;
specialVictory.effect.toOtherMessage = "core.genrltxt.253";
specialVictory.onFulfill = "core.genrltxt.252";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.253");
specialVictory.onFulfill.appendTextID("core.genrltxt.252");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -675,8 +675,8 @@ void MapSettings::on_pushButton_clicked()
int townIdx = victorySelectWidget->currentData().toInt();
if(townIdx > -1)
cond.position = controller.map()->objects[townIdx]->pos;
specialVictory.effect.toOtherMessage = "core.genrltxt.293";
specialVictory.onFulfill = "core.genrltxt.292";
specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.293");
specialVictory.onFulfill.appendTextID("core.genrltxt.292");
specialVictory.trigger = EventExpression(cond);
break;
}
@ -697,8 +697,8 @@ void MapSettings::on_pushButton_clicked()
// if normal victory allowed - add one more quest
if(ui->standardVictoryCheck->isChecked())
{
controller.map()->victoryMessage += " / ";
controller.map()->victoryMessage += VLC->generaltexth->victoryConditions[0];
controller.map()->victoryMessage.appendRawString(" / ");
controller.map()->victoryMessage.appendTextID(VLC->generaltexth->victoryConditions[0]);
controller.map()->triggeredEvents.push_back(standardVictory);
}
controller.map()->triggeredEvents.push_back(specialVictory);
@ -709,7 +709,7 @@ void MapSettings::on_pushButton_clicked()
{
controller.map()->triggeredEvents.push_back(standardDefeat);
controller.map()->defeatIconIndex = 3;
controller.map()->defeatMessage = VLC->generaltexth->lossCondtions[0];
controller.map()->defeatMessage.appendTextID("core.lcdesc.0");
}
else
{
@ -721,7 +721,6 @@ void MapSettings::on_pushButton_clicked()
specialDefeat.description.clear(); // TODO: display in quest window
controller.map()->defeatIconIndex = lossCondition;
controller.map()->defeatMessage = VLC->generaltexth->lossCondtions[size_t(lossCondition) + 1];
switch(lossCondition)
{
@ -733,8 +732,9 @@ void MapSettings::on_pushButton_clicked()
int townIdx = loseTypeWidget->currentData().toInt();
cond.position = controller.map()->objects[townIdx]->pos;
noneOf.expressions.push_back(cond);
specialDefeat.onFulfill = "core.genrltxt.251";
specialDefeat.onFulfill.appendTextID("core.genrltxt.251");
specialDefeat.trigger = EventExpression(noneOf);
controller.map()->defeatMessage.appendTextID("core.lcdesc.1");
break;
}
@ -746,8 +746,9 @@ void MapSettings::on_pushButton_clicked()
int townIdx = loseTypeWidget->currentData().toInt();
cond.position = controller.map()->objects[townIdx]->pos;
noneOf.expressions.push_back(cond);
specialDefeat.onFulfill = "core.genrltxt.253";
specialDefeat.onFulfill.appendTextID("core.genrltxt.253");
specialDefeat.trigger = EventExpression(noneOf);
controller.map()->defeatMessage.appendTextID("core.lcdesc.2");
break;
}
@ -755,8 +756,9 @@ void MapSettings::on_pushButton_clicked()
EventCondition cond(EventCondition::DAYS_PASSED);
assert(loseValueWidget);
cond.value = expiredDate(loseValueWidget->text());
specialDefeat.onFulfill = "core.genrltxt.254";
specialDefeat.onFulfill.appendTextID("core.genrltxt.254");
specialDefeat.trigger = EventExpression(cond);
controller.map()->defeatMessage.appendTextID("core.lcdesc.3");
break;
}
@ -764,7 +766,7 @@ void MapSettings::on_pushButton_clicked()
EventCondition cond(EventCondition::DAYS_WITHOUT_TOWN);
assert(loseValueWidget);
cond.value = loseValueWidget->text().toInt();
specialDefeat.onFulfill = "core.genrltxt.7";
specialDefeat.onFulfill.appendTextID("core.genrltxt.7");
specialDefeat.trigger = EventExpression(cond);
break;
}

View File

@ -5790,12 +5790,8 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
void CGameHandler::getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const
{
out.player = player;
out.text.clear();
out.text.appendRawString(VLC->generaltexth->translate(victoryLossCheckResult.messageToOthers));
// hackish, insert one player-specific string, if applicable
if (victoryLossCheckResult.messageToOthers.find("%s") != std::string::npos)
out.text.replaceLocalString(EMetaText::COLOR, player.getNum());
out.text = victoryLossCheckResult.messageToOthers;
out.text.replaceLocalString(EMetaText::COLOR, player.getNum());
out.components.emplace_back(Component::EComponentType::FLAG, player.getNum(), 0, 0);
}