MetaString.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. * MetaString.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "MetaString.h"
  12. #include "CArtHandler.h"
  13. #include "CCreatureHandler.h"
  14. #include "CCreatureSet.h"
  15. #include "CGeneralTextHandler.h"
  16. #include "CSkillHandler.h"
  17. #include "GameConstants.h"
  18. #include "VCMI_Lib.h"
  19. #include "mapObjectConstructors/CObjectClassesHandler.h"
  20. #include "spells/CSpellHandler.h"
  21. VCMI_LIB_NAMESPACE_BEGIN
  22. MetaString MetaString::createFromRawString(const std::string & value)
  23. {
  24. MetaString result;
  25. result.appendRawString(value);
  26. return result;
  27. }
  28. MetaString MetaString::createFromTextID(const std::string & value)
  29. {
  30. MetaString result;
  31. result.appendTextID(value);
  32. return result;
  33. }
  34. void MetaString::appendLocalString(EMetaText type, ui32 serial)
  35. {
  36. message.push_back(EMessage::APPEND_LOCAL_STRING);
  37. localStrings.emplace_back(type, serial);
  38. }
  39. void MetaString::appendRawString(const std::string & value)
  40. {
  41. message.push_back(EMessage::APPEND_RAW_STRING);
  42. exactStrings.push_back(value);
  43. }
  44. void MetaString::appendTextID(const std::string & value)
  45. {
  46. message.push_back(EMessage::APPEND_TEXTID_STRING);
  47. stringsTextID.push_back(value);
  48. }
  49. void MetaString::appendNumber(int64_t value)
  50. {
  51. message.push_back(EMessage::APPEND_NUMBER);
  52. numbers.push_back(value);
  53. }
  54. void MetaString::replaceLocalString(EMetaText type, ui32 serial)
  55. {
  56. message.push_back(EMessage::REPLACE_LOCAL_STRING);
  57. localStrings.emplace_back(type, serial);
  58. }
  59. void MetaString::replaceRawString(const std::string &txt)
  60. {
  61. message.push_back(EMessage::REPLACE_RAW_STRING);
  62. exactStrings.push_back(txt);
  63. }
  64. void MetaString::replaceTextID(const std::string & value)
  65. {
  66. message.push_back(EMessage::REPLACE_TEXTID_STRING);
  67. stringsTextID.push_back(value);
  68. }
  69. void MetaString::replaceNumber(int64_t txt)
  70. {
  71. message.push_back(EMessage::REPLACE_NUMBER);
  72. numbers.push_back(txt);
  73. }
  74. void MetaString::replacePositiveNumber(int64_t txt)
  75. {
  76. message.push_back(EMessage::REPLACE_POSITIVE_NUMBER);
  77. numbers.push_back(txt);
  78. }
  79. void MetaString::clear()
  80. {
  81. exactStrings.clear();
  82. localStrings.clear();
  83. stringsTextID.clear();
  84. message.clear();
  85. numbers.clear();
  86. }
  87. bool MetaString::empty() const
  88. {
  89. return message.empty();
  90. }
  91. std::string MetaString::getLocalString(const std::pair<EMetaText, ui32> & txt) const
  92. {
  93. EMetaText type = txt.first;
  94. int ser = txt.second;
  95. switch(type)
  96. {
  97. case EMetaText::ART_NAMES:
  98. {
  99. const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
  100. if(art)
  101. return art->getNameTranslated();
  102. return "#!#";
  103. }
  104. case EMetaText::ART_DESCR:
  105. {
  106. const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
  107. if(art)
  108. return art->getDescriptionTranslated();
  109. return "#!#";
  110. }
  111. case EMetaText::ART_EVNTS:
  112. {
  113. const auto * art = ArtifactID(ser).toArtifact(VLC->artifacts());
  114. if(art)
  115. return art->getEventTranslated();
  116. return "#!#";
  117. }
  118. case EMetaText::CRE_PL_NAMES:
  119. {
  120. const auto * cre = CreatureID(ser).toCreature(VLC->creatures());
  121. if(cre)
  122. return cre->getNamePluralTranslated();
  123. return "#!#";
  124. }
  125. case EMetaText::CRE_SING_NAMES:
  126. {
  127. const auto * cre = CreatureID(ser).toCreature(VLC->creatures());
  128. if(cre)
  129. return cre->getNameSingularTranslated();
  130. return "#!#";
  131. }
  132. case EMetaText::MINE_NAMES:
  133. {
  134. return VLC->generaltexth->translate("core.minename", ser);
  135. }
  136. case EMetaText::MINE_EVNTS:
  137. {
  138. return VLC->generaltexth->translate("core.mineevnt", ser);
  139. }
  140. case EMetaText::SPELL_NAME:
  141. {
  142. const auto * spell = SpellID(ser).toSpell(VLC->spells());
  143. if(spell)
  144. return spell->getNameTranslated();
  145. return "#!#";
  146. }
  147. case EMetaText::OBJ_NAMES:
  148. return VLC->objtypeh->getObjectName(ser, 0);
  149. case EMetaText::SEC_SKILL_NAME:
  150. return VLC->skillh->getByIndex(ser)->getNameTranslated();
  151. case EMetaText::GENERAL_TXT:
  152. return VLC->generaltexth->translate("core.genrltxt", ser);
  153. case EMetaText::RES_NAMES:
  154. return VLC->generaltexth->translate("core.restypes", ser);
  155. case EMetaText::ARRAY_TXT:
  156. return VLC->generaltexth->translate("core.arraytxt", ser);
  157. case EMetaText::CREGENS:
  158. return VLC->objtypeh->getObjectName(Obj::CREATURE_GENERATOR1, ser);
  159. case EMetaText::CREGENS4:
  160. return VLC->objtypeh->getObjectName(Obj::CREATURE_GENERATOR4, ser);
  161. case EMetaText::ADVOB_TXT:
  162. return VLC->generaltexth->translate("core.advevent", ser);
  163. case EMetaText::COLOR:
  164. return VLC->generaltexth->translate("vcmi.capitalColors", ser);
  165. case EMetaText::JK_TXT:
  166. return VLC->generaltexth->translate("core.jktext", ser);
  167. default:
  168. logGlobal->error("Failed string substitution because type is %d", static_cast<int>(type));
  169. return "#@#";
  170. }
  171. }
  172. DLL_LINKAGE std::string MetaString::toString() const
  173. {
  174. std::string dst;
  175. size_t exSt = 0;
  176. size_t loSt = 0;
  177. size_t nums = 0;
  178. size_t textID = 0;
  179. dst.clear();
  180. for(const auto & elem : message)
  181. {
  182. switch(elem)
  183. {
  184. case EMessage::APPEND_RAW_STRING:
  185. dst += exactStrings[exSt++];
  186. break;
  187. case EMessage::APPEND_LOCAL_STRING:
  188. dst += getLocalString(localStrings[loSt++]);
  189. break;
  190. case EMessage::APPEND_TEXTID_STRING:
  191. dst += VLC->generaltexth->translate(stringsTextID[textID++]);
  192. break;
  193. case EMessage::APPEND_NUMBER:
  194. dst += std::to_string(numbers[nums++]);
  195. break;
  196. case EMessage::REPLACE_RAW_STRING:
  197. boost::replace_first(dst, "%s", exactStrings[exSt++]);
  198. break;
  199. case EMessage::REPLACE_LOCAL_STRING:
  200. boost::replace_first(dst, "%s", getLocalString(localStrings[loSt++]));
  201. break;
  202. case EMessage::REPLACE_TEXTID_STRING:
  203. boost::replace_first(dst, "%s", VLC->generaltexth->translate(stringsTextID[textID++]));
  204. break;
  205. case EMessage::REPLACE_NUMBER:
  206. boost::replace_first(dst, "%d", std::to_string(numbers[nums++]));
  207. break;
  208. case EMessage::REPLACE_POSITIVE_NUMBER:
  209. boost::replace_first(dst, "%+d", '+' + std::to_string(numbers[nums++]));
  210. break;
  211. default:
  212. logGlobal->error("MetaString processing error! Received message of type %d", static_cast<int>(elem));
  213. assert(0);
  214. break;
  215. }
  216. }
  217. return dst;
  218. }
  219. DLL_LINKAGE std::string MetaString::buildList() const
  220. {
  221. size_t exSt = 0;
  222. size_t loSt = 0;
  223. size_t nums = 0;
  224. size_t textID = 0;
  225. std::string lista;
  226. for(int i = 0; i < message.size(); ++i)
  227. {
  228. if(i > 0 && (message[i] == EMessage::APPEND_RAW_STRING || message[i] == EMessage::APPEND_LOCAL_STRING))
  229. {
  230. if(exSt == exactStrings.size() - 1)
  231. lista += VLC->generaltexth->allTexts[141]; //" and "
  232. else
  233. lista += ", ";
  234. }
  235. switch(message[i])
  236. {
  237. case EMessage::APPEND_RAW_STRING:
  238. lista += exactStrings[exSt++];
  239. break;
  240. case EMessage::APPEND_LOCAL_STRING:
  241. lista += getLocalString(localStrings[loSt++]);
  242. break;
  243. case EMessage::APPEND_TEXTID_STRING:
  244. lista += VLC->generaltexth->translate(stringsTextID[textID++]);
  245. break;
  246. case EMessage::APPEND_NUMBER:
  247. lista += std::to_string(numbers[nums++]);
  248. break;
  249. case EMessage::REPLACE_RAW_STRING:
  250. lista.replace(lista.find("%s"), 2, exactStrings[exSt++]);
  251. break;
  252. case EMessage::REPLACE_LOCAL_STRING:
  253. lista.replace(lista.find("%s"), 2, getLocalString(localStrings[loSt++]));
  254. break;
  255. case EMessage::REPLACE_TEXTID_STRING:
  256. lista.replace(lista.find("%s"), 2, VLC->generaltexth->translate(stringsTextID[textID++]));
  257. break;
  258. case EMessage::REPLACE_NUMBER:
  259. lista.replace(lista.find("%d"), 2, std::to_string(numbers[nums++]));
  260. break;
  261. default:
  262. logGlobal->error("MetaString processing error! Received message of type %d", int(message[i]));
  263. }
  264. }
  265. return lista;
  266. }
  267. void MetaString::replaceCreatureName(const CreatureID & id, TQuantity count) //adds sing or plural name;
  268. {
  269. if (count == 1)
  270. replaceLocalString (EMetaText::CRE_SING_NAMES, id);
  271. else
  272. replaceLocalString (EMetaText::CRE_PL_NAMES, id);
  273. }
  274. void MetaString::replaceCreatureName(const CStackBasicDescriptor & stack)
  275. {
  276. assert(stack.type); //valid type
  277. replaceCreatureName(stack.type->getId(), stack.count);
  278. }
  279. bool MetaString::operator == (const MetaString & other) const
  280. {
  281. return message == other.message && localStrings == other.localStrings && exactStrings == other.exactStrings && stringsTextID == other.stringsTextID && numbers == other.numbers;
  282. }
  283. void MetaString::jsonSerialize(JsonNode & dest) const
  284. {
  285. JsonNode jsonMessage;
  286. JsonNode jsonLocalStrings;
  287. JsonNode jsonExactStrings;
  288. JsonNode jsonStringsTextID;
  289. JsonNode jsonNumbers;
  290. for (const auto & entry : message )
  291. {
  292. JsonNode value;
  293. value.Float() = static_cast<int>(entry);
  294. jsonMessage.Vector().push_back(value);
  295. }
  296. for (const auto & entry : localStrings )
  297. {
  298. JsonNode value;
  299. value.Integer() = static_cast<int>(entry.first) * 10000 + entry.second;
  300. jsonLocalStrings.Vector().push_back(value);
  301. }
  302. for (const auto & entry : exactStrings )
  303. {
  304. JsonNode value;
  305. value.String() = entry;
  306. jsonExactStrings.Vector().push_back(value);
  307. }
  308. for (const auto & entry : stringsTextID )
  309. {
  310. JsonNode value;
  311. value.String() = entry;
  312. jsonStringsTextID.Vector().push_back(value);
  313. }
  314. for (const auto & entry : numbers )
  315. {
  316. JsonNode value;
  317. value.Integer() = entry;
  318. jsonNumbers.Vector().push_back(value);
  319. }
  320. dest["message"] = jsonMessage;
  321. dest["localStrings"] = jsonLocalStrings;
  322. dest["exactStrings"] = jsonExactStrings;
  323. dest["stringsTextID"] = jsonStringsTextID;
  324. dest["numbers"] = jsonNumbers;
  325. }
  326. void MetaString::jsonDeserialize(const JsonNode & source)
  327. {
  328. clear();
  329. if (source.isString())
  330. {
  331. // compatibility with fields that were converted from string to MetaString
  332. if(boost::starts_with(source.String(), "core.") || boost::starts_with(source.String(), "vcmi."))
  333. appendTextID(source.String());
  334. else
  335. appendRawString(source.String());
  336. return;
  337. }
  338. for (const auto & entry : source["message"].Vector() )
  339. message.push_back(static_cast<EMessage>(entry.Integer()));
  340. for (const auto & entry : source["localStrings"].Vector() )
  341. localStrings.push_back({ static_cast<EMetaText>(entry.Integer() / 10000), entry.Integer() % 10000 });
  342. for (const auto & entry : source["exactStrings"].Vector() )
  343. exactStrings.push_back(entry.String());
  344. for (const auto & entry : source["stringsTextID"].Vector() )
  345. stringsTextID.push_back(entry.String());
  346. for (const auto & entry : source["numbers"].Vector() )
  347. numbers.push_back(entry.Integer());
  348. }
  349. VCMI_LIB_NAMESPACE_END