StateAccessors.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. //============================================================================================
  2. // Spirenkov Maxim, 2006
  3. //============================================================================================
  4. // Mission objects
  5. //============================================================================================
  6. // StateAccessors
  7. //============================================================================================
  8. #include "StateAccessors.h"
  9. //============================================================================================
  10. StateAccessor::StateAccessor()
  11. {
  12. name = null;
  13. }
  14. //Получить текущие имя стейта
  15. const char * StateAccessor::GetName(const char * name, bool useAccessFilter)
  16. {
  17. if(string::IsEmpty(name))
  18. {
  19. LogicDebugError("Can't operate because name is empty");
  20. return null;
  21. }
  22. //Для начала проверим имя на наличее звёзд и посчитаем длинну
  23. bool isNeedReplace = false;
  24. for(long i = 0; name[i]; i++)
  25. {
  26. isNeedReplace |= (name[i] == '*');
  27. }
  28. if(isNeedReplace)
  29. {
  30. bool isError = false;
  31. //Разбираем строку
  32. tempName.Empty();
  33. tempName.Reserve(i + 32);
  34. for(long i = 0; name[i]; i++)
  35. {
  36. if(name[i] == '*')
  37. {
  38. const char * insert = "";
  39. //Начинаеться имя объекта
  40. dword index = tempName.Len();
  41. for(i++; name[i] != '*' && name[i]; i++)
  42. {
  43. tempName += name[i];
  44. }
  45. if(index < tempName.Len())
  46. {
  47. const char * objectName = tempName.c_str() + index;
  48. MOSafePointer mo;
  49. if(FindObject(ConstString(objectName), mo))
  50. {
  51. MO_IS_IF(stVarId, "StateVariable", mo.Ptr())
  52. {
  53. insert = ((StateVariable *)mo.Ptr())->GetParameter();
  54. }else{
  55. LogicDebugError("Mission object \"%s\" is not type \"State parameter\"", objectName);
  56. isError = true;
  57. }
  58. }else{
  59. LogicDebugError("Mission object \"%s\" not found", objectName);
  60. isError = true;
  61. }
  62. }
  63. tempName.Delete(index, tempName.Len() - index);
  64. tempName += insert;
  65. }else{
  66. tempName += name[i];
  67. }
  68. }
  69. if(isError)
  70. {
  71. return null;
  72. }
  73. name = tempName.c_str();
  74. }
  75. if(!useAccessFilter)
  76. {
  77. return name;
  78. }
  79. //Проверяем на возможность доступа по префиксам
  80. const char * enableAccess[] = {"profile.", "profile1.", "options.", "game.", "runtime."};
  81. for(long i = 0; i < ARRSIZE(enableAccess); i++)
  82. {
  83. const char * pefexName = enableAccess[i];
  84. for(long j = 0; pefexName[j]; j++)
  85. {
  86. char c = name[j];
  87. if(c <= 'Z' && c >= 'A') c += 'a' - 'A';
  88. if(pefexName[j] != c) break;
  89. }
  90. if(!pefexName[j])
  91. {
  92. return name;
  93. }
  94. }
  95. LogicDebugError("Can't operate because path \"%s\" not accessible", name);
  96. return null;
  97. }
  98. //============================================================================================
  99. StateVariable::StateVariable() : table(_FL_, 1)
  100. {
  101. mode = tm_force;
  102. param = null;
  103. }
  104. //Инициализировать объект
  105. bool StateVariable::Create(MOPReader & reader)
  106. {
  107. ConstString smode = reader.Enum();
  108. mode = tm_force;
  109. for(long m = 0; m < tm_count; m++)
  110. {
  111. if(smode == tms[m].name)
  112. {
  113. mode = tms[m].mode;
  114. break;
  115. }
  116. }
  117. param = reader.String().c_str();
  118. if(mode == tm_case_string || mode == tm_case_id)
  119. {
  120. //Надо прочитать дальше
  121. long count = reader.Array();
  122. if(mode == tm_case_id)
  123. {
  124. table.AddElements(count);
  125. for(long i = 0; i < count; i++)
  126. {
  127. for(long i = 0; i < count; i++)
  128. {
  129. table[i] = reader.LocString();
  130. }
  131. }
  132. }else{
  133. mode = tm_case_id;
  134. for(long i = 0; i < count; i++)
  135. {
  136. reader.LocString();
  137. }
  138. count = reader.Array();
  139. table.AddElements(count);
  140. for(long i = 0; i < count; i++)
  141. {
  142. table[i] = reader.String().c_str();
  143. }
  144. }
  145. }
  146. return true;
  147. }
  148. //Получить параметер
  149. const char * StateVariable::GetParameter()
  150. {
  151. bool isOk = false;
  152. const char * name;
  153. if(mode == tm_param)
  154. {
  155. parameter = param;
  156. }else
  157. if(mode == tm_string)
  158. {
  159. name = GetName(param, false);
  160. if(name)
  161. {
  162. parameter = api->Storage().GetString(name, "", &isOk);
  163. if(!isOk)
  164. {
  165. LogicDebugError("Can't access to string state \"%s\" (taking from \"%s\")", name, param);
  166. return null;
  167. }
  168. }
  169. }else{
  170. name = GetName(param, false);
  171. if(name)
  172. {
  173. float value = api->Storage().GetFloat(name, 0.0f, &isOk);
  174. if(!isOk)
  175. {
  176. LogicDebugError("Can't access to number state \"%s\" (taking from \"%s\")", name, param);
  177. return null;
  178. }
  179. if(mode == tm_case_id)
  180. {
  181. if(!table.Size())
  182. {
  183. LogicDebugError("Can't get table value because table is empty");
  184. return null;
  185. }
  186. int index = (int)value;
  187. if(index < 0 || index >= table)
  188. {
  189. LogicDebugError("Number state \"%s\" (taking from \"%s\") value %i out of range [0..%i]", name, param, index, table.Size() - 1);
  190. if(index < 0)
  191. {
  192. index = 0;
  193. }else{
  194. index = table - 1;
  195. }
  196. }
  197. parameter = table[index];
  198. }else{
  199. const char * formatString = "%f";
  200. switch(mode)
  201. {
  202. case tm_int:
  203. formatString = "%.0f";
  204. break;
  205. case tm_float_X_1:
  206. formatString = "%.1f";
  207. break;
  208. case tm_float_X_2:
  209. formatString = "%.2f";
  210. break;
  211. case tm_float_X_3:
  212. formatString = "%.3f";
  213. break;
  214. case tm_float_X_4:
  215. formatString = "%.4f";
  216. break;
  217. default:
  218. Assert(false);
  219. }
  220. char buf[32];
  221. crt_snprintf(buf, sizeof(buf) - 1, formatString, value);
  222. buf[sizeof(buf) - 1] = 0;
  223. parameter = buf;
  224. }
  225. }
  226. }
  227. LogicDebug("Return value = %s", parameter.c_str());
  228. return parameter.c_str();
  229. }
  230. const char * StateVariable::comment =
  231. "This object make dynamic state name.\n"
  232. "This sample show how to access to gold:\n"
  233. " In object with type \"State number set\" write: \"Profile.*Difficulty*.Player.gold\"\n"
  234. " Also we can make object with name Difficulty and type of \"State variable\"\n"
  235. " This object will be access to \"Profile.Global.Difficulty\" as string state\n"
  236. " When we activate object \"State number set\" they insert to *Difficulty* part\n"
  237. " value from string state \"Profile.Global.Difficulty\".\n"
  238. " You can use any count of replaces in state name."
  239. " ";
  240. const StateVariable::EnumParams StateVariable::tms[tm_count] = {{tm_param, ConstString("Constant")},
  241. {tm_string, ConstString("String state")},
  242. {tm_int, ConstString("Number state as integer")},
  243. {tm_float_X_1, ConstString("Number state as float X.X")},
  244. {tm_float_X_2, ConstString("Number state as float X.XX")},
  245. {tm_float_X_3, ConstString("Number state as float X.XXX")},
  246. {tm_float_X_4, ConstString("Number state as float X.XXXX")},
  247. {tm_case_id, ConstString("Number state as index in loctable")},
  248. {tm_case_string, ConstString("Number state as index in strtable")}};
  249. MOP_BEGINLISTCG(StateVariable, "State variable", '1.00', 0, StateVariable::comment, "Managment")
  250. MOP_ENUMBEG("Md")
  251. for(long i = 0; i < ARRSIZE(StateVariable::tms); i++)
  252. {
  253. MOP_ENUMELEMENT(StateVariable::tms[i].name.c_str())
  254. }
  255. MOP_ENUMEND
  256. MOP_ENUMC("Md", "Mode", "How to use this parameter")
  257. MOP_STRINGC("Parameter", "", "String parameter use la-la-la")
  258. MOP_ARRAYBEGC("Loctable", 0, 100, "Table of localization strings")
  259. MOP_LOCSTRINGC("String", "This string use only for set UI elements")
  260. MOP_ARRAYEND
  261. MOP_ARRAYBEGC("Strtable", 0, 100, "Table of system strings")
  262. MOP_STRINGC("Value", "", "This string use only in system purpose")
  263. MOP_ARRAYEND
  264. MOP_ENDLIST(StateVariable)
  265. //============================================================================================
  266. //Инициализировать объект
  267. bool StateEmpty::Create(MOPReader & reader)
  268. {
  269. name = reader.String().c_str();
  270. return true;
  271. }
  272. //Активировать/деактивировать объект
  273. void StateEmpty::Activate(bool isActive)
  274. {
  275. if(isActive)
  276. {
  277. api->Storage().Delete(name);
  278. LogicDebug("Activate: now state \"%s\" is empty", name);
  279. }else{
  280. LogicDebug("Deactivate: ignore");
  281. }
  282. }
  283. MOP_BEGINLISTG(StateEmpty, "State folder cleaner", '1.00', 10, "Managment")
  284. MOP_STRING("State folder name", "")
  285. MOP_ENDLIST(StateEmpty)
  286. //============================================================================================
  287. StateCopy::StateCopy()
  288. {
  289. name2 = null;
  290. }
  291. //Инициализировать объект
  292. bool StateCopy::Create(MOPReader & reader)
  293. {
  294. name = reader.String().c_str();
  295. name2 = reader.String().c_str();
  296. return true;
  297. }
  298. //Активировать/деактивировать объект
  299. void StateCopy::Activate(bool isActive)
  300. {
  301. if(isActive)
  302. {
  303. array<byte> buffer(_FL_, 1024);
  304. const char * n = GetName(name, false);
  305. if(n)
  306. {
  307. if(api->Storage().Save(n, buffer))
  308. {
  309. LogicDebug("Copy fields from %s to buffer", n);
  310. n = GetName(name2, true);
  311. if(n)
  312. {
  313. dword readPointer = 0;
  314. if(api->Storage().Load(n, buffer.GetBuffer(), buffer.Size(), readPointer))
  315. {
  316. LogicDebug("Past buffer to %s.", n);
  317. }else{
  318. LogicDebugError("Can't past buffer to %s. Difference types? Try before copy delete destination folder.", n);
  319. }
  320. }
  321. }else{
  322. LogicDebugError("Can't copy fields from %s to buffer", n);
  323. }
  324. }
  325. }else{
  326. LogicDebug("Deactivate: ignore");
  327. }
  328. }
  329. MOP_BEGINLISTG(StateCopy, "State copy", '1.00', 10, "Managment")
  330. MOP_STRINGC("From", "", "Folder or filed from get copy")
  331. MOP_STRINGC("To", "", "Folder when put copy")
  332. MOP_ENDLIST(StateCopy)
  333. //============================================================================================
  334. //Инициализировать объект
  335. bool StateStringSet::Create(MOPReader & reader)
  336. {
  337. name = reader.String().c_str();
  338. initState = reader.String().c_str();
  339. Activate(reader.Bool());
  340. return true;
  341. }
  342. //Активировать/деактивировать объект
  343. void StateStringSet::Activate(bool isActive)
  344. {
  345. if(isActive)
  346. {
  347. const char * n = GetName(name, true);
  348. if(n)
  349. {
  350. if(api->Storage().SetString(n, initState))
  351. {
  352. LogicDebug("Activate, set state \"%s\" to \"%s\"", n, initState);
  353. }else{
  354. LogicDebugError("Cant set state \"%s\", invalidate type", n);
  355. }
  356. }
  357. }else{
  358. LogicDebug("Deactivate: ignore");
  359. }
  360. }
  361. MOP_BEGINLISTG(StateStringSet, "State string set", '1.00', 10, "Managment")
  362. MOP_STRING("State name", "")
  363. MOP_STRING("State", "")
  364. MOP_BOOL("Active", false)
  365. MOP_ENDLIST(StateStringSet)
  366. //Инициализировать объект
  367. bool StateStringCheck::Create(MOPReader & reader)
  368. {
  369. inActiveProcess = false;
  370. name = reader.String().c_str();
  371. value = reader.String().c_str();
  372. triggerEq.Init(reader);
  373. triggerNEq.Init(reader);
  374. return true;
  375. }
  376. //Активировать/деактивировать объект
  377. void StateStringCheck::Activate(bool isActive)
  378. {
  379. if(inActiveProcess)
  380. {
  381. LogicDebugError("Recursive call detected!");
  382. return;
  383. }
  384. inActiveProcess = true;
  385. if(isActive)
  386. {
  387. const char * n = GetName(name, false);
  388. if(n)
  389. {
  390. const char * sv = api->Storage().GetString(n, null);
  391. if(sv)
  392. {
  393. bool res = string::IsEqual(sv, value);
  394. LogicDebug("Compare state \"%s\"(\"%s\") with \"%s\", strings is ", n, sv, value, res ? "equal" : "not equal");
  395. if(res)
  396. {
  397. triggerEq.Activate(Mission(), false);
  398. }else{
  399. triggerNEq.Activate(Mission(), false);
  400. }
  401. }else{
  402. LogicDebugError("Cant check state \"%s\", invalidate type", name);
  403. }
  404. }
  405. }else{
  406. LogicDebug("Deactivate: ignore");
  407. }
  408. inActiveProcess = false;
  409. }
  410. MOP_BEGINLISTCG(StateStringCheck, "State string check", '1.00', 0, "Compare string state with defined value", "Managment")
  411. MOP_STRING("State name", "")
  412. MOP_STRING("Value", "")
  413. MOP_MISSIONTRIGGERG("Equal", "eq.")
  414. MOP_MISSIONTRIGGERG("Not equal", "nq.")
  415. MOP_BOOL("Active", false)
  416. MOP_ENDLIST(StateStringCheck)
  417. //Инициализировать объект
  418. bool StateNumberSet::Create(MOPReader & reader)
  419. {
  420. name = reader.String().c_str();
  421. initState = reader.Float();
  422. Activate(reader.Bool());
  423. return true;
  424. }
  425. //Активировать/деактивировать объект
  426. void StateNumberSet::Activate(bool isActive)
  427. {
  428. if(isActive)
  429. {
  430. const char * n = GetName(name, true);
  431. if(n)
  432. {
  433. if(api->Storage().SetFloat(n, initState))
  434. {
  435. LogicDebug("Activate, set state \"%s\" to %f", n, initState);
  436. }else{
  437. LogicDebugError("Cant set state \"%s\", invalidate type", n);
  438. }
  439. }
  440. }else{
  441. LogicDebug("Deactivate: ignore");
  442. }
  443. }
  444. MOP_BEGINLISTG(StateNumberSet, "State number set", '1.00', 10, "Managment")
  445. MOP_STRING("State name", "")
  446. MOP_FLOAT("State", 0.0f)
  447. MOP_BOOL("Active", false)
  448. MOP_ENDLIST(StateNumberSet)
  449. //Инициализировать объект
  450. bool StateNumberCheck::Create(MOPReader & reader)
  451. {
  452. inActiveProcess = false;
  453. name = reader.String().c_str();
  454. value = reader.Float();
  455. valueName = reader.String().c_str();
  456. if(string::IsEmpty(valueName)) valueName = null;
  457. ConstString scnd = reader.Enum();
  458. for(long i = 0; i < ARRSIZE(cnds); i++)
  459. {
  460. if(scnd == cnds[i].name)
  461. {
  462. cnd = cnds[i].cnd;
  463. break;
  464. }
  465. }
  466. Assert(i < ARRSIZE(cnds));
  467. trigger.Init(reader);
  468. Activate(reader.Bool());
  469. return true;
  470. }
  471. //Активировать/деактивировать объект
  472. void StateNumberCheck::Activate(bool isActive)
  473. {
  474. if(inActiveProcess)
  475. {
  476. LogicDebugError("Recursive call detected!");
  477. return;
  478. }
  479. inActiveProcess = true;
  480. if(isActive)
  481. {
  482. const char * n = GetName(name, false);
  483. if(!n)
  484. {
  485. LogicDebugError("Can't build state path for State name: \"%s\"", name);
  486. inActiveProcess = false;
  487. return;
  488. }
  489. bool isOk = false;
  490. float arg1 = api->Storage().GetFloat(n, 0.0f, &isOk);
  491. if(!isOk)
  492. {
  493. LogicDebugError("Can't get number for State name: \"%s\"", n);
  494. inActiveProcess = false;
  495. return;
  496. }
  497. float arg2 = value;
  498. if(valueName)
  499. {
  500. n = GetName(valueName, false);
  501. if(!n)
  502. {
  503. LogicDebugError("Can't build state path for Value name: \"%s\"", valueName);
  504. inActiveProcess = false;
  505. return;
  506. }
  507. isOk = false;
  508. arg2 = api->Storage().GetFloat(n, 0.0f, &isOk);
  509. if(!isOk)
  510. {
  511. LogicDebugError("Can't get number for Value name: \"%s\"", n);
  512. inActiveProcess = false;
  513. return;
  514. }
  515. }
  516. bool isCnd = false;
  517. const char * scnd = "";
  518. switch(cnd)
  519. {
  520. case c_less:
  521. isCnd = (arg1 < arg2);
  522. scnd = "<";
  523. break;
  524. case c_less_eq:
  525. isCnd = (arg1 <= arg2);
  526. scnd = "<=";
  527. break;
  528. case c_eq:
  529. isCnd = fabsf(arg1 - arg2) < 1e-10f;
  530. scnd = "==";
  531. break;
  532. case c_above_eq:
  533. isCnd = (arg1 >= arg2);
  534. scnd = ">=";
  535. break;
  536. case c_above:
  537. isCnd = (arg1 > arg2);
  538. scnd = ">";
  539. break;
  540. default:
  541. Assert(false);
  542. }
  543. LogicDebug("Activate");
  544. LogicDebug("Arg1 is \"%s\" = %f", name, arg1);
  545. if(valueName)
  546. {
  547. LogicDebug("Arg2 is \"%s\" = %f", valueName, arg2);
  548. }else{
  549. LogicDebug("Arg2 is constant: %f", value);
  550. }
  551. LogicDebug("Activate, condition is %f %s %f", arg1, arg2);
  552. if(isCnd)
  553. {
  554. LogicDebug("Start trigger...");
  555. trigger.Activate(Mission(), false);
  556. }else{
  557. LogicDebug("Skip trigger, because condition is false...");
  558. }
  559. }else{
  560. LogicDebug("Deactivate: ignore");
  561. }
  562. inActiveProcess = false;
  563. }
  564. const char * StateNumberCheck::comment = "Check number state with default value";
  565. const StateNumberCheck::EnumParams StateNumberCheck::cnds[c_size] = {{c_less, ConstString("Less")},
  566. {c_less_eq, ConstString("Less-Equal")},
  567. {c_eq, ConstString("Equal")},
  568. {c_above_eq, ConstString("Above-Equal")},
  569. {c_above, ConstString("Above")}};
  570. MOP_BEGINLISTCG(StateNumberCheck, "State number check", '1.00', 0, StateNumberCheck::comment, "Managment")
  571. MOP_ENUMBEG("Cnd")
  572. for(long i = 0; i < ARRSIZE(StateNumberCheck::cnds); i++)
  573. {
  574. MOP_ENUMELEMENT(StateNumberCheck::cnds[i].name.c_str())
  575. }
  576. MOP_ENUMEND
  577. MOP_STRING("State name", "")
  578. MOP_FLOAT("Value", 0.0f)
  579. MOP_STRINGC("Value name", "", "Set there state name if you want use game state instead of value constant")
  580. MOP_ENUM("Cnd", "Condition")
  581. MOP_MISSIONTRIGGERG("Event", "")
  582. MOP_BOOL("Active", false)
  583. MOP_ENDLIST(StateNumberCheck)
  584. //Инициализировать объект
  585. bool StateNumberOperation::Create(MOPReader & reader)
  586. {
  587. name = reader.String().c_str();
  588. name2 = reader.String().c_str();
  589. value = reader.Float();
  590. valueName = reader.String().c_str();
  591. if(string::IsEmpty(valueName)) valueName = null;
  592. useLimits = reader.Bool();
  593. minResult = reader.Float();
  594. maxResult = reader.Float();
  595. ConstString sop = reader.Enum();
  596. for(long i = 0; i < ARRSIZE(ops); i++)
  597. {
  598. if(sop == ops[i].name)
  599. {
  600. op = ops[i].op;
  601. }
  602. }
  603. Activate(reader.Bool());
  604. return true;
  605. }
  606. //Активировать/деактивировать объект
  607. void StateNumberOperation::Activate(bool isActive)
  608. {
  609. if(isActive)
  610. {
  611. const char * n = GetName(name, false);
  612. if(!n)
  613. {
  614. LogicDebugError("Can't build state path for State1 name: \"%s\"", name);
  615. return;
  616. }
  617. bool isOk = false;
  618. float arg1 = api->Storage().GetFloat(n, 0.0f, &isOk);
  619. if(!isOk)
  620. {
  621. LogicDebugError("Can't get number for State1 name: \"%s\"", n);
  622. return;
  623. }
  624. float arg2 = value;
  625. if(valueName)
  626. {
  627. n = GetName(valueName, false);
  628. if(!n)
  629. {
  630. LogicDebugError("Can't build state path for Value name: \"%s\"", valueName);
  631. return;
  632. }
  633. isOk = false;
  634. arg2 = api->Storage().GetFloat(n, 0.0f, &isOk);
  635. if(!isOk)
  636. {
  637. LogicDebugError("Can't get number for Value name: \"%s\"", n);
  638. return;
  639. }
  640. }
  641. float res = 0.0f;
  642. switch(op)
  643. {
  644. case o_add:
  645. res = arg1 + arg2;
  646. LogicDebug("Activate, state number operation: \"%s\"(%f) + %f = %f", name, arg1, arg2, res);
  647. break;
  648. case o_sub_s_v:
  649. res = arg1 - arg2;
  650. LogicDebug("Activate, state number operation: \"%s\"(%f) - %f = (%f)", name, arg1, arg2, res);
  651. break;
  652. case o_sub_v_s:
  653. res = arg2 - arg1;
  654. LogicDebug("Activate, state number operation: %f - \"%s\"(%f) = (%f)", arg2, name, arg1, res);
  655. break;
  656. case o_mul:
  657. res = arg1*arg2;
  658. LogicDebug("Activate, state number operation: \"%s\"(%f)*%f = (%f)", name, arg1, arg2, res);
  659. break;
  660. case o_div_s_v:
  661. if(fabsf(arg2) < 1e-10f)
  662. {
  663. LogicDebugError("Activate, can't divide state by value, because value is zero");
  664. return;
  665. }
  666. res = arg1/arg2;
  667. LogicDebug("Activate, state number operation: \"%s\"(%f)/%f = (%f)", name, arg1, arg2, res);
  668. break;
  669. case o_div_v_s:
  670. if(fabsf(arg1) < 1e-10f)
  671. {
  672. LogicDebugError("Activate, can't divide value by state, because state \"%s\" is zero", name);
  673. return;
  674. }
  675. res = arg2/arg1;
  676. LogicDebug("Activate, state number operation: %f/\"%s\"(%f) = (%f)", arg2, name, arg1, res);
  677. break;
  678. }
  679. if(useLimits)
  680. {
  681. if(res < minResult)
  682. {
  683. LogicDebug("Use limits, change %f to Min(%f)", res, minResult);
  684. res = minResult;
  685. }
  686. if(res > maxResult)
  687. {
  688. LogicDebug("Use limits, change %f to Max(%f)", res, maxResult);
  689. res = maxResult;
  690. }
  691. }
  692. n = GetName(name2, true);
  693. if(!n)
  694. {
  695. LogicDebugError("Can't build state path for State2 name: \"%s\"", name);
  696. }
  697. if(api->Storage().SetFloat(n, res))
  698. {
  699. LogicDebug("Set relult %f to State2 name \"%s\"", res, n);
  700. }else{
  701. LogicDebugError("Can't set result to State2 name \"%s\", because state have not float type", n);
  702. }
  703. }else{
  704. LogicDebug("Deactivate: ignore");
  705. }
  706. }
  707. const char * StateNumberOperation::comment = "Mathimatic operations with state";
  708. const StateNumberOperation::EnumParams StateNumberOperation::ops[o_size] = {{o_add, ConstString("State2 = State1 + Value")},
  709. {o_sub_s_v, ConstString("State2 = State1 - Value")},
  710. {o_sub_v_s, ConstString("State2 = Value - State1")},
  711. {o_mul, ConstString("State2 = State1*Value")},
  712. {o_div_s_v, ConstString("State2 = State1 / Value")},
  713. {o_div_v_s, ConstString("State2 = Value / State1")}};
  714. MOP_BEGINLISTCG(StateNumberOperation, "State number operation", '1.00', 0, StateNumberOperation::comment, "Managment")
  715. MOP_ENUMBEG("Op")
  716. for(long i = 0; i < ARRSIZE(StateNumberOperation::ops); i++)
  717. {
  718. MOP_ENUMELEMENT(StateNumberOperation::ops[i].name.c_str())
  719. }
  720. MOP_ENUMEND
  721. MOP_STRING("State1 name", "")
  722. MOP_STRING("State2 name", "")
  723. MOP_FLOAT("Value", 0.0f)
  724. MOP_STRINGC("Value name", "", "Set there state name if you want use game state instead of value constant")
  725. MOP_BOOL("Use limits", true)
  726. MOP_FLOAT("Min", 0.0f)
  727. MOP_FLOAT("Max", 1000000.0f)
  728. MOP_ENUM("Op", "Operation")
  729. MOP_BOOL("Active", false)
  730. MOP_ENDLIST(StateNumberOperation)
  731. StateNumberGet::StateNumberGet() : buffer(_FL_, 256)
  732. {
  733. }
  734. //Инициализировать объект
  735. bool StateNumberGet::Create(MOPReader & reader)
  736. {
  737. objName = reader.String();
  738. mo.Reset();
  739. command = reader.String().c_str();
  740. //Параметры команды
  741. numParams = reader.Array();
  742. Assert(numParams <= ARRSIZE(params));
  743. for(long i = 0; i < numParams; i++)
  744. {
  745. params[i].str = reader.String().c_str();
  746. params[i].needTranslate = reader.Bool();
  747. }
  748. return true;
  749. }
  750. //Активировать/деактивировать объект
  751. void StateNumberGet::Activate(bool isActive)
  752. {
  753. if(!isActive)
  754. {
  755. LogicDebug("Deactivate: ignore");
  756. return;
  757. }
  758. if(!mo.Validate())
  759. {
  760. if(!FindObject(objName, mo))
  761. {
  762. LogicDebugError("Activate: Can't find mission object: \"%s\"", name);
  763. return;
  764. }
  765. Assert(mo.Validate());
  766. }
  767. buffer.Empty();
  768. const char * prms[ARRSIZE(params)];
  769. long trs[ARRSIZE(params)];
  770. for(long i = 0; i < numParams; i++)
  771. {
  772. prms[i] = null;
  773. trs[i] = -1;
  774. if(params[i].needTranslate)
  775. {
  776. const char * str = GetName(params[i].str, false);
  777. if(str)
  778. {
  779. trs[i] = buffer;
  780. long len = string::Size(str) + 1;
  781. buffer.AddElements(len);
  782. memcpy(&buffer[trs[i]], str, len);
  783. }
  784. }else{
  785. prms[i] = params[i].str;
  786. }
  787. }
  788. for(long i = 0; i < numParams; i++)
  789. {
  790. if(!prms[i])
  791. {
  792. if(trs[i] >= 0)
  793. {
  794. prms[i] = buffer.GetBuffer() + trs[i];
  795. }else{
  796. LogicDebugError("Activate: No send command. Can't get all parameters.");
  797. return;
  798. }
  799. }
  800. }
  801. LogicDebug("Execute command \"%s\" for object \"%s\"", command, name);
  802. for(long n = 0; n < numParams; n++)
  803. {
  804. LogicDebug("|-param %i: \"%s\"", n, prms[n]);
  805. }
  806. LogicDebugLevel(true);
  807. mo.Ptr()->Command(command, numParams, prms);
  808. LogicDebugLevel(false);
  809. }
  810. const char * StateNumberGet::comment = "This object send command with morphing params based on number states";
  811. MOP_BEGINLISTCG(StateNumberGet, "State number get", '1.00', 0, StateNumberGet::comment, "Managment")
  812. MOP_STRINGC("Object ID", "", "Mission object, what can receave command")
  813. MOP_STRINGC("Command", "", "Command name for object")
  814. MOP_ARRAYBEG("Command params", 0, 8)
  815. MOP_STRINGC("Prameter", "", "Parameter for command")
  816. MOP_BOOLC("Translate parameter", false, "Translate parameter like state name or leave as have")
  817. MOP_ARRAYEND
  818. MOP_ENDLIST(StateNumberGet)
  819. long MissionTestConfigurator::isCreated = 0;
  820. MissionTestConfigurator::MissionTestConfigurator()
  821. {
  822. }
  823. MissionTestConfigurator::~MissionTestConfigurator()
  824. {
  825. isCreated--;
  826. if(isCreated < 0)
  827. {
  828. isCreated = 0;
  829. }
  830. }
  831. //Инициализировать объект
  832. bool MissionTestConfigurator::EditMode_Create(MOPReader & reader)
  833. {
  834. if(isCreated > 1)
  835. {
  836. return false;
  837. }
  838. isCreated = 1;
  839. EditMode_Update(reader);
  840. return true;
  841. }
  842. //Обновить параметры
  843. bool MissionTestConfigurator::EditMode_Update(MOPReader & reader)
  844. {
  845. if(reader.Bool())
  846. {
  847. return true;
  848. }
  849. long count = reader.Array();
  850. for(long i = 0; i < count; i++)
  851. {
  852. const char * type = reader.Enum().c_str();
  853. const char * name = reader.String().c_str();
  854. const char * svalue = reader.String().c_str();
  855. float nvalue = reader.Float();
  856. if(name[0])
  857. {
  858. if(type[0] == 's' || type[0] == 'S')
  859. {
  860. api->Storage().SetString(name, svalue);
  861. }else{
  862. api->Storage().SetFloat(name, nvalue);
  863. }
  864. }
  865. }
  866. return true;
  867. }
  868. MOP_BEGINLISTCG(MissionTestConfigurator, "Test configurator", '1.00', 0, "Write states in editor", "Managment")
  869. MOP_ENUMBEG("tp")
  870. MOP_ENUMELEMENT("string")
  871. MOP_ENUMELEMENT("number")
  872. MOP_ENUMEND
  873. MOP_BOOLC("Edit process", true, "Set this flag when edit state name or type")
  874. MOP_ARRAYBEG("Command params", 0, 10)
  875. MOP_ENUM("tp", "Type")
  876. MOP_STRING("State name", "")
  877. MOP_STRING("String value", "")
  878. MOP_FLOAT("Number value", 0.0f)
  879. MOP_ARRAYEND
  880. MOP_ENDLIST(MissionTestConfigurator)