GuiScript.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "Window.h"
  23. #include "Winvar.h"
  24. #include "GuiScript.h"
  25. #include "UserInterfaceLocal.h"
  26. /*
  27. =========================
  28. Script_Set
  29. =========================
  30. */
  31. void Script_Set(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  32. idStr key, val;
  33. idWinStr *dest = dynamic_cast<idWinStr*>((*src)[0].var);
  34. if (dest) {
  35. if (idStr::Icmp(*dest, "cmd") == 0) {
  36. dest = dynamic_cast<idWinStr*>((*src)[1].var);
  37. int parmCount = src->Num();
  38. if (parmCount > 2) {
  39. val = dest->c_str();
  40. int i = 2;
  41. while (i < parmCount) {
  42. val += " \"";
  43. val += (*src)[i].var->c_str();
  44. val += "\"";
  45. i++;
  46. }
  47. window->AddCommand(val);
  48. } else {
  49. window->AddCommand(*dest);
  50. }
  51. return;
  52. }
  53. }
  54. (*src)[0].var->Set((*src)[1].var->c_str());
  55. (*src)[0].var->SetEval(false);
  56. }
  57. /*
  58. =========================
  59. Script_SetFocus
  60. =========================
  61. */
  62. void Script_SetFocus(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  63. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  64. if (parm) {
  65. drawWin_t *win = window->GetGui()->GetDesktop()->FindChildByName(*parm);
  66. if ( win != NULL && win->win != NULL ) {
  67. window->SetFocus(win->win);
  68. }
  69. }
  70. }
  71. /*
  72. =========================
  73. Script_ShowCursor
  74. =========================
  75. */
  76. void Script_ShowCursor(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  77. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  78. if ( parm ) {
  79. if ( atoi( *parm ) ) {
  80. window->GetGui()->GetDesktop()->ClearFlag( WIN_NOCURSOR );
  81. } else {
  82. window->GetGui()->GetDesktop()->SetFlag( WIN_NOCURSOR );
  83. }
  84. }
  85. }
  86. /*
  87. =========================
  88. Script_RunScript
  89. run scripts must come after any set cmd set's in the script
  90. =========================
  91. */
  92. void Script_RunScript(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  93. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  94. if (parm) {
  95. idStr str = window->cmd;
  96. str += " ; runScript ";
  97. str += parm->c_str();
  98. window->cmd = str;
  99. }
  100. }
  101. /*
  102. =========================
  103. Script_LocalSound
  104. =========================
  105. */
  106. void Script_LocalSound(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  107. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  108. if (parm) {
  109. common->SW()->PlayShaderDirectly(*parm);
  110. }
  111. }
  112. /*
  113. =========================
  114. Script_EvalRegs
  115. =========================
  116. */
  117. void Script_EvalRegs(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  118. window->EvalRegs(-1, true);
  119. }
  120. /*
  121. =========================
  122. Script_EndGame
  123. =========================
  124. */
  125. void Script_EndGame( idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src ) {
  126. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
  127. }
  128. /*
  129. =========================
  130. Script_ResetTime
  131. =========================
  132. */
  133. void Script_ResetTime(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  134. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  135. drawWin_t *win = NULL;
  136. if (parm != NULL && src->Num() > 1) {
  137. win = window->GetGui()->GetDesktop()->FindChildByName(*parm);
  138. parm = dynamic_cast<idWinStr*>((*src)[1].var);
  139. }
  140. if ( parm == NULL ) {
  141. return;
  142. }
  143. if (win != NULL && win->win != NULL) {
  144. win->win->ResetTime(atoi(*parm));
  145. win->win->EvalRegs(-1, true);
  146. } else {
  147. window->ResetTime(atoi(*parm));
  148. window->EvalRegs(-1, true);
  149. }
  150. }
  151. /*
  152. =========================
  153. Script_ResetCinematics
  154. =========================
  155. */
  156. void Script_ResetCinematics(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  157. window->ResetCinematics();
  158. }
  159. /*
  160. =========================
  161. Script_Transition
  162. =========================
  163. */
  164. void Script_Transition(idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src) {
  165. // transitions always affect rect or vec4 vars
  166. if (src->Num() >= 4) {
  167. idWinRectangle *rect = NULL;
  168. idWinVec4 *vec4 = dynamic_cast<idWinVec4*>((*src)[0].var);
  169. //
  170. // added float variable
  171. idWinFloat* val = NULL;
  172. //
  173. if (vec4 == NULL) {
  174. rect = dynamic_cast<idWinRectangle*>((*src)[0].var);
  175. //
  176. // added float variable
  177. if ( NULL == rect ) {
  178. val = dynamic_cast<idWinFloat*>((*src)[0].var);
  179. }
  180. //
  181. }
  182. idWinVec4 *from = dynamic_cast<idWinVec4*>((*src)[1].var);
  183. idWinVec4 *to = dynamic_cast<idWinVec4*>((*src)[2].var);
  184. idWinStr *timeStr = dynamic_cast<idWinStr*>((*src)[3].var);
  185. //
  186. // added float variable
  187. if (!((vec4 || rect || val) && from && to && timeStr)) {
  188. //
  189. common->Warning("Bad transition in gui %s in window %s\n", window->GetGui()->GetSourceFile(), window->GetName());
  190. return;
  191. }
  192. int time = atoi(*timeStr);
  193. float ac = 0.0f;
  194. float dc = 0.0f;
  195. if (src->Num() > 4) {
  196. idWinStr *acv = dynamic_cast<idWinStr*>((*src)[4].var);
  197. idWinStr *dcv = dynamic_cast<idWinStr*>((*src)[5].var);
  198. assert(acv && dcv);
  199. ac = atof(*acv);
  200. dc = atof(*dcv);
  201. }
  202. if (vec4) {
  203. vec4->SetEval(false);
  204. window->AddTransition(vec4, *from, *to, time, ac, dc);
  205. //
  206. // added float variable
  207. } else if ( val ) {
  208. val->SetEval ( false );
  209. window->AddTransition(val, *from, *to, time, ac, dc);
  210. //
  211. } else {
  212. rect->SetEval(false);
  213. window->AddTransition(rect, *from, *to, time, ac, dc);
  214. }
  215. window->StartTransition();
  216. }
  217. }
  218. typedef struct {
  219. const char *name;
  220. void (*handler) (idWindow *window, idList<idGSWinVar, TAG_OLD_UI> *src);
  221. int mMinParms;
  222. int mMaxParms;
  223. } guiCommandDef_t;
  224. guiCommandDef_t commandList[] = {
  225. { "set", Script_Set, 2, 999 },
  226. { "setFocus", Script_SetFocus, 1, 1 },
  227. { "endGame", Script_EndGame, 0, 0 },
  228. { "resetTime", Script_ResetTime, 0, 2 },
  229. { "showCursor", Script_ShowCursor, 1, 1 },
  230. { "resetCinematics", Script_ResetCinematics, 0, 2 },
  231. { "transition", Script_Transition, 4, 6 },
  232. { "localSound", Script_LocalSound, 1, 1 },
  233. { "runScript", Script_RunScript, 1, 1 },
  234. { "evalRegs", Script_EvalRegs, 0, 0 }
  235. };
  236. int scriptCommandCount = sizeof(commandList) / sizeof(guiCommandDef_t);
  237. /*
  238. =========================
  239. idGuiScript::idGuiScript
  240. =========================
  241. */
  242. idGuiScript::idGuiScript() {
  243. ifList = NULL;
  244. elseList = NULL;
  245. conditionReg = -1;
  246. handler = NULL;
  247. parms.SetGranularity( 2 );
  248. }
  249. /*
  250. =========================
  251. idGuiScript::~idGuiScript
  252. =========================
  253. */
  254. idGuiScript::~idGuiScript() {
  255. delete ifList;
  256. delete elseList;
  257. int c = parms.Num();
  258. for ( int i = 0; i < c; i++ ) {
  259. if ( parms[i].own ) {
  260. delete parms[i].var;
  261. }
  262. }
  263. }
  264. /*
  265. =========================
  266. idGuiScript::WriteToSaveGame
  267. =========================
  268. */
  269. void idGuiScript::WriteToSaveGame( idFile *savefile ) {
  270. int i;
  271. if ( ifList ) {
  272. ifList->WriteToSaveGame( savefile );
  273. }
  274. if ( elseList ) {
  275. elseList->WriteToSaveGame( savefile );
  276. }
  277. savefile->Write( &conditionReg, sizeof( conditionReg ) );
  278. for ( i = 0; i < parms.Num(); i++ ) {
  279. if ( parms[i].own ) {
  280. parms[i].var->WriteToSaveGame( savefile );
  281. }
  282. }
  283. }
  284. /*
  285. =========================
  286. idGuiScript::ReadFromSaveGame
  287. =========================
  288. */
  289. void idGuiScript::ReadFromSaveGame( idFile *savefile ) {
  290. int i;
  291. if ( ifList ) {
  292. ifList->ReadFromSaveGame( savefile );
  293. }
  294. if ( elseList ) {
  295. elseList->ReadFromSaveGame( savefile );
  296. }
  297. savefile->Read( &conditionReg, sizeof( conditionReg ) );
  298. for ( i = 0; i < parms.Num(); i++ ) {
  299. if ( parms[i].own ) {
  300. parms[i].var->ReadFromSaveGame( savefile );
  301. }
  302. }
  303. }
  304. /*
  305. =========================
  306. idGuiScript::Parse
  307. =========================
  308. */
  309. bool idGuiScript::Parse(idTokenParser *src) {
  310. int i;
  311. // first token should be function call
  312. // then a potentially variable set of parms
  313. // ended with a ;
  314. idToken token;
  315. if ( !src->ReadToken(&token) ) {
  316. src->Error( "Unexpected end of file" );
  317. return false;
  318. }
  319. handler = NULL;
  320. for ( i = 0; i < scriptCommandCount ; i++ ) {
  321. if ( idStr::Icmp(token, commandList[i].name) == 0 ) {
  322. handler = commandList[i].handler;
  323. break;
  324. }
  325. }
  326. if (handler == NULL) {
  327. src->Error("Uknown script call %s", token.c_str());
  328. }
  329. // now read parms til ;
  330. // all parms are read as idWinStr's but will be fixed up later
  331. // to be proper types
  332. while (1) {
  333. if ( !src->ReadToken(&token) ) {
  334. src->Error( "Unexpected end of file" );
  335. return false;
  336. }
  337. if (idStr::Icmp(token, ";") == 0) {
  338. break;
  339. }
  340. if (idStr::Icmp(token, "}") == 0) {
  341. src->UnreadToken(&token);
  342. break;
  343. }
  344. idWinStr *str = new (TAG_OLD_UI) idWinStr();
  345. *str = token;
  346. idGSWinVar wv;
  347. wv.own = true;
  348. wv.var = str;
  349. parms.Append( wv );
  350. }
  351. //
  352. // verify min/max params
  353. if ( handler && (parms.Num() < commandList[i].mMinParms || parms.Num() > commandList[i].mMaxParms ) ) {
  354. src->Error("incorrect number of parameters for script %s", commandList[i].name );
  355. }
  356. //
  357. return true;
  358. }
  359. /*
  360. =========================
  361. idGuiScriptList::Execute
  362. =========================
  363. */
  364. void idGuiScriptList::Execute(idWindow *win) {
  365. int c = list.Num();
  366. for (int i = 0; i < c; i++) {
  367. idGuiScript *gs = list[i];
  368. assert(gs);
  369. if (gs->conditionReg >= 0) {
  370. if (win->HasOps()) {
  371. float f = win->EvalRegs(gs->conditionReg);
  372. if (f) {
  373. if (gs->ifList) {
  374. win->RunScriptList(gs->ifList);
  375. }
  376. } else if (gs->elseList) {
  377. win->RunScriptList(gs->elseList);
  378. }
  379. }
  380. }
  381. gs->Execute(win);
  382. }
  383. }
  384. /*
  385. =========================
  386. idGuiScriptList::FixupParms
  387. =========================
  388. */
  389. void idGuiScript::FixupParms(idWindow *win) {
  390. if (handler == &Script_Set) {
  391. bool precacheBackground = false;
  392. bool precacheSounds = false;
  393. idWinStr *str = dynamic_cast<idWinStr*>(parms[0].var);
  394. assert(str);
  395. idWinVar *dest = win->GetWinVarByName(*str, true);
  396. if (dest) {
  397. delete parms[0].var;
  398. parms[0].var = dest;
  399. parms[0].own = false;
  400. if ( dynamic_cast<idWinBackground *>(dest) != NULL ) {
  401. precacheBackground = true;
  402. }
  403. } else if ( idStr::Icmp( str->c_str(), "cmd" ) == 0 ) {
  404. precacheSounds = true;
  405. }
  406. int parmCount = parms.Num();
  407. for (int i = 1; i < parmCount; i++) {
  408. idWinStr *str = dynamic_cast<idWinStr*>(parms[i].var);
  409. if (idStr::Icmpn(*str, "gui::", 5) == 0) {
  410. // always use a string here, no point using a float if it is one
  411. // FIXME: This creates duplicate variables, while not technically a problem since they
  412. // are all bound to the same guiDict, it does consume extra memory and is generally a bad thing
  413. idWinStr* defvar = new (TAG_OLD_UI) idWinStr();
  414. defvar->Init ( *str, win );
  415. win->AddDefinedVar ( defvar );
  416. delete parms[i].var;
  417. parms[i].var = defvar;
  418. parms[i].own = false;
  419. //dest = win->GetWinVarByName(*str, true);
  420. //if (dest) {
  421. // delete parms[i].var;
  422. // parms[i].var = dest;
  423. // parms[i].own = false;
  424. //}
  425. //
  426. } else if ((*str[0]) == '$') {
  427. //
  428. // dont include the $ when asking for variable
  429. dest = win->GetGui()->GetDesktop()->GetWinVarByName((const char*)(*str) + 1, true);
  430. //
  431. if (dest) {
  432. delete parms[i].var;
  433. parms[i].var = dest;
  434. parms[i].own = false;
  435. }
  436. } else if ( idStr::Cmpn( str->c_str(), STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ) {
  437. str->Set( idLocalization::GetString( str->c_str() ) );
  438. } else if ( precacheBackground ) {
  439. const idMaterial *mat = declManager->FindMaterial( str->c_str() );
  440. mat->SetSort( SS_GUI );
  441. } else if ( precacheSounds ) {
  442. // Search for "play <...>"
  443. idToken token;
  444. idParser parser( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
  445. parser.LoadMemory(str->c_str(), str->Length(), "command");
  446. while ( parser.ReadToken(&token) ) {
  447. if ( token.Icmp("play") == 0 ) {
  448. if ( parser.ReadToken(&token) && ( token != "" ) ) {
  449. declManager->FindSound( token.c_str() );
  450. }
  451. }
  452. }
  453. }
  454. }
  455. } else if (handler == &Script_Transition) {
  456. if (parms.Num() < 4) {
  457. common->Warning("Window %s in gui %s has a bad transition definition", win->GetName(), win->GetGui()->GetSourceFile());
  458. }
  459. idWinStr *str = dynamic_cast<idWinStr*>(parms[0].var);
  460. assert(str);
  461. //
  462. drawWin_t *destowner;
  463. idWinVar *dest = win->GetWinVarByName(*str, true, &destowner );
  464. //
  465. if (dest) {
  466. delete parms[0].var;
  467. parms[0].var = dest;
  468. parms[0].own = false;
  469. } else {
  470. common->Warning("Window %s in gui %s: a transition does not have a valid destination var %s", win->GetName(), win->GetGui()->GetSourceFile(),str->c_str());
  471. }
  472. //
  473. // support variables as parameters
  474. int c;
  475. for ( c = 1; c < 3; c ++ ) {
  476. str = dynamic_cast<idWinStr*>(parms[c].var);
  477. idWinVec4 *v4 = new (TAG_OLD_UI) idWinVec4;
  478. parms[c].var = v4;
  479. parms[c].own = true;
  480. drawWin_t* owner = NULL;
  481. if ( (*str[0]) == '$' ) {
  482. dest = win->GetWinVarByName ( (const char*)(*str) + 1, true, &owner );
  483. } else {
  484. dest = NULL;
  485. }
  486. if ( dest ) {
  487. idWindow* ownerparent;
  488. idWindow* destparent;
  489. if ( owner != NULL ) {
  490. ownerparent = owner->simp?owner->simp->GetParent():owner->win->GetParent();
  491. destparent = destowner->simp?destowner->simp->GetParent():destowner->win->GetParent();
  492. // If its the rectangle they are referencing then adjust it
  493. if ( ownerparent && destparent &&
  494. (dest == (owner->simp?owner->simp->GetWinVarByName ( "rect" ):owner->win->GetWinVarByName ( "rect" ) ) ) )
  495. {
  496. idRectangle rect;
  497. rect = *(dynamic_cast<idWinRectangle*>(dest));
  498. ownerparent->ClientToScreen ( &rect );
  499. destparent->ScreenToClient ( &rect );
  500. *v4 = rect.ToVec4 ( );
  501. } else {
  502. v4->Set ( dest->c_str ( ) );
  503. }
  504. } else {
  505. v4->Set ( dest->c_str ( ) );
  506. }
  507. } else {
  508. v4->Set(*str);
  509. }
  510. delete str;
  511. }
  512. //
  513. } else if (handler == &Script_LocalSound) {
  514. idWinStr * str = dynamic_cast<idWinStr*>(parms[0].var);
  515. if ( str ) {
  516. declManager->FindSound( str->c_str() );
  517. }
  518. } else {
  519. int c = parms.Num();
  520. for (int i = 0; i < c; i++) {
  521. parms[i].var->Init(parms[i].var->c_str(), win);
  522. }
  523. }
  524. }
  525. /*
  526. =========================
  527. idGuiScriptList::FixupParms
  528. =========================
  529. */
  530. void idGuiScriptList::FixupParms(idWindow *win) {
  531. int c = list.Num();
  532. for (int i = 0; i < c; i++) {
  533. idGuiScript *gs = list[i];
  534. gs->FixupParms(win);
  535. if (gs->ifList) {
  536. gs->ifList->FixupParms(win);
  537. }
  538. if (gs->elseList) {
  539. gs->elseList->FixupParms(win);
  540. }
  541. }
  542. }
  543. /*
  544. =========================
  545. idGuiScriptList::WriteToSaveGame
  546. =========================
  547. */
  548. void idGuiScriptList::WriteToSaveGame( idFile *savefile ) {
  549. int i;
  550. for ( i = 0; i < list.Num(); i++ ) {
  551. list[i]->WriteToSaveGame( savefile );
  552. }
  553. }
  554. /*
  555. =========================
  556. idGuiScriptList::ReadFromSaveGame
  557. =========================
  558. */
  559. void idGuiScriptList::ReadFromSaveGame( idFile *savefile ) {
  560. int i;
  561. for ( i = 0; i < list.Num(); i++ ) {
  562. list[i]->ReadFromSaveGame( savefile );
  563. }
  564. }