MetaString.cpp 11 KB

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