MetaString.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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 "CCreatureHandler.h"
  13. #include "entities/artifact/CArtifact.h"
  14. #include "entities/faction/CFaction.h"
  15. #include "entities/hero/CHero.h"
  16. #include "entities/ResourceTypeHandler.h"
  17. #include "texts/CGeneralTextHandler.h"
  18. #include "CSkillHandler.h"
  19. #include "GameConstants.h"
  20. #include "GameLibrary.h"
  21. #include "mapObjects/army/CStackBasicDescriptor.h"
  22. #include "mapObjectConstructors/CObjectClassesHandler.h"
  23. #include "spells/CSpellHandler.h"
  24. #include "serializer/JsonSerializeFormat.h"
  25. VCMI_LIB_NAMESPACE_BEGIN
  26. MetaString MetaString::createFromRawString(const std::string & value)
  27. {
  28. MetaString result;
  29. result.appendRawString(value);
  30. return result;
  31. }
  32. MetaString MetaString::createFromTextID(const std::string & value)
  33. {
  34. MetaString result;
  35. result.appendTextID(value);
  36. return result;
  37. }
  38. MetaString MetaString::createFromName(const GameResID& id)
  39. {
  40. MetaString result;
  41. result.appendName(id);
  42. return result;
  43. }
  44. void MetaString::appendLocalString(EMetaText type, ui32 serial)
  45. {
  46. message.push_back(EMessage::APPEND_LOCAL_STRING);
  47. localStrings.emplace_back(type, serial);
  48. }
  49. void MetaString::appendRawString(const std::string & value)
  50. {
  51. message.push_back(EMessage::APPEND_RAW_STRING);
  52. exactStrings.push_back(value);
  53. }
  54. void MetaString::appendTextID(const std::string & value)
  55. {
  56. if (!value.empty())
  57. {
  58. message.push_back(EMessage::APPEND_TEXTID_STRING);
  59. stringsTextID.push_back(value);
  60. }
  61. }
  62. void MetaString::appendNumber(int64_t value)
  63. {
  64. message.push_back(EMessage::APPEND_NUMBER);
  65. numbers.push_back(value);
  66. }
  67. void MetaString::appendEOL()
  68. {
  69. message.push_back(EMessage::APPEND_EOL);
  70. }
  71. void MetaString::replaceLocalString(EMetaText type, ui32 serial)
  72. {
  73. message.push_back(EMessage::REPLACE_LOCAL_STRING);
  74. localStrings.emplace_back(type, serial);
  75. }
  76. void MetaString::replaceRawString(const std::string &txt)
  77. {
  78. message.push_back(EMessage::REPLACE_RAW_STRING);
  79. exactStrings.push_back(txt);
  80. }
  81. void MetaString::replaceTextID(const std::string & value)
  82. {
  83. message.push_back(EMessage::REPLACE_TEXTID_STRING);
  84. stringsTextID.push_back(value);
  85. }
  86. void MetaString::replaceNumber(int64_t txt)
  87. {
  88. message.push_back(EMessage::REPLACE_NUMBER);
  89. numbers.push_back(txt);
  90. }
  91. void MetaString::replacePositiveNumber(int64_t txt)
  92. {
  93. message.push_back(EMessage::REPLACE_POSITIVE_NUMBER);
  94. numbers.push_back(txt);
  95. }
  96. void MetaString::clear()
  97. {
  98. exactStrings.clear();
  99. localStrings.clear();
  100. stringsTextID.clear();
  101. message.clear();
  102. numbers.clear();
  103. }
  104. bool MetaString::empty() const
  105. {
  106. return message.empty() || toString().empty();
  107. }
  108. std::string MetaString::getLocalString(const std::pair<EMetaText, ui32> & txt) const
  109. {
  110. EMetaText type = txt.first;
  111. int ser = txt.second;
  112. switch(type)
  113. {
  114. case EMetaText::GENERAL_TXT:
  115. return LIBRARY->generaltexth->translate("core.genrltxt", ser);
  116. case EMetaText::ARRAY_TXT:
  117. return LIBRARY->generaltexth->translate("core.arraytxt", ser);
  118. case EMetaText::ADVOB_TXT:
  119. return LIBRARY->generaltexth->translate("core.advevent", ser);
  120. case EMetaText::JK_TXT:
  121. return LIBRARY->generaltexth->translate("core.jktext", ser);
  122. default:
  123. logGlobal->error("Failed string substitution because type is %d", static_cast<int>(type));
  124. return "#@#";
  125. }
  126. }
  127. DLL_LINKAGE std::string MetaString::toString() const
  128. {
  129. std::string dst;
  130. size_t exSt = 0;
  131. size_t loSt = 0;
  132. size_t nums = 0;
  133. size_t textID = 0;
  134. dst.clear();
  135. for(const auto & elem : message)
  136. {
  137. switch(elem)
  138. {
  139. case EMessage::APPEND_RAW_STRING:
  140. dst += exactStrings.at(exSt++);
  141. break;
  142. case EMessage::APPEND_LOCAL_STRING:
  143. dst += getLocalString(localStrings.at(loSt++));
  144. break;
  145. case EMessage::APPEND_TEXTID_STRING:
  146. dst += LIBRARY->generaltexth->translate(stringsTextID.at(textID++));
  147. break;
  148. case EMessage::APPEND_NUMBER:
  149. dst += std::to_string(numbers.at(nums++));
  150. break;
  151. case EMessage::APPEND_EOL:
  152. dst += '\n';
  153. break;
  154. case EMessage::REPLACE_RAW_STRING:
  155. boost::replace_first(dst, "%s", exactStrings.at(exSt++));
  156. break;
  157. case EMessage::REPLACE_LOCAL_STRING:
  158. boost::replace_first(dst, "%s", getLocalString(localStrings.at(loSt++)));
  159. break;
  160. case EMessage::REPLACE_TEXTID_STRING:
  161. boost::replace_first(dst, "%s", LIBRARY->generaltexth->translate(stringsTextID.at(textID++)));
  162. break;
  163. case EMessage::REPLACE_NUMBER:
  164. boost::replace_first(dst, "%d", std::to_string(numbers.at(nums++)));
  165. break;
  166. case EMessage::REPLACE_POSITIVE_NUMBER:
  167. if (dst.find("%+d") != std::string::npos)
  168. {
  169. int64_t value = numbers.at(nums);
  170. if (value > 0)
  171. boost::replace_first(dst, "%+d", '+' + std::to_string(value));
  172. else
  173. boost::replace_first(dst, "%+d", std::to_string(value));
  174. nums++;
  175. }
  176. else
  177. boost::replace_first(dst, "%d", std::to_string(numbers.at(nums++)));
  178. break;
  179. default:
  180. logGlobal->error("MetaString processing error! Received message of type %d", static_cast<int>(elem));
  181. assert(0);
  182. break;
  183. }
  184. }
  185. return dst;
  186. }
  187. DLL_LINKAGE std::string MetaString::buildList() const
  188. {
  189. size_t exSt = 0;
  190. size_t loSt = 0;
  191. size_t nums = 0;
  192. size_t textID = 0;
  193. std::string lista;
  194. for(int i = 0; i < message.size(); ++i)
  195. {
  196. if(i > 0 && (message.at(i) == EMessage::APPEND_RAW_STRING || message.at(i) == EMessage::APPEND_LOCAL_STRING))
  197. {
  198. if(exSt == exactStrings.size() - 1)
  199. lista += LIBRARY->generaltexth->allTexts[141]; //" and "
  200. else
  201. lista += ", ";
  202. }
  203. switch(message.at(i))
  204. {
  205. case EMessage::APPEND_RAW_STRING:
  206. lista += exactStrings.at(exSt++);
  207. break;
  208. case EMessage::APPEND_LOCAL_STRING:
  209. lista += getLocalString(localStrings.at(loSt++));
  210. break;
  211. case EMessage::APPEND_TEXTID_STRING:
  212. lista += LIBRARY->generaltexth->translate(stringsTextID.at(textID++));
  213. break;
  214. case EMessage::APPEND_NUMBER:
  215. lista += std::to_string(numbers.at(nums++));
  216. break;
  217. case EMessage::APPEND_EOL:
  218. lista += '\n';
  219. break;
  220. case EMessage::REPLACE_RAW_STRING:
  221. lista.replace(lista.find("%s"), 2, exactStrings.at(exSt++));
  222. break;
  223. case EMessage::REPLACE_LOCAL_STRING:
  224. lista.replace(lista.find("%s"), 2, getLocalString(localStrings.at(loSt++)));
  225. break;
  226. case EMessage::REPLACE_TEXTID_STRING:
  227. lista.replace(lista.find("%s"), 2, LIBRARY->generaltexth->translate(stringsTextID.at(textID++)));
  228. break;
  229. case EMessage::REPLACE_NUMBER:
  230. lista.replace(lista.find("%d"), 2, std::to_string(numbers.at(nums++)));
  231. break;
  232. default:
  233. logGlobal->error("MetaString processing error! Received message of type %d", int(message.at(i)));
  234. }
  235. }
  236. return lista;
  237. }
  238. bool MetaString::operator == (const MetaString & other) const
  239. {
  240. return message == other.message && localStrings == other.localStrings && exactStrings == other.exactStrings && stringsTextID == other.stringsTextID && numbers == other.numbers;
  241. }
  242. void MetaString::jsonSerialize(JsonNode & dest) const
  243. {
  244. JsonNode jsonMessage;
  245. JsonNode jsonLocalStrings;
  246. JsonNode jsonExactStrings;
  247. JsonNode jsonStringsTextID;
  248. JsonNode jsonNumbers;
  249. for (const auto & entry : message )
  250. {
  251. JsonNode value;
  252. value.Float() = static_cast<int>(entry);
  253. jsonMessage.Vector().push_back(value);
  254. }
  255. for (const auto & entry : localStrings )
  256. {
  257. JsonNode value;
  258. value.Integer() = static_cast<int>(entry.first) * 10000 + entry.second;
  259. jsonLocalStrings.Vector().push_back(value);
  260. }
  261. for (const auto & entry : exactStrings )
  262. {
  263. JsonNode value;
  264. value.String() = entry;
  265. jsonExactStrings.Vector().push_back(value);
  266. }
  267. for (const auto & entry : stringsTextID )
  268. {
  269. JsonNode value;
  270. value.String() = entry;
  271. jsonStringsTextID.Vector().push_back(value);
  272. }
  273. for (const auto & entry : numbers )
  274. {
  275. JsonNode value;
  276. value.Integer() = entry;
  277. jsonNumbers.Vector().push_back(value);
  278. }
  279. dest["message"] = jsonMessage;
  280. dest["localStrings"] = jsonLocalStrings;
  281. dest["exactStrings"] = jsonExactStrings;
  282. dest["stringsTextID"] = jsonStringsTextID;
  283. dest["numbers"] = jsonNumbers;
  284. }
  285. void MetaString::jsonDeserialize(const JsonNode & source)
  286. {
  287. clear();
  288. if (source.isString())
  289. {
  290. // compatibility with fields that were converted from string to MetaString
  291. if(boost::starts_with(source.String(), "core.") || boost::starts_with(source.String(), "vcmi."))
  292. appendTextID(source.String());
  293. else
  294. appendRawString(source.String());
  295. return;
  296. }
  297. for (const auto & entry : source["message"].Vector() )
  298. message.push_back(static_cast<EMessage>(entry.Integer()));
  299. for (const auto & entry : source["localStrings"].Vector() )
  300. localStrings.push_back({ static_cast<EMetaText>(entry.Integer() / 10000), entry.Integer() % 10000 });
  301. for (const auto & entry : source["exactStrings"].Vector() )
  302. exactStrings.push_back(entry.String());
  303. for (const auto & entry : source["stringsTextID"].Vector() )
  304. stringsTextID.push_back(entry.String());
  305. for (const auto & entry : source["numbers"].Vector() )
  306. numbers.push_back(entry.Integer());
  307. }
  308. void MetaString::serializeJson(JsonSerializeFormat & handler)
  309. {
  310. if(handler.saving)
  311. jsonSerialize(const_cast<JsonNode&>(handler.getCurrent()));
  312. if(!handler.saving)
  313. jsonDeserialize(handler.getCurrent());
  314. }
  315. void MetaString::appendName(const ArtifactID & id)
  316. {
  317. appendTextID(id.toEntity(LIBRARY)->getNameTextID());
  318. }
  319. void MetaString::appendName(const SpellID & id)
  320. {
  321. appendTextID(id.toEntity(LIBRARY)->getNameTextID());
  322. }
  323. void MetaString::appendName(const PlayerColor & id)
  324. {
  325. appendTextID(TextIdentifier("vcmi.capitalColors", id.getNum()).get());
  326. }
  327. void MetaString::appendName(const CreatureID & id, TQuantity count)
  328. {
  329. if(count == 1)
  330. appendNameSingular(id);
  331. else
  332. appendNamePlural(id);
  333. }
  334. void MetaString::appendName(const GameResID& id)
  335. {
  336. appendTextID(id.toResource()->getNameTextID());
  337. }
  338. void MetaString::appendNameSingular(const CreatureID & id)
  339. {
  340. appendTextID(id.toEntity(LIBRARY)->getNameSingularTextID());
  341. }
  342. void MetaString::appendNamePlural(const CreatureID & id)
  343. {
  344. appendTextID(id.toEntity(LIBRARY)->getNamePluralTextID());
  345. }
  346. void MetaString::replaceName(const ArtifactID & id)
  347. {
  348. replaceTextID(id.toEntity(LIBRARY)->getNameTextID());
  349. }
  350. void MetaString::replaceName(const FactionID & id)
  351. {
  352. replaceTextID(id.toEntity(LIBRARY)->getNameTextID());
  353. }
  354. void MetaString::replaceName(const MapObjectID & id, const MapObjectSubID & subId)
  355. {
  356. replaceTextID(LIBRARY->objtypeh->getObjectName(id, subId));
  357. }
  358. void MetaString::replaceName(const PlayerColor & id)
  359. {
  360. replaceTextID(TextIdentifier("vcmi.capitalColors", id.getNum()).get());
  361. }
  362. void MetaString::replaceName(const SecondarySkill & id)
  363. {
  364. replaceTextID(LIBRARY->skillh->getById(id)->getNameTextID());
  365. }
  366. void MetaString::replaceName(const SpellID & id)
  367. {
  368. replaceTextID(id.toEntity(LIBRARY)->getNameTextID());
  369. }
  370. void MetaString::replaceName(const GameResID& id)
  371. {
  372. replaceTextID(id.toResource()->getNameTextID());
  373. }
  374. void MetaString::replaceNameSingular(const CreatureID & id)
  375. {
  376. replaceTextID(id.toEntity(LIBRARY)->getNameSingularTextID());
  377. }
  378. void MetaString::replaceNamePlural(const CreatureID & id)
  379. {
  380. replaceTextID(id.toEntity(LIBRARY)->getNamePluralTextID());
  381. }
  382. void MetaString::replaceName(const CreatureID & id, TQuantity count) //adds sing or plural name;
  383. {
  384. if(count == 1)
  385. replaceNameSingular(id);
  386. else
  387. replaceNamePlural(id);
  388. }
  389. void MetaString::replaceName(const CStackBasicDescriptor & stack)
  390. {
  391. replaceName(stack.getId(), stack.getCount());
  392. }
  393. VCMI_LIB_NAMESPACE_END