functions.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  1. /*
  2. FinalSun/FinalAlert 2 Mission Editor
  3. Copyright (C) 1999-2024 Electronic Arts, Inc.
  4. Authored by Matthias Wagner
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. */
  16. // standard functions
  17. #include "stdafx.h"
  18. #include "FinalSunDlg.h"
  19. #include "TSoptions.h"
  20. #include "variables.h"
  21. #include "functions.h"
  22. #include "inlines.h"
  23. #include "mmsystem.h"
  24. #define DBG
  25. #undef DBG
  26. #define DBG2
  27. #undef DBG2
  28. bool isValidUtf8(const char* utf8)
  29. {
  30. // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32
  31. auto utf8Count = strlen(utf8);
  32. if (utf8Count == 0)
  33. return true;
  34. // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1)
  35. auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, utf8Count, nullptr, 0);
  36. return unterminatedCountWChars > 0;
  37. }
  38. std::wstring utf8ToUtf16(const std::string& utf8)
  39. {
  40. // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32
  41. if (utf8.size() == 0)
  42. // MultiByteToWideChar does not support passing in cbMultiByte == 0
  43. return L"";
  44. // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1)
  45. auto utf8Count = utf8.size();
  46. auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, nullptr, 0);
  47. if (unterminatedCountWChars == 0)
  48. {
  49. throw std::runtime_error("UTF8 -> UTF16 conversion failed");
  50. }
  51. std::wstring utf16;
  52. utf16.resize(unterminatedCountWChars);
  53. if (MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, utf16.data(), unterminatedCountWChars) == 0)
  54. {
  55. throw std::runtime_error("UTF8 -> UTF16 conversion failed");
  56. }
  57. return utf16;
  58. }
  59. std::wstring utf8ToUtf16(const char* utf8)
  60. {
  61. // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32
  62. auto utf8Count = strlen(utf8);
  63. if (utf8Count == 0)
  64. // MultiByteToWideChar does not support passing in cbMultiByte == 0
  65. return L"";
  66. // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1)
  67. auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8, utf8Count, nullptr, 0);
  68. if (unterminatedCountWChars == 0)
  69. {
  70. throw std::runtime_error("UTF8 -> UTF16 conversion failed");
  71. }
  72. std::wstring utf16;
  73. utf16.resize(unterminatedCountWChars);
  74. if (MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8, utf8Count, utf16.data(), unterminatedCountWChars) == 0)
  75. {
  76. throw std::runtime_error("UTF8 -> UTF16 conversion failed");
  77. }
  78. return utf16;
  79. }
  80. std::string utf16ToCP(const std::wstring& utf16, int CP)
  81. {
  82. // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32
  83. if (utf16.size() == 0)
  84. // WideCharToMultiByte does not support passing in cbMultiByte == 0
  85. return "";
  86. // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1)
  87. auto utf16Count = utf16.size();
  88. auto unterminatedCountChars = WideCharToMultiByte(CP, CP == CP_UTF8 ? WC_ERR_INVALID_CHARS : 0, utf16.data(), utf16Count, nullptr, 0, nullptr, nullptr);
  89. if (unterminatedCountChars == 0)
  90. {
  91. throw std::runtime_error(CP == CP_UTF8 ? "UTF16 -> UTF8 conversion failed" : "UTF16 -> MultiByte conversion failed");
  92. }
  93. std::string cps;
  94. cps.resize(unterminatedCountChars);
  95. if (WideCharToMultiByte(CP, CP == CP_UTF8 ? WC_ERR_INVALID_CHARS : 0, utf16.data(), utf16Count, cps.data(), unterminatedCountChars, nullptr, nullptr) == 0)
  96. {
  97. throw std::runtime_error(CP == CP_UTF8 ? "UTF16 -> UTF8 conversion failed" : "UTF16 -> MultiByte conversion failed");
  98. }
  99. return cps;
  100. }
  101. std::string utf16ToUtf8(const std::wstring& utf16)
  102. {
  103. return utf16ToCP(utf16, CP_UTF8);
  104. }
  105. std::string utf16ToACP(const std::wstring& utf16)
  106. {
  107. return utf16ToCP(utf16, CP_ACP);
  108. }
  109. // strcpy for overlapping strings
  110. char *strcpy_safe( char *strDestination, const char *strSource )
  111. {
  112. /*char* buffer=new(char[strlen(strSource)+1]);
  113. strcpy(buffer, strSource);
  114. strcpy(strDestination, buffer);*/
  115. int len=strlen(strSource)+1;
  116. memmove(strDestination, strSource, len);
  117. return strDestination;
  118. }
  119. CString TranslateHouse(CString original, BOOL bToUI)
  120. {
  121. #ifdef RA2_MODE
  122. if(bToUI)
  123. {
  124. // CCStrings[*rules.sections[HOUSES].GetValue(i)].wString
  125. int i;
  126. for(i=0;i<rules.sections[HOUSES].values.size();i++)
  127. {
  128. original.Replace(*rules.sections[HOUSES].GetValue(i), CCStrings[*rules.sections[HOUSES].GetValue(i)].cString);
  129. }
  130. }
  131. else
  132. {
  133. int i;
  134. for(i=0;i<rules.sections[HOUSES].values.size();i++)
  135. {
  136. original.Replace(CCStrings[*rules.sections[HOUSES].GetValue(i)].cString, *rules.sections[HOUSES].GetValue(i));
  137. }
  138. }
  139. #endif
  140. return original;
  141. }
  142. bool deleteFile(const std::string& u8FilePath)
  143. {
  144. return DeleteFileW(utf8ToUtf16(u8FilePath).c_str()) ? true : false;
  145. }
  146. // set the status bar text in the main dialog
  147. void SetMainStatusBar(const char* text)
  148. {
  149. CFinalSunDlg* dlg=(CFinalSunDlg*)theApp.GetMainWnd();
  150. dlg->SetText(text);
  151. }
  152. // set the status bar text in the main dialog to ready
  153. void SetMainStatusBarReady()
  154. {
  155. CFinalSunDlg* dlg=(CFinalSunDlg*)theApp.GetMainWnd();
  156. dlg->SetReady();;
  157. }
  158. // Should not be required anymore
  159. void RepairTrigger(CString& triggerdata)
  160. {
  161. if(GetParam(triggerdata, 3).GetLength()==0) triggerdata=SetParam(triggerdata, 3, "0");
  162. if(GetParam(triggerdata, 4).GetLength()==0) triggerdata=SetParam(triggerdata, 4, "1");
  163. if(GetParam(triggerdata, 5).GetLength()==0) triggerdata=SetParam(triggerdata, 5, "1");
  164. if(GetParam(triggerdata, 6).GetLength()==0) triggerdata=SetParam(triggerdata, 6, "1");
  165. if(GetParam(triggerdata, 7).GetLength()==0) {
  166. triggerdata=SetParam(triggerdata, 7, "0");
  167. }
  168. }
  169. // make some UI noise
  170. void Sound(int ID)
  171. {
  172. if(theApp.m_Options.bNoSounds) return;
  173. if(ID==SOUND_NONE) return;
  174. LPCSTR lpSound=NULL;
  175. if(ID==SOUND_POSITIVE)
  176. {
  177. lpSound=MAKEINTRESOURCE(IDR_WAVE1);
  178. }
  179. else if(ID==SOUND_NEGATIVE)
  180. lpSound=MAKEINTRESOURCE(IDR_WAVE2);
  181. else if(ID==SOUND_LAYDOWNTILE)
  182. lpSound=MAKEINTRESOURCE(IDR_WAVE3);
  183. if(lpSound)
  184. {
  185. PlaySound(lpSound, GetModuleHandle(NULL), SND_ASYNC | SND_RESOURCE);
  186. }
  187. }
  188. void HandleParamList(CComboBox &cb, int type)
  189. {
  190. CString oldText;
  191. cb.GetWindowText(oldText);
  192. switch(type)
  193. {
  194. case PARAMTYPE_NOTHING:
  195. {
  196. while(cb.DeleteString(0)!=CB_ERR);
  197. cb.SetWindowText(oldText);
  198. //cb.AddString("0");
  199. }
  200. break;
  201. case PARAMTYPE_HOUSES:
  202. ListHouses(cb, TRUE, TRUE, TRUE);
  203. break;
  204. case PARAMTYPE_WAYPOINTS:
  205. ListWaypoints(cb);
  206. break;
  207. case PARAMTYPE_TEAMTYPES:
  208. ListTeamTypes(cb, FALSE);
  209. break;
  210. case PARAMTYPE_UNITTYPES:
  211. ListUnits(cb);
  212. break;
  213. case PARAMTYPE_INFANTRYTYPES:
  214. ListInfantry(cb);
  215. break;
  216. case PARAMTYPE_AIRCRAFTTYPES:
  217. ListAircraft(cb);
  218. break;
  219. case PARAMTYPE_BUILDINGTYPES:
  220. ListBuildings(cb);
  221. break;
  222. case PARAMTYPE_VIDEOS:
  223. ListMovies(cb, FALSE, TRUE);
  224. break;
  225. case PARAMTYPE_TUTORIALTEXTS:
  226. ListTutorial(cb);
  227. break;
  228. case PARAMTYPE_TRIGGERS:
  229. ListTriggers(cb);
  230. break;
  231. case PARAMTYPE_YESNO:
  232. ListYesNo(cb);
  233. break;
  234. case PARAMTYPE_SOUNDS:
  235. ListSounds(cb);
  236. break;
  237. case PARAMTYPE_THEMES:
  238. ListThemes(cb);
  239. break;
  240. case PARAMTYPE_SPEECHES:
  241. ListSpeeches(cb);
  242. break;
  243. case PARAMTYPE_SPECIALWEAPONS:
  244. ListSpecialWeapons(cb);
  245. break;
  246. case PARAMTYPE_ANIMATIONS:
  247. ListAnimations(cb);
  248. break;
  249. case PARAMTYPE_PARTICLES:
  250. ListParticles(cb);
  251. break;
  252. case PARAMTYPE_CRATETYPES:
  253. ListCrateTypes(cb);
  254. break;
  255. case PARAMTYPE_SPEECHBUBBLETYPES:
  256. ListSpeechBubbleTypes(cb);
  257. break;
  258. case PARAMTYPE_GLOBALS:
  259. ListGlobals(cb);
  260. break;
  261. case PARAMTYPE_RULESGLOBALS:
  262. ListRulesGlobals(cb);
  263. break;
  264. case PARAMTYPE_BUILDINGTYPESINI:
  265. ListBuildings(cb, TRUE);
  266. break;
  267. case PARAMTYPE_TECHTYPES:
  268. ListTechtypes(cb);
  269. break;
  270. }
  271. }
  272. void ShowOptionsDialog()
  273. {
  274. // show the options dialog, and save the options.
  275. #ifdef RA2_MODE
  276. CString game = "RA2";
  277. CString app = "FinalAlert";
  278. #else
  279. CString game = "TS";
  280. CString app = "FinalSun";
  281. #endif
  282. std::string iniFile="";
  283. CIniFile optini;
  284. iniFile=u8AppDataPath;
  285. #ifndef RA2_MODE
  286. iniFile+="\\FinalSun.ini";
  287. #else
  288. iniFile+="\\FinalAlert.ini";
  289. #endif
  290. optini.LoadFile(iniFile);
  291. CTSOptions opt;
  292. opt.m_TSEXE=theApp.m_Options.TSExe;
  293. if(opt.DoModal()==IDCANCEL) return;
  294. theApp.m_Options.TSExe=opt.m_TSEXE;
  295. optini.sections[game].values["Exe"]=theApp.m_Options.TSExe;
  296. optini.sections[app].values["Language"]=opt.m_LanguageName;
  297. BOOL bOldSearch=theApp.m_Options.bSearchLikeTS;
  298. if(!(opt.m_LikeTS==1)) {
  299. optini.sections[app].values["FileSearchLikeGame"]="yes";
  300. theApp.m_Options.bSearchLikeTS=TRUE;
  301. }
  302. else {
  303. theApp.m_Options.bSearchLikeTS=FALSE;
  304. optini.sections[app].values["FileSearchLikeGame"]="no";
  305. }
  306. auto bOldPreferLocalTheaterFiles = theApp.m_Options.bPreferLocalTheaterFiles;
  307. theApp.m_Options.bPreferLocalTheaterFiles = opt.m_PreferLocalTheaterFiles ? true : false;
  308. optini.sections[app].values["PreferLocalTheaterFiles"] = theApp.m_Options.bPreferLocalTheaterFiles ? "1" : "0";
  309. if (
  310. (
  311. (bOldPreferLocalTheaterFiles != theApp.m_Options.bPreferLocalTheaterFiles) ||
  312. (bOldSearch != theApp.m_Options.bSearchLikeTS)
  313. ) && bOptionsStartup == FALSE)
  314. MessageBox(0, GetLanguageStringACP("RestartNeeded"), "Restart", 0);
  315. CString oldLang=theApp.m_Options.LanguageName;
  316. theApp.m_Options.LanguageName=opt.m_LanguageName;
  317. if(oldLang!=theApp.m_Options.LanguageName && theApp.m_pMainWnd!=NULL && theApp.m_pMainWnd->m_hWnd!=NULL)
  318. ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateStrings();
  319. optini.SaveFile(iniFile);
  320. }
  321. BOOL DoesFileExist(LPCSTR szFile)
  322. {
  323. std::wstring file = utf8ToUtf16(szFile);
  324. HANDLE hFound=CreateFileW(file.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
  325. OPEN_EXISTING, 0, NULL);
  326. if (hFound != INVALID_HANDLE_VALUE)
  327. {
  328. CloseHandle(hFound);
  329. return TRUE;
  330. }
  331. return FALSE;
  332. }
  333. CString ToACP(const CString& utf8)
  334. {
  335. // convert to process codepage (should be UTF8 on newer systems)
  336. auto cp = GetACP();
  337. return (cp == CP_UTF8) ? utf8 : CString(utf16ToACP(utf8ToUtf16(utf8)).c_str());
  338. }
  339. // change all %n (where n is an int) in an string, to another specified string
  340. CString TranslateStringVariables(int n, const char* originaltext, const char* inserttext)
  341. {
  342. char c[50];
  343. itoa(n,c,10);
  344. char seekedstring[50];
  345. seekedstring[0]='%';
  346. seekedstring[1]=0;
  347. strcat(seekedstring, c);
  348. CString orig=originaltext;
  349. if(orig.Find(seekedstring)<0) return orig;
  350. orig.Replace(seekedstring, inserttext);
  351. return orig;
  352. }
  353. // retrieve the string name in the correct language (name is an ID).
  354. CString GetLanguageStringACP(CString name)
  355. {
  356. #ifdef RA2_MODE
  357. CString sec2=theApp.m_Options.LanguageName+"-StringsRA2";
  358. if(language.sections[sec2].values.end()==language.sections[sec2].values.find(name))
  359. {
  360. if(language.sections["English-StringsRA2"].FindName(name)>=0)
  361. {
  362. CString s=language.sections["English-StringsRA2"].values[name];
  363. return ToACP(s);
  364. }
  365. }
  366. else
  367. return ToACP(language.sections[sec2].values[name]);
  368. #endif
  369. if(language.sections[theApp.m_Options.LanguageName+"-Strings"].values.find(name)==language.sections[theApp.m_Options.LanguageName+"-Strings"].values.end())
  370. {
  371. CString s=language.sections["English-Strings"].values[name];
  372. #ifndef RA2_MODE
  373. s=TranslateStringVariables(9, s, "FinalSun");
  374. #else
  375. #ifdef YR_MODE
  376. s=TranslateStringVariables(9, s, "FinalAlert 2: Yuri's Revenge");
  377. #else
  378. s=TranslateStringVariables(9, s, "FinalAlert 2");
  379. #endif
  380. #endif
  381. return ToACP(s);
  382. }
  383. CString s;
  384. s= language.sections[theApp.m_Options.LanguageName+"-Strings"].values[name];
  385. #ifndef RA2_MODE
  386. if(s.Find("%9")>=0) s=TranslateStringVariables(9,s,"FinalSun");
  387. #else
  388. #ifdef YR_MODE
  389. if(s.Find("%9")>=0) s=TranslateStringVariables(9,s,"FinalAlert 2: Yuri's Revenge");
  390. #else
  391. if(s.Find("%9")>=0) s=TranslateStringVariables(9,s,"FinalAlert 2");
  392. #endif
  393. #endif
  394. return ToACP(s);
  395. }
  396. CString TranslateStringACP(WCHAR* u16EnglishString)
  397. {
  398. return TranslateStringACP(utf16ToUtf8(u16EnglishString).c_str());
  399. }
  400. // tranlate a string/word by using the table from english to the current language
  401. CString TranslateStringACP(CString u8EnglishString)
  402. {
  403. if (!isValidUtf8(u8EnglishString))
  404. {
  405. errstream << "TranslateStringACP(\"" << u8EnglishString << "\") called with an invalid UTF-8 string" << std::endl;
  406. return u8EnglishString;
  407. }
  408. #ifdef RA2_MODE
  409. CString sec2=theApp.m_Options.LanguageName+"-TranslationsRA2";
  410. if(language.sections[sec2].values.end()==language.sections[sec2].values.find(u8EnglishString))
  411. {
  412. if(language.sections["English-TranslationsRA2"].FindName(u8EnglishString)>=0)
  413. {
  414. CString s=language.sections["English-TranslationsRA2"].values[u8EnglishString];
  415. return ToACP(s);
  416. }
  417. }
  418. else
  419. return ToACP(language.sections[sec2].values[u8EnglishString]);
  420. #endif
  421. CString sec=theApp.m_Options.LanguageName+"-Translations";
  422. // check if the string can be translated
  423. if(language.sections[sec].values.end()==language.sections[sec].values.find(u8EnglishString))
  424. {
  425. CString seceng;
  426. seceng="English-Translations";
  427. if(language.sections[seceng].FindName(u8EnglishString)>=0)
  428. {
  429. CString s=language.sections[seceng].values[u8EnglishString];
  430. #ifndef RA2_MODE
  431. s=TranslateStringVariables(9, s, "FinalSun");
  432. #else
  433. #ifdef YR_MODE
  434. s=TranslateStringVariables(9, s, "FinalAlert 2: Yuri's Revenge");
  435. #else
  436. s=TranslateStringVariables(9, s, "FinalAlert 2");
  437. #endif
  438. #endif
  439. return ToACP(s);
  440. }
  441. #ifndef RA2_MODE
  442. return ToACP(TranslateStringVariables(9,u8EnglishString,"FinalSun"));
  443. #else
  444. #ifdef YR_MODE
  445. return ToACP(TranslateStringVariables(9,u8EnglishString,"FinalAlert 2: Yuri's Revenge"));
  446. #else
  447. return ToACP(TranslateStringVariables(9,u8EnglishString,"FinalAlert 2"));
  448. #endif
  449. #endif
  450. }
  451. CString s=language.sections[sec].values[u8EnglishString];
  452. #ifndef RA2_MODE
  453. s=TranslateStringVariables(9,s,"FinalSun");
  454. #else
  455. #ifdef YR_MODE
  456. s=TranslateStringVariables(9,s,"FinalAlert 2: Yuri's Revenge");
  457. #else
  458. s=TranslateStringVariables(9,s,"FinalAlert 2");
  459. #endif
  460. #endif
  461. return ToACP(s);
  462. }
  463. void TruncSpace(string& str)
  464. {
  465. CString cstr=str.data();
  466. TruncSpace(cstr);
  467. str=cstr;
  468. }
  469. void TruncSpace(CString& str)
  470. {
  471. str.TrimLeft();
  472. str.TrimRight();
  473. if(str.Find(" ")>=0) str.Delete(str.Find(" "), str.GetLength()-str.Find(" "));
  474. }
  475. CString GetText(CWnd* wnd){
  476. CString str;
  477. wnd->GetWindowText(str);
  478. return str;
  479. }
  480. CString GetText(CSliderCtrl* wnd)
  481. {
  482. int v=wnd->GetPos();
  483. char c[150];
  484. itoa(v,c,10);
  485. return(c);
  486. }
  487. CString GetText(CComboBox* wnd){
  488. CString str;
  489. if(wnd->GetCurSel()!=-1)
  490. {
  491. wnd->GetLBText(wnd->GetCurSel(), str);
  492. return str;
  493. }
  494. wnd->GetWindowText(str);
  495. return(str);
  496. }
  497. void Info(const char* data, string& house, string& type, int& strength, int& x, int& y, string & other)
  498. {
  499. other="";
  500. house=GetParam(data, 0);
  501. type=GetParam(data, 1);
  502. strength=atoi(GetParam(data, 2));
  503. y=atoi(GetParam(data, 3));
  504. x=atoi(GetParam(data, 4));
  505. CString tmp;
  506. BOOL takeABreak=FALSE;
  507. int i=1;
  508. do{
  509. tmp=GetParam(data, 4+i);
  510. //MessageBox(0,tmp.data(),"",0);
  511. if(tmp!="")
  512. {
  513. other+=",";
  514. other+=tmp;
  515. }
  516. else
  517. {
  518. takeABreak=TRUE;
  519. break;
  520. }
  521. i++;
  522. }while(takeABreak==FALSE);
  523. };
  524. void UnitInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& direction, string& action, string& actiontrigger, int & u1, int & u2, int& u3, int& u4, int& u5, int& u6)
  525. {
  526. house=GetParam(data, 0);
  527. type=GetParam(data, 1);
  528. strength=atoi(GetParam(data, 2));
  529. y=atoi(GetParam(data, 3));
  530. x=atoi(GetParam(data, 4));
  531. direction=atoi(GetParam(data, 5));
  532. action=GetParam(data, 6);
  533. actiontrigger=GetParam(data, 7);
  534. u1=atoi(GetParam(data, 8));
  535. u2=atoi(GetParam(data, 9));
  536. u3=atoi(GetParam(data, 10));
  537. u4=atoi(GetParam(data, 11));
  538. u5=atoi(GetParam(data, 12));
  539. u6=atoi(GetParam(data, 13));
  540. }
  541. void AirInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& direction, string& action, string& actiontrigger, int & u1, int & u2, int& u3, int& u4)
  542. {
  543. house=GetParam(data, 0);
  544. type=GetParam(data, 1);
  545. strength=atoi(GetParam(data, 2));
  546. y=atoi(GetParam(data, 3));
  547. x=atoi(GetParam(data, 4));
  548. direction=atoi(GetParam(data, 5));
  549. action=GetParam(data, 6);
  550. actiontrigger=GetParam(data, 7);
  551. u1=atoi(GetParam(data, 8));
  552. u2=atoi(GetParam(data, 9));
  553. u3=atoi(GetParam(data, 10));
  554. u4=atoi(GetParam(data, 11));
  555. }
  556. void InfanteryInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& pos, string& action, int& direction, string& actiontrigger, int & u1, int & u2, int& u3, int& u4, int& u5)
  557. {
  558. house=GetParam(data, 0);
  559. type=GetParam(data, 1);
  560. strength=atoi(GetParam(data, 2));
  561. y=atoi(GetParam(data, 3));
  562. x=atoi(GetParam(data, 4));
  563. pos=atoi(GetParam(data, 5));
  564. action=GetParam(data, 6);
  565. direction=atoi(GetParam(data, 7));
  566. actiontrigger=GetParam(data, 8);
  567. u1=atoi(GetParam(data, 9));
  568. u2=atoi(GetParam(data, 10));
  569. u3=atoi(GetParam(data, 11));
  570. u4=atoi(GetParam(data, 12));
  571. u5=atoi(GetParam(data, 12));
  572. }
  573. void StructureInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& direction, string& action, int & u1, int & u2, int& energy, int& upgrades, int& u5, string& upgrade1, string& upgrade2, string& upgrade3, int& u9, int& u10)
  574. {
  575. house=GetParam(data, 0);
  576. type=GetParam(data, 1);
  577. strength=atoi(GetParam(data, 2));
  578. y=atoi(GetParam(data, 3));
  579. x=atoi(GetParam(data, 4));
  580. direction=atoi(GetParam(data, 5));
  581. action=GetParam(data, 6);
  582. u1=atoi(GetParam(data, 7));
  583. u2=atoi(GetParam(data, 8));
  584. energy=atoi(GetParam(data, 9));
  585. upgrades=atoi(GetParam(data, 10));
  586. u5=atoi(GetParam(data, 11));
  587. upgrade1=GetParam(data, 12);
  588. upgrade2=GetParam(data, 13);
  589. upgrade3=GetParam(data, 14);
  590. u9=atoi(GetParam(data, 15));
  591. u10=atoi(GetParam(data, 16));
  592. }
  593. void PosToXY(const char* pos, int* X, int* Y)
  594. {
  595. int Posleng;
  596. //int XX, YY;
  597. char Pos[100];
  598. strcpy(Pos, pos);
  599. char XS[10], YS[10];
  600. Posleng = strlen(Pos);
  601. strcpy(YS, Pos+Posleng-3);
  602. Pos[Posleng-3]=0;
  603. strcpy(XS, Pos);
  604. *X = atoi(XS);
  605. *Y = atoi(YS);
  606. }
  607. bool HSVToRGB(const float h, const float s, const float v, float& r, float& g, float& b)
  608. {
  609. if (h < 0.0 || h >= 360.0 || s < 0.0 || s > 1.0 || v < 0.0 || v > 1.0)
  610. return false;
  611. const int h_ = floor(h / 60.0);
  612. const float c = s * v;
  613. const float x = c * (1 - fabs(fmod(h / 60.0, 2.0) - 1));
  614. const float m = v - c;
  615. switch(h_)
  616. {
  617. case 0:
  618. r = c, g = x, b = 0.0;
  619. break;
  620. case 1:
  621. r = x, g = c, b = 0.0;
  622. break;
  623. case 2:
  624. r = 0.0, g = c, b = x;
  625. break;
  626. case 3:
  627. r = 0.0, g = x, b = c;
  628. break;
  629. case 4:
  630. r = x, g = 0.0, b = c;
  631. break;
  632. case 5:
  633. r = c, g = 0.0, b = x;
  634. break;
  635. }
  636. r += m;
  637. g += m;
  638. b += m;
  639. return true;
  640. }
  641. void HSVToRGB(const unsigned char hsv[3], unsigned char rgb[3])
  642. {
  643. float frgb[3];
  644. HSVToRGB(hsv[0] * 360.0 / 255.0, hsv[1] / 255.0, hsv[2] / 255.0, frgb[0], frgb[1], frgb[2]);
  645. for (int i = 0; i < 3; ++i)
  646. rgb[i] = (frgb[i] < 0.0 ? 0.0 : (frgb[i] > 1.0 ? 1.0 : frgb[i])) * 255.0;
  647. }
  648. std::array<unsigned char, 3> HSVToRGB(const float h, const float s, const float v)
  649. {
  650. std::array<float, 3> frgb;
  651. HSVToRGB(h, s, v, frgb[0], frgb[1], frgb[2]);
  652. std::array<unsigned char, 3> ret;
  653. for (int i = 0; i < 3; ++i)
  654. ret[i] = (frgb[i] < 0.0 ? 0.0 : (frgb[i] > 1.0 ? 1.0 : frgb[i])) * 255.0;
  655. return ret;
  656. }
  657. std::array<unsigned char, 3> HSVToRGB(const unsigned char hsv[3])
  658. {
  659. std::array<unsigned char, 3> ret;
  660. HSVToRGB(hsv, ret.data());
  661. return ret;
  662. }
  663. void ListBuildings(CComboBox& cb, BOOL bININame)
  664. {
  665. while(cb.DeleteString(0)!=CB_ERR);
  666. int i;
  667. for(i=0;i<rules.sections["BuildingTypes"].values.size();i++)
  668. {
  669. if(rules.sections["BuildingTypes"].GetValueOrigPos(i)<0) continue;
  670. char c[50];
  671. itoa(rules.sections["BuildingTypes"].GetValueOrigPos(i),c,10);
  672. CString s=c;
  673. //s+=rules.sections[*rules.sections["BuildingTypes"].GetValue(i)].values["Name"];
  674. //s+=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i));
  675. if(bININame) s=*rules.sections["BuildingTypes"].GetValue(i);
  676. s+=" ";
  677. CString t=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i));
  678. //if(t!="MISSING")
  679. {
  680. s+=t;
  681. cb.AddString(s);
  682. }
  683. }
  684. }
  685. void ListInfantry(CComboBox& cb)
  686. {
  687. while(cb.DeleteString(0)!=CB_ERR);
  688. int i;
  689. for(i=0;i<rules.sections["InfantryTypes"].values.size();i++)
  690. {
  691. if(rules.sections["InfantryTypes"].GetValueOrigPos(i)<0) continue;
  692. char c[50];
  693. itoa(rules.sections["InfantryTypes"].GetValueOrigPos(i),c,10);
  694. CString s=c;
  695. s+=" ";
  696. //s+=Map->GetUnitName(*rules.sections["InfantryTypes"].GetValue(i));
  697. CString t=Map->GetUnitName(*rules.sections["InfantryTypes"].GetValue(i));
  698. //if(t!="MISSING")
  699. {
  700. s+=t;
  701. cb.AddString(s);
  702. }
  703. }
  704. }
  705. void ListUnits(CComboBox& cb)
  706. {
  707. while(cb.DeleteString(0)!=CB_ERR);
  708. int i;
  709. for(i=0;i<rules.sections["VehicleTypes"].values.size();i++)
  710. {
  711. if(rules.sections["VehicleTypes"].GetValueOrigPos(i)<0) continue;
  712. char c[50];
  713. itoa(rules.sections["VehicleTypes"].GetValueOrigPos(i),c,10);
  714. CString s=c;
  715. s+=" ";
  716. //s+=rules.sections[*rules.sections["VehicleTypes"].GetValue(i)].values["Name"];
  717. CString t=Map->GetUnitName(*rules.sections["VehicleTypes"].GetValue(i));
  718. //if(t!="MISSING")
  719. {
  720. s+=t;
  721. cb.AddString(s);
  722. }
  723. }
  724. }
  725. void ListAircraft(CComboBox& cb)
  726. {
  727. while(cb.DeleteString(0)!=CB_ERR);
  728. int i;
  729. for(i=0;i<rules.sections["AircraftTypes"].values.size();i++)
  730. {
  731. if(rules.sections["AircraftTypes"].GetValueOrigPos(i)<0) continue;
  732. char c[50];
  733. itoa(rules.sections["AircraftTypes"].GetValueOrigPos(i),c,10);
  734. CString s=c;
  735. s+=" ";
  736. //s+=rules.sections[*rules.sections["AircraftTypes"].GetValue(i)].values["Name"];
  737. CString t=Map->GetUnitName(*rules.sections["AircraftTypes"].GetValue(i));
  738. //if(t!="MISSING")
  739. {
  740. s+=t;
  741. cb.AddString(s);
  742. }
  743. }
  744. }
  745. void ListTechtypes(CComboBox& cb)
  746. {
  747. while(cb.DeleteString(0)!=CB_ERR);
  748. int i;
  749. for(i=0;i<rules.sections["AircraftTypes"].values.size();i++)
  750. {
  751. if(rules.sections["AircraftTypes"].GetValueOrigPos(i)<0) continue;
  752. //char c[50];
  753. //itoa(rules.sections["AircraftTypes"].GetValueOrigPos(i),c,10);
  754. CString s=*rules.sections["AircraftTypes"].GetValue(i);
  755. s+=" ";
  756. //s+=rules.sections[*rules.sections["AircraftTypes"].GetValue(i)].values["Name"];
  757. CString t=Map->GetUnitName(*rules.sections["AircraftTypes"].GetValue(i));
  758. //if(t!="MISSING")
  759. {
  760. s+=t;
  761. cb.AddString(s);
  762. }
  763. }
  764. for(i=0;i<rules.sections["InfantryTypes"].values.size();i++)
  765. {
  766. if(rules.sections["InfantryTypes"].GetValueOrigPos(i)<0) continue;
  767. //char c[50];
  768. //itoa(rules.sections["InfantryTypes"].GetValueOrigPos(i),c,10);
  769. CString s=*rules.sections["InfantryTypes"].GetValue(i);
  770. s+=" ";
  771. //s+=rules.sections[*rules.sections["InfantryTypes"].GetValue(i)].values["Name"];
  772. CString t=Map->GetUnitName(*rules.sections["InfantryTypes"].GetValue(i));
  773. //if(t!="MISSING")
  774. {
  775. s+=t;
  776. cb.AddString(s);
  777. }
  778. }
  779. for(i=0;i<rules.sections["VehicleTypes"].values.size();i++)
  780. {
  781. if(rules.sections["VehicleTypes"].GetValueOrigPos(i)<0) continue;
  782. //char c[50];
  783. //itoa(rules.sections["VehicleTypes"].GetValueOrigPos(i),c,10);
  784. CString s=*rules.sections["VehicleTypes"].GetValue(i);
  785. s+=" ";
  786. //s+=rules.sections[*rules.sections["VehicleTypes"].GetValue(i)].values["Name"];
  787. CString t=Map->GetUnitName(*rules.sections["VehicleTypes"].GetValue(i));
  788. //if(t!="MISSING")
  789. {
  790. s+=t;
  791. cb.AddString(s);
  792. }
  793. }
  794. for(i=0;i<rules.sections["BuildingTypes"].values.size();i++)
  795. {
  796. if(rules.sections["BuildingTypes"].GetValueOrigPos(i)<0) continue;
  797. //char c[50];
  798. //itoa(rules.sections["BuildingTypes"].GetValueOrigPos(i),c,10);
  799. CString s=*rules.sections["BuildingTypes"].GetValue(i);
  800. s+=" ";
  801. //s+=rules.sections[*rules.sections["BuildingTypes"].GetValue(i)].values["Name"];
  802. CString t=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i));
  803. //if(t!="MISSING")
  804. {
  805. s+=t;
  806. cb.AddString(s);
  807. }
  808. }
  809. }
  810. // should be ListLocals()
  811. void ListGlobals(CComboBox& cb)
  812. {
  813. while(cb.DeleteString(0)!=CB_ERR);
  814. int i;
  815. CIniFile& ini=Map->GetIniFile();
  816. for(i=0;i<ini.sections["VariableNames"].values.size();i++)
  817. {
  818. CString s=*ini.sections["VariableNames"].GetValueName(i);
  819. s+=" ";
  820. s+=*ini.sections["VariableNames"].GetValue(i);
  821. cb.AddString(s);
  822. }
  823. }
  824. void ListRulesGlobals(CComboBox& cb)
  825. {
  826. while(cb.DeleteString(0)!=CB_ERR);
  827. int i;
  828. for(i=0;i<rules.sections["VariableNames"].values.size();i++)
  829. {
  830. CString s=*rules.sections["VariableNames"].GetValueName(i);
  831. s+=" ";
  832. s+=*rules.sections["VariableNames"].GetValue(i);
  833. cb.AddString(s);
  834. }
  835. }
  836. extern map<CString, XCString> AllStrings;
  837. void ListTutorial(CComboBox& cb)
  838. {
  839. while(cb.DeleteString(0)!=CB_ERR);
  840. #ifndef RA2_MODE
  841. int i;
  842. for(i=0;i<tutorial.sections["Tutorial"].values.size();i++)
  843. {
  844. CString s;
  845. s=*tutorial.sections["Tutorial"].GetValueName(i);
  846. s+=" ";
  847. s+=*tutorial.sections["Tutorial"].GetValue(i);
  848. cb.AddString(s);
  849. }
  850. #else
  851. typedef map<CString, XCString>::iterator it;
  852. it _it=AllStrings.begin();
  853. /*it begin;
  854. it end;
  855. begin=CCStrings.begin();
  856. end=CCStrings.end();*/
  857. int i;
  858. for(i=0;i<CCStrings.size();i++)
  859. {
  860. CString s;
  861. s=_it->first;
  862. s+=" : ";
  863. s+=_it->second.cString;
  864. cb.AddString(s);
  865. _it++;
  866. }
  867. #endif
  868. }
  869. void ListTriggers(CComboBox& cb)
  870. {
  871. while(cb.DeleteString(0)!=CB_ERR);
  872. int i;
  873. CIniFile& ini=Map->GetIniFile();
  874. for(i=0;i<ini.sections["Triggers"].values.size();i++)
  875. {
  876. CString type;
  877. CString s;
  878. type=*ini.sections["Triggers"].GetValueName(i);
  879. s=type;
  880. s+=" (";
  881. s+=GetParam(ini.sections["Triggers"].values[type], 2);
  882. s+=")";
  883. cb.AddString(s);
  884. }
  885. }
  886. void ListYesNo(CComboBox& cb)
  887. {
  888. while(cb.DeleteString(0)!=CB_ERR);
  889. cb.AddString("1 " + GetLanguageStringACP("Yes"));
  890. cb.AddString("0 " + GetLanguageStringACP("No"));
  891. }
  892. void ListSounds(CComboBox& cb)
  893. {
  894. while(cb.DeleteString(0)!=CB_ERR);
  895. #ifdef RA2_MODE
  896. int i;
  897. for(i=0;i<sound.sections["SoundList"].values.size();i++)
  898. {
  899. CString s;
  900. s=*sound.sections["SoundList"].GetValue(i);
  901. cb.AddString(s);
  902. }
  903. #endif
  904. }
  905. void ListThemes(CComboBox& cb)
  906. {
  907. while(cb.DeleteString(0)!=CB_ERR);
  908. #ifdef RA2_MODE
  909. int i;
  910. for(i=0;i<theme.sections["Themes"].values.size();i++)
  911. {
  912. CString s;
  913. s=*theme.sections["Themes"].GetValue(i);
  914. TruncSpace(s);
  915. if(s.GetLength()==0) continue;
  916. s+=" ";
  917. s+=AllStrings[sound.sections[s].values["Name"]].cString;
  918. cb.AddString(s);
  919. }
  920. #endif
  921. }
  922. void ListSpeeches(CComboBox& cb)
  923. {
  924. while(cb.DeleteString(0)!=CB_ERR);
  925. #ifdef RA2_MODE
  926. int i;
  927. for(i=0;i<eva.sections["DialogList"].values.size();i++)
  928. {
  929. CString s;
  930. s=*eva.sections["DialogList"].GetValue(i);
  931. cb.AddString(s);
  932. }
  933. #endif
  934. }
  935. void ListSpecialWeapons(CComboBox& cb)
  936. {
  937. while(cb.DeleteString(0)!=CB_ERR);
  938. int i;
  939. for(i=0;i<rules.sections["SuperWeaponTypes"].values.size();i++)
  940. {
  941. CString s;
  942. char c[50];
  943. itoa(rules.sections["SuperWeaponTypes"].GetValueOrigPos(i),c,10);
  944. s=c;
  945. s+=" ";
  946. s+=*rules.sections["SuperWeaponTypes"].GetValue(i);
  947. cb.AddString(s);
  948. }
  949. }
  950. void ListAnimations(CComboBox& cb)
  951. {
  952. while(cb.DeleteString(0)!=CB_ERR);
  953. int i;
  954. for(i=0;i<rules.sections["Animations"].values.size();i++)
  955. {
  956. CString s;
  957. char c[50];
  958. itoa(rules.sections["Animations"].GetValueOrigPos(i),c,10);
  959. s=c;
  960. s+=" ";
  961. s+=*rules.sections["Animations"].GetValue(i);
  962. cb.AddString(s);
  963. }
  964. }
  965. void ListParticles(CComboBox& cb)
  966. {
  967. while(cb.DeleteString(0)!=CB_ERR);
  968. int i;
  969. for(i=0;i<rules.sections["Particles"].values.size();i++)
  970. {
  971. CString s;
  972. char c[50];
  973. itoa(rules.sections["Particles"].GetValueOrigPos(i),c,10);
  974. s=c;
  975. s+=" ";
  976. s+=*rules.sections["Particles"].GetValue(i);
  977. cb.AddString(s);
  978. }
  979. }
  980. void ListCrateTypes(CComboBox& cb)
  981. {
  982. while(cb.DeleteString(0)!=CB_ERR);
  983. }
  984. void ListSpeechBubbleTypes(CComboBox& cb)
  985. {
  986. while(cb.DeleteString(0)!=CB_ERR);
  987. }
  988. void ListMovies(CComboBox& cb, BOOL bListNone, BOOL bListParam)
  989. {
  990. if(!bListParam)
  991. {
  992. int sel=cb.GetCurSel();
  993. while(cb.DeleteString(0)!=CB_ERR);
  994. int i;
  995. if(bListNone) cb.AddString("<none>");
  996. for(i=0;i<art.sections["Movies"].values.size();i++)
  997. {
  998. if(i<atoi(g_data.sections["MovieList"].values["Start"])) continue;
  999. CString s=*art.sections["Movies"].GetValue(i);
  1000. cb.AddString(s);
  1001. }
  1002. if(sel>=0) cb.SetCurSel(sel);
  1003. }
  1004. else
  1005. {
  1006. while(cb.DeleteString(0)!=CB_ERR);
  1007. int i;
  1008. for(i=0;i<art.sections["Movies"].values.size();i++)
  1009. {
  1010. if(i<atoi(g_data.sections["MovieList"].values["Start"])) continue;
  1011. CString s;
  1012. char c[50];
  1013. itoa(art.sections["Movies"].GetValueOrigPos(i),c,10);
  1014. s=c;
  1015. s+=" ";
  1016. s+=*art.sections["Movies"].GetValue(i);
  1017. cb.AddString(s);
  1018. }
  1019. }
  1020. }
  1021. void ListTags(CComboBox& cb, BOOL bListNone)
  1022. {
  1023. CIniFile& ini=Map->GetIniFile();
  1024. int sel=cb.GetCurSel();
  1025. while(cb.DeleteString(0)!=CB_ERR);
  1026. int i;
  1027. if(bListNone) cb.AddString("None");
  1028. for(i=0;i<ini.sections["Tags"].values.size();i++)
  1029. {
  1030. CString type=*ini.sections["Tags"].GetValueName(i);
  1031. CString s=type;
  1032. s+=" ";
  1033. s+=GetParam(*ini.sections["Tags"].GetValue(i), 1);
  1034. cb.AddString(s);
  1035. }
  1036. if(sel>=0) cb.SetCurSel(sel);
  1037. }
  1038. int GetRulesHousesSize()
  1039. {
  1040. int i;
  1041. int count=0;
  1042. for(i=0;i<rules.sections[HOUSES].values.size();i++)
  1043. {
  1044. if(rules.sections[HOUSES].GetValueOrigPos(i)<0) continue;
  1045. count++;
  1046. }
  1047. return count;
  1048. }
  1049. // a bug adds an empty house to the rules section, delete it here
  1050. int RepairRulesHouses()
  1051. {
  1052. int i;
  1053. int count=0;
  1054. int delcount=0;
  1055. CString* toDelete;
  1056. toDelete=new(CString[rules.sections[HOUSES].values.size()]);
  1057. for(i=0;i<rules.sections[HOUSES].values.size();i++)
  1058. {
  1059. if(rules.sections[HOUSES].GetValueOrigPos(i)<0)
  1060. {
  1061. toDelete[delcount]=*rules.sections[HOUSES].GetValueName(i);
  1062. delcount++;
  1063. }
  1064. else
  1065. count++;
  1066. }
  1067. for(i=0;i<delcount;i++)
  1068. rules.sections[HOUSES].values.erase(toDelete[i]);
  1069. delete[] toDelete;
  1070. return count;
  1071. }
  1072. // MW 07/27/01: Modified for <Player @ A> etc in YR
  1073. void ListHouses(CComboBox &cb, BOOL bNumbers, BOOL bCountries, BOOL bPlayers)
  1074. {
  1075. CIniFile& ini=Map->GetIniFile();
  1076. int i;
  1077. int sel=cb.GetCurSel();
  1078. int crulesh=GetRulesHousesSize();
  1079. if(Map->IsMultiplayer()==FALSE) bPlayers=FALSE; // really only for multi maps!
  1080. //for(i=0;i<ini.sections[HOUSES]
  1081. CString sSection=MAPHOUSES;
  1082. if(bCountries) sSection=HOUSES;
  1083. while(cb.DeleteString(0)!=CB_ERR);
  1084. // houses: rules.ini + map definitions!
  1085. if(ini.sections.find(sSection)!=ini.sections.end())
  1086. {
  1087. if(ini.sections[sSection].values.size()==0) goto wasnohouse;
  1088. // we use the map definitions!
  1089. if(yuri_mode && bPlayers)
  1090. {
  1091. if(bNumbers)
  1092. {
  1093. cb.AddString("4475 <Player @ A>");
  1094. cb.AddString("4476 <Player @ B>");
  1095. cb.AddString("4477 <Player @ C>");
  1096. cb.AddString("4478 <Player @ D>");
  1097. cb.AddString("4479 <Player @ E>");
  1098. cb.AddString("4480 <Player @ F>");
  1099. cb.AddString("4481 <Player @ G>");
  1100. cb.AddString("4482 <Player @ H>");
  1101. }
  1102. else
  1103. {
  1104. cb.AddString("<Player @ A>");
  1105. cb.AddString("<Player @ B>");
  1106. cb.AddString("<Player @ C>");
  1107. cb.AddString("<Player @ D>");
  1108. cb.AddString("<Player @ E>");
  1109. cb.AddString("<Player @ F>");
  1110. cb.AddString("<Player @ G>");
  1111. cb.AddString("<Player @ H>");
  1112. }
  1113. }
  1114. for(i=0;i<ini.sections[sSection].values.size();i++)
  1115. {
  1116. CString j;
  1117. #ifdef RA2_MODE
  1118. j=*ini.sections[sSection].GetValue(i);
  1119. j.MakeLower();
  1120. if(j=="nod" || j=="gdi") continue;
  1121. #endif
  1122. if(bNumbers)
  1123. {
  1124. char c[50];
  1125. int n=atoi(*ini.sections[sSection].GetValueName(i));
  1126. itoa(n, c, 10);
  1127. #ifdef RA2_MODE
  1128. if(bCountries)
  1129. {
  1130. int preexisting=0;
  1131. int e;
  1132. for(e=0;e<i;e++)
  1133. {
  1134. if(rules.sections[sSection].FindValue(*ini.sections[sSection].GetValue(e))>=0)
  1135. preexisting++;
  1136. }
  1137. if(rules.sections[sSection].FindValue(*ini.sections[sSection].GetValue(i))>=0)
  1138. {
  1139. itoa(rules.sections[sSection].value_orig_pos[*rules.sections[sSection].GetValueName(rules.sections[sSection].FindValue(*ini.sections[sSection].GetValue(i)))], c, 10);
  1140. }
  1141. else
  1142. {
  1143. itoa(n+crulesh-preexisting, c, 10);
  1144. }
  1145. }
  1146. #endif
  1147. j=c;
  1148. j+=" ";
  1149. j+=TranslateHouse(*ini.sections[sSection].GetValue(i), TRUE);
  1150. }
  1151. else
  1152. j=TranslateHouse(*ini.sections[sSection].GetValue(i), TRUE);
  1153. cb.AddString(j);
  1154. }
  1155. }
  1156. else
  1157. {
  1158. wasnohouse:
  1159. if(bNumbers)
  1160. {
  1161. for(i=0;i<rules.sections[HOUSES].values.size();i++)
  1162. {
  1163. CString j;
  1164. #ifdef RA2_MODE
  1165. j=*rules.sections[HOUSES].GetValue(i);
  1166. j.MakeLower();
  1167. if(j=="nod" || j=="gdi") continue;
  1168. #endif
  1169. j=*rules.sections[HOUSES].GetValueName(i);
  1170. j+=" ";
  1171. j+=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE);
  1172. cb.AddString(j);
  1173. }
  1174. if(!yuri_mode || !bPlayers )
  1175. {
  1176. for(i=0;i<8;i++)
  1177. {
  1178. int k=i;
  1179. #ifdef RA2_MODE
  1180. k+=crulesh;
  1181. //rules.sections[HOUSES].values.size();
  1182. #endif
  1183. CString j;
  1184. char c[50];
  1185. itoa(k,c,10);
  1186. j+=c;
  1187. j+=" Multi-Player ";
  1188. itoa(i,c,10);
  1189. j+=c;
  1190. cb.AddString(j);
  1191. }
  1192. }
  1193. else
  1194. {
  1195. cb.AddString("4475 <Player @ A>");
  1196. cb.AddString("4476 <Player @ B>");
  1197. cb.AddString("4477 <Player @ C>");
  1198. cb.AddString("4478 <Player @ D>");
  1199. cb.AddString("4479 <Player @ E>");
  1200. cb.AddString("4480 <Player @ F>");
  1201. cb.AddString("4481 <Player @ G>");
  1202. cb.AddString("4482 <Player @ H>");
  1203. }
  1204. }
  1205. else
  1206. {
  1207. if(yuri_mode && bPlayers)
  1208. {
  1209. cb.AddString("<Player @ A>");
  1210. cb.AddString("<Player @ B>");
  1211. cb.AddString("<Player @ C>");
  1212. cb.AddString("<Player @ D>");
  1213. cb.AddString("<Player @ E>");
  1214. cb.AddString("<Player @ F>");
  1215. cb.AddString("<Player @ G>");
  1216. cb.AddString("<Player @ H>");
  1217. }
  1218. for(i=0;i<rules.sections[HOUSES].values.size();i++)
  1219. {
  1220. CString j;
  1221. #ifdef RA2_MODE
  1222. j=*rules.sections[HOUSES].GetValue(i);
  1223. j.MakeLower();
  1224. if(j=="nod" || j=="gdi") continue;
  1225. #endif
  1226. if(bNumbers)
  1227. {
  1228. j=*rules.sections[HOUSES].GetValueName(i);
  1229. j+=" ";
  1230. j+=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE);
  1231. }
  1232. else
  1233. j=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE);
  1234. cb.AddString(j);
  1235. }
  1236. }
  1237. }
  1238. if(sel>=0) cb.SetCurSel(sel);
  1239. }
  1240. void ListTeamTypes(CComboBox &cb, BOOL bListNone)
  1241. {
  1242. CIniFile& ini=Map->GetIniFile();
  1243. int sel=cb.GetCurSel();
  1244. while(cb.DeleteString(0)!=CB_ERR);
  1245. int i;
  1246. if(bListNone) cb.AddString("<none>");
  1247. for(i=0;i<ini.sections["TeamTypes"].values.size();i++)
  1248. {
  1249. CIniFileSection& sec=ini.sections[*ini.sections["TeamTypes"].GetValue(i)];
  1250. CString type=*ini.sections["TeamTypes"].GetValue(i);
  1251. CString s=type;
  1252. s+=" ";
  1253. s+=sec.values["Name"];
  1254. cb.AddString(s);
  1255. }
  1256. if(sel>=0) cb.SetCurSel(sel);
  1257. }
  1258. void ListWaypoints(CComboBox &cb)
  1259. {
  1260. CIniFile& ini=Map->GetIniFile();
  1261. int sel=cb.GetCurSel();
  1262. while(cb.DeleteString(0)!=CB_ERR);
  1263. int i;
  1264. for(i=0;i<ini.sections["Waypoints"].values.size();i++)
  1265. {
  1266. CString s=*ini.sections["Waypoints"].GetValueName(i); //type;
  1267. cb.AddString(s);
  1268. }
  1269. if(sel>=0) cb.SetCurSel(sel);
  1270. }
  1271. void ListTargets(CComboBox &cb)
  1272. {
  1273. int sel=cb.GetCurSel();
  1274. while(cb.DeleteString(0)!=CB_ERR);
  1275. cb.AddString("1 - Not specified");
  1276. cb.AddString("2 - Buildings");
  1277. cb.AddString("3 - Harvesters");
  1278. cb.AddString("4 - Infantry");
  1279. cb.AddString("5 - Vehicles");
  1280. cb.AddString("6 - Factories");
  1281. cb.AddString("7 - Base defenses");
  1282. cb.AddString("9 - Power plants");
  1283. if(sel>=0) cb.SetCurSel(sel);
  1284. }
  1285. CString GetHouseSectionName(CString lpHouse)
  1286. {
  1287. #ifndef RA2_MODE
  1288. return lpHouse;
  1289. #else
  1290. return lpHouse+" House";
  1291. #endif
  1292. }
  1293. CString GetFreeID()
  1294. {
  1295. CIniFile& ini=Map->GetIniFile();
  1296. int n=1000000;
  1297. while(TRUE)
  1298. {
  1299. char p[50];
  1300. p[0]='0';
  1301. itoa(n,p+1,10);
  1302. if(ini.sections["ScriptTypes"].FindValue(p)==-1)
  1303. {
  1304. if(ini.sections["TaskForces"].FindValue(p)==-1)
  1305. {
  1306. if(ini.sections["TeamTypes"].FindValue(p)==-1)
  1307. {
  1308. if(ini.sections["Triggers"].values.find(p)==ini.sections["Triggers"].values.end())
  1309. {
  1310. if(ini.sections["Events"].values.find(p)==ini.sections["Events"].values.end())
  1311. {
  1312. if(ini.sections["Tags"].values.find(p)==ini.sections["Tags"].values.end())
  1313. {
  1314. if(ini.sections["Actions"].values.find(p)==ini.sections["Actions"].values.end())
  1315. {
  1316. if(ini.sections["AITriggerTypes"].values.find(p)==ini.sections["AITriggerTypes"].values.end())
  1317. {
  1318. if(ini.sections.find(p)==ini.sections.end())
  1319. return p;
  1320. }
  1321. }
  1322. }
  1323. }
  1324. }
  1325. }
  1326. }
  1327. }
  1328. n++;
  1329. }
  1330. return "";
  1331. }
  1332. void GetNodeName(CString & name, int n)
  1333. {
  1334. char c[5];
  1335. char p[6];
  1336. memset(p,0,6);
  1337. itoa(n,c,10);
  1338. strcpy(p,c);
  1339. if(strlen(c)==1)
  1340. {
  1341. memcpy(c,"00", 2);
  1342. strcpy(c+2, p);
  1343. }
  1344. else if(strlen(c)==2)
  1345. {
  1346. memcpy(c,"0", 1);
  1347. strcpy(c+1, p);
  1348. }
  1349. else if(strlen(c)==3)
  1350. {
  1351. strcpy(c, p);
  1352. }
  1353. name=c;
  1354. }
  1355. int GetNodeAt(CString& owner, CString& type, int x, int y)
  1356. {
  1357. CIniFile& ini=Map->GetIniFile();
  1358. type="";
  1359. owner="";
  1360. int owners;
  1361. if(ini.sections.find(HOUSES)!=ini.sections.end())
  1362. {
  1363. for(owners=0;owners<ini.sections[HOUSES].values.size();owners++)
  1364. {
  1365. owner=*ini.sections[HOUSES].GetValue(owners);
  1366. // okay now owner is correct!
  1367. int i,c=atoi(ini.sections[owner].values["NodeCount"]);
  1368. for(i=0;i<c;i++)
  1369. {
  1370. CString p;
  1371. GetNodeName(p, i);
  1372. CString sx, sy;
  1373. type=GetParam(ini.sections[owner].values[p], 0);
  1374. sy=GetParam(ini.sections[owner].values[p], 1);
  1375. sx=GetParam(ini.sections[owner].values[p], 2);
  1376. CString arttype=type;
  1377. if(rules.sections[type].values.find("Image")!=rules.sections[type].values.end())
  1378. {
  1379. // other art!
  1380. arttype=rules.sections[type].values["Image"];
  1381. }
  1382. if(ini.sections.find(type)!=ini.sections.end())
  1383. if(ini.sections[type].values.find("Image")!=ini.sections[type].values.end())
  1384. {
  1385. // other art!
  1386. arttype=rules.sections[type].values["Image"];
  1387. }
  1388. int w,h;
  1389. char d[6];
  1390. memcpy(d, (LPCTSTR)art.sections[arttype].values["Foundation"],1);
  1391. d[1]=0;
  1392. w=atoi(d);
  1393. if(w==0) w=1;
  1394. memcpy(d, (LPCTSTR)art.sections[arttype].values["Foundation"]+2,1);
  1395. d[1]=0;
  1396. h=atoi(d);
  1397. if(h==0) h=1;
  1398. int j,k;
  1399. for(j=0;j<h;j++)
  1400. {
  1401. for(k=0;k<w;k++)
  1402. {
  1403. if(atoi(sx)+j==x && atoi(sy)+k==y)
  1404. return i;
  1405. }
  1406. }
  1407. }
  1408. }
  1409. }
  1410. else
  1411. return -1;
  1412. return -1;
  1413. }
  1414. std::unique_ptr<CBitmap> BitmapFromResource(int resource_id)
  1415. {
  1416. std::unique_ptr<CBitmap> bm(new CBitmap);
  1417. if (!bm->LoadBitmap(resource_id))
  1418. throw BitmapNotFound();
  1419. return bm;
  1420. }
  1421. std::unique_ptr<CBitmap> BitmapFromFile(const CString& filepath)
  1422. {
  1423. std::unique_ptr<CBitmap> bm(new CBitmap);
  1424. if (!bm->LoadBitmap(filepath))
  1425. throw BitmapNotFound();
  1426. return bm;
  1427. }
  1428. /*
  1429. Returns the area in the current line that should be painted
  1430. Truncates areas that are transparent, and therefore increases display speed!
  1431. flags must be set to 0
  1432. */
  1433. void GetDrawBorder(const BYTE* data, int width, int line, int& left, int& right, unsigned int flags, BOOL* TranspInside)
  1434. {
  1435. int i;
  1436. const BYTE* lpStart = data + line * width;
  1437. if (flags == 0)
  1438. {
  1439. // left border:
  1440. for (i = 0;i < width;i++)
  1441. {
  1442. if (lpStart[i] || i == width - 1)
  1443. {
  1444. left = i;
  1445. break;
  1446. }
  1447. }
  1448. // right border:
  1449. for (i = width - 1;i >= 0;i--)
  1450. {
  1451. if (lpStart[i] || i == 0)
  1452. {
  1453. right = i;
  1454. break;
  1455. }
  1456. }
  1457. if (TranspInside)
  1458. {
  1459. for (i = left;i <= right;i++)
  1460. {
  1461. if (!lpStart[i])
  1462. {
  1463. *TranspInside = TRUE;
  1464. break;
  1465. }
  1466. }
  1467. }
  1468. }
  1469. }
  1470. CComPtr<IDirectDrawSurface4> BitmapToSurface(IDirectDraw4 * pDD, const CBitmap& bitmap)
  1471. {
  1472. BITMAP bm;
  1473. GetObject(bitmap, sizeof(bm), &bm);
  1474. DDSURFACEDESC2 desc = { 0 };
  1475. ZeroMemory(&desc, sizeof(desc));
  1476. desc.dwSize = sizeof(desc);
  1477. desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  1478. desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  1479. desc.dwWidth = bm.bmWidth;
  1480. desc.dwHeight = bm.bmHeight;
  1481. auto pSurface = CComPtr<IDirectDrawSurface4>();
  1482. if (pDD->CreateSurface(&desc, &pSurface, nullptr) != DD_OK)
  1483. return nullptr;
  1484. pSurface->Restore();
  1485. CDC bitmapDC;
  1486. if (!bitmapDC.CreateCompatibleDC(nullptr))
  1487. return nullptr;
  1488. bitmapDC.SelectObject(bitmap);
  1489. HDC hSurfaceDC = nullptr;
  1490. if (pSurface->GetDC(&hSurfaceDC) != DD_OK)
  1491. return nullptr;
  1492. CDC surfaceDC;
  1493. surfaceDC.Attach(hSurfaceDC);
  1494. auto success = surfaceDC.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &bitmapDC, 0, 0, SRCCOPY);
  1495. surfaceDC.Detach();
  1496. pSurface->ReleaseDC(hSurfaceDC);
  1497. return pSurface;
  1498. }