GuiScript.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  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> *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> *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 && win->win) {
  67. window->SetFocus(win->win);
  68. }
  69. }
  70. }
  71. /*
  72. =========================
  73. Script_ShowCursor
  74. =========================
  75. */
  76. void Script_ShowCursor(idWindow *window, idList<idGSWinVar> *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> *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> *src) {
  107. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  108. if (parm) {
  109. session->sw->PlayShaderDirectly(*parm);
  110. }
  111. }
  112. /*
  113. =========================
  114. Script_EvalRegs
  115. =========================
  116. */
  117. void Script_EvalRegs(idWindow *window, idList<idGSWinVar> *src) {
  118. window->EvalRegs(-1, true);
  119. }
  120. /*
  121. =========================
  122. Script_EndGame
  123. =========================
  124. */
  125. void Script_EndGame( idWindow *window, idList<idGSWinVar> *src ) {
  126. cvarSystem->SetCVarBool( "g_nightmare", true );
  127. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
  128. }
  129. /*
  130. =========================
  131. Script_ResetTime
  132. =========================
  133. */
  134. void Script_ResetTime(idWindow *window, idList<idGSWinVar> *src) {
  135. idWinStr *parm = dynamic_cast<idWinStr*>((*src)[0].var);
  136. drawWin_t *win = NULL;
  137. if (parm && src->Num() > 1) {
  138. win = window->GetGui()->GetDesktop()->FindChildByName(*parm);
  139. parm = dynamic_cast<idWinStr*>((*src)[1].var);
  140. }
  141. if (win && win->win) {
  142. win->win->ResetTime(atoi(*parm));
  143. win->win->EvalRegs(-1, true);
  144. } else {
  145. window->ResetTime(atoi(*parm));
  146. window->EvalRegs(-1, true);
  147. }
  148. }
  149. /*
  150. =========================
  151. Script_ResetCinematics
  152. =========================
  153. */
  154. void Script_ResetCinematics(idWindow *window, idList<idGSWinVar> *src) {
  155. window->ResetCinematics();
  156. }
  157. /*
  158. =========================
  159. Script_Transition
  160. =========================
  161. */
  162. void Script_Transition(idWindow *window, idList<idGSWinVar> *src) {
  163. // transitions always affect rect or vec4 vars
  164. if (src->Num() >= 4) {
  165. idWinRectangle *rect = NULL;
  166. idWinVec4 *vec4 = dynamic_cast<idWinVec4*>((*src)[0].var);
  167. //
  168. // added float variable
  169. idWinFloat* val = NULL;
  170. //
  171. if (vec4 == NULL) {
  172. rect = dynamic_cast<idWinRectangle*>((*src)[0].var);
  173. //
  174. // added float variable
  175. if ( NULL == rect ) {
  176. val = dynamic_cast<idWinFloat*>((*src)[0].var);
  177. }
  178. //
  179. }
  180. idWinVec4 *from = dynamic_cast<idWinVec4*>((*src)[1].var);
  181. idWinVec4 *to = dynamic_cast<idWinVec4*>((*src)[2].var);
  182. idWinStr *timeStr = dynamic_cast<idWinStr*>((*src)[3].var);
  183. //
  184. // added float variable
  185. if (!((vec4 || rect || val) && from && to && timeStr)) {
  186. //
  187. common->Warning("Bad transition in gui %s in window %s\n", window->GetGui()->GetSourceFile(), window->GetName());
  188. return;
  189. }
  190. int time = atoi(*timeStr);
  191. float ac = 0.0f;
  192. float dc = 0.0f;
  193. if (src->Num() > 4) {
  194. idWinStr *acv = dynamic_cast<idWinStr*>((*src)[4].var);
  195. idWinStr *dcv = dynamic_cast<idWinStr*>((*src)[5].var);
  196. assert(acv && dcv);
  197. ac = atof(*acv);
  198. dc = atof(*dcv);
  199. }
  200. if (vec4) {
  201. vec4->SetEval(false);
  202. window->AddTransition(vec4, *from, *to, time, ac, dc);
  203. //
  204. // added float variable
  205. } else if ( val ) {
  206. val->SetEval ( false );
  207. window->AddTransition(val, *from, *to, time, ac, dc);
  208. //
  209. } else {
  210. rect->SetEval(false);
  211. window->AddTransition(rect, *from, *to, time, ac, dc);
  212. }
  213. window->StartTransition();
  214. }
  215. }
  216. typedef struct {
  217. const char *name;
  218. void (*handler) (idWindow *window, idList<idGSWinVar> *src);
  219. int mMinParms;
  220. int mMaxParms;
  221. } guiCommandDef_t;
  222. guiCommandDef_t commandList[] = {
  223. { "set", Script_Set, 2, 999 },
  224. { "setFocus", Script_SetFocus, 1, 1 },
  225. { "endGame", Script_EndGame, 0, 0 },
  226. { "resetTime", Script_ResetTime, 0, 2 },
  227. { "showCursor", Script_ShowCursor, 1, 1 },
  228. { "resetCinematics", Script_ResetCinematics, 0, 2 },
  229. { "transition", Script_Transition, 4, 6 },
  230. { "localSound", Script_LocalSound, 1, 1 },
  231. { "runScript", Script_RunScript, 1, 1 },
  232. { "evalRegs", Script_EvalRegs, 0, 0 }
  233. };
  234. int scriptCommandCount = sizeof(commandList) / sizeof(guiCommandDef_t);
  235. /*
  236. =========================
  237. idGuiScript::idGuiScript
  238. =========================
  239. */
  240. idGuiScript::idGuiScript() {
  241. ifList = NULL;
  242. elseList = NULL;
  243. conditionReg = -1;
  244. handler = NULL;
  245. parms.SetGranularity( 2 );
  246. }
  247. /*
  248. =========================
  249. idGuiScript::~idGuiScript
  250. =========================
  251. */
  252. idGuiScript::~idGuiScript() {
  253. delete ifList;
  254. delete elseList;
  255. int c = parms.Num();
  256. for ( int i = 0; i < c; i++ ) {
  257. if ( parms[i].own ) {
  258. delete parms[i].var;
  259. }
  260. }
  261. }
  262. /*
  263. =========================
  264. idGuiScript::WriteToSaveGame
  265. =========================
  266. */
  267. void idGuiScript::WriteToSaveGame( idFile *savefile ) {
  268. int i;
  269. if ( ifList ) {
  270. ifList->WriteToSaveGame( savefile );
  271. }
  272. if ( elseList ) {
  273. elseList->WriteToSaveGame( savefile );
  274. }
  275. savefile->Write( &conditionReg, sizeof( conditionReg ) );
  276. for ( i = 0; i < parms.Num(); i++ ) {
  277. if ( parms[i].own ) {
  278. parms[i].var->WriteToSaveGame( savefile );
  279. }
  280. }
  281. }
  282. /*
  283. =========================
  284. idGuiScript::ReadFromSaveGame
  285. =========================
  286. */
  287. void idGuiScript::ReadFromSaveGame( idFile *savefile ) {
  288. int i;
  289. if ( ifList ) {
  290. ifList->ReadFromSaveGame( savefile );
  291. }
  292. if ( elseList ) {
  293. elseList->ReadFromSaveGame( savefile );
  294. }
  295. savefile->Read( &conditionReg, sizeof( conditionReg ) );
  296. for ( i = 0; i < parms.Num(); i++ ) {
  297. if ( parms[i].own ) {
  298. parms[i].var->ReadFromSaveGame( savefile );
  299. }
  300. }
  301. }
  302. /*
  303. =========================
  304. idGuiScript::Parse
  305. =========================
  306. */
  307. bool idGuiScript::Parse(idParser *src) {
  308. int i;
  309. // first token should be function call
  310. // then a potentially variable set of parms
  311. // ended with a ;
  312. idToken token;
  313. if ( !src->ReadToken(&token) ) {
  314. src->Error( "Unexpected end of file" );
  315. return false;
  316. }
  317. handler = NULL;
  318. for ( i = 0; i < scriptCommandCount ; i++ ) {
  319. if ( idStr::Icmp(token, commandList[i].name) == 0 ) {
  320. handler = commandList[i].handler;
  321. break;
  322. }
  323. }
  324. if (handler == NULL) {
  325. src->Error("Uknown script call %s", token.c_str());
  326. }
  327. // now read parms til ;
  328. // all parms are read as idWinStr's but will be fixed up later
  329. // to be proper types
  330. while (1) {
  331. if ( !src->ReadToken(&token) ) {
  332. src->Error( "Unexpected end of file" );
  333. return false;
  334. }
  335. if (idStr::Icmp(token, ";") == 0) {
  336. break;
  337. }
  338. if (idStr::Icmp(token, "}") == 0) {
  339. src->UnreadToken(&token);
  340. break;
  341. }
  342. idWinStr *str = new idWinStr();
  343. *str = token;
  344. idGSWinVar wv;
  345. wv.own = true;
  346. wv.var = str;
  347. parms.Append( wv );
  348. }
  349. //
  350. // verify min/max params
  351. if ( handler && (parms.Num() < commandList[i].mMinParms || parms.Num() > commandList[i].mMaxParms ) ) {
  352. src->Error("incorrect number of parameters for script %s", commandList[i].name );
  353. }
  354. //
  355. return true;
  356. }
  357. /*
  358. =========================
  359. idGuiScriptList::Execute
  360. =========================
  361. */
  362. void idGuiScriptList::Execute(idWindow *win) {
  363. int c = list.Num();
  364. for (int i = 0; i < c; i++) {
  365. idGuiScript *gs = list[i];
  366. assert(gs);
  367. if (gs->conditionReg >= 0) {
  368. if (win->HasOps()) {
  369. float f = win->EvalRegs(gs->conditionReg);
  370. if (f) {
  371. if (gs->ifList) {
  372. win->RunScriptList(gs->ifList);
  373. }
  374. } else if (gs->elseList) {
  375. win->RunScriptList(gs->elseList);
  376. }
  377. }
  378. }
  379. gs->Execute(win);
  380. }
  381. }
  382. /*
  383. =========================
  384. idGuiScriptList::FixupParms
  385. =========================
  386. */
  387. void idGuiScript::FixupParms(idWindow *win) {
  388. if (handler == &Script_Set) {
  389. bool precacheBackground = false;
  390. bool precacheSounds = false;
  391. idWinStr *str = dynamic_cast<idWinStr*>(parms[0].var);
  392. assert(str);
  393. idWinVar *dest = win->GetWinVarByName(*str, true);
  394. if (dest) {
  395. delete parms[0].var;
  396. parms[0].var = dest;
  397. parms[0].own = false;
  398. if ( dynamic_cast<idWinBackground *>(dest) != NULL ) {
  399. precacheBackground = true;
  400. }
  401. } else if ( idStr::Icmp( str->c_str(), "cmd" ) == 0 ) {
  402. precacheSounds = true;
  403. }
  404. int parmCount = parms.Num();
  405. for (int i = 1; i < parmCount; i++) {
  406. idWinStr *str = dynamic_cast<idWinStr*>(parms[i].var);
  407. if (idStr::Icmpn(*str, "gui::", 5) == 0) {
  408. // always use a string here, no point using a float if it is one
  409. // FIXME: This creates duplicate variables, while not technically a problem since they
  410. // are all bound to the same guiDict, it does consume extra memory and is generally a bad thing
  411. idWinStr* defvar = new idWinStr();
  412. defvar->Init ( *str, win );
  413. win->AddDefinedVar ( defvar );
  414. delete parms[i].var;
  415. parms[i].var = defvar;
  416. parms[i].own = false;
  417. //dest = win->GetWinVarByName(*str, true);
  418. //if (dest) {
  419. // delete parms[i].var;
  420. // parms[i].var = dest;
  421. // parms[i].own = false;
  422. //}
  423. //
  424. } else if ((*str[0]) == '$') {
  425. //
  426. // dont include the $ when asking for variable
  427. dest = win->GetGui()->GetDesktop()->GetWinVarByName((const char*)(*str) + 1, true);
  428. //
  429. if (dest) {
  430. delete parms[i].var;
  431. parms[i].var = dest;
  432. parms[i].own = false;
  433. }
  434. } else if ( idStr::Cmpn( str->c_str(), STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ) {
  435. str->Set( common->GetLanguageDict()->GetString( str->c_str() ) );
  436. } else if ( precacheBackground ) {
  437. const idMaterial *mat = declManager->FindMaterial( str->c_str() );
  438. mat->SetSort( SS_GUI );
  439. } else if ( precacheSounds ) {
  440. // Search for "play <...>"
  441. idToken token;
  442. idParser parser( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
  443. parser.LoadMemory(str->c_str(), str->Length(), "command");
  444. while ( parser.ReadToken(&token) ) {
  445. if ( token.Icmp("play") == 0 ) {
  446. if ( parser.ReadToken(&token) && ( token != "" ) ) {
  447. declManager->FindSound( token.c_str() );
  448. }
  449. }
  450. }
  451. }
  452. }
  453. } else if (handler == &Script_Transition) {
  454. if (parms.Num() < 4) {
  455. common->Warning("Window %s in gui %s has a bad transition definition", win->GetName(), win->GetGui()->GetSourceFile());
  456. }
  457. idWinStr *str = dynamic_cast<idWinStr*>(parms[0].var);
  458. assert(str);
  459. //
  460. drawWin_t *destowner;
  461. idWinVar *dest = win->GetWinVarByName(*str, true, &destowner );
  462. //
  463. if (dest) {
  464. delete parms[0].var;
  465. parms[0].var = dest;
  466. parms[0].own = false;
  467. } else {
  468. 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());
  469. }
  470. //
  471. // support variables as parameters
  472. int c;
  473. for ( c = 1; c < 3; c ++ ) {
  474. str = dynamic_cast<idWinStr*>(parms[c].var);
  475. idWinVec4 *v4 = new idWinVec4;
  476. parms[c].var = v4;
  477. parms[c].own = true;
  478. drawWin_t* owner;
  479. if ( (*str[0]) == '$' ) {
  480. dest = win->GetWinVarByName ( (const char*)(*str) + 1, true, &owner );
  481. } else {
  482. dest = NULL;
  483. }
  484. if ( dest ) {
  485. idWindow* ownerparent;
  486. idWindow* destparent;
  487. if ( owner ) {
  488. ownerparent = owner->simp?owner->simp->GetParent():owner->win->GetParent();
  489. destparent = destowner->simp?destowner->simp->GetParent():destowner->win->GetParent();
  490. // If its the rectangle they are referencing then adjust it
  491. if ( ownerparent && destparent &&
  492. (dest == (owner->simp?owner->simp->GetWinVarByName ( "rect" ):owner->win->GetWinVarByName ( "rect" ) ) ) )
  493. {
  494. idRectangle rect;
  495. rect = *(dynamic_cast<idWinRectangle*>(dest));
  496. ownerparent->ClientToScreen ( &rect );
  497. destparent->ScreenToClient ( &rect );
  498. *v4 = rect.ToVec4 ( );
  499. } else {
  500. v4->Set ( dest->c_str ( ) );
  501. }
  502. } else {
  503. v4->Set ( dest->c_str ( ) );
  504. }
  505. } else {
  506. v4->Set(*str);
  507. }
  508. delete str;
  509. }
  510. //
  511. } else {
  512. int c = parms.Num();
  513. for (int i = 0; i < c; i++) {
  514. parms[i].var->Init(parms[i].var->c_str(), win);
  515. }
  516. }
  517. }
  518. /*
  519. =========================
  520. idGuiScriptList::FixupParms
  521. =========================
  522. */
  523. void idGuiScriptList::FixupParms(idWindow *win) {
  524. int c = list.Num();
  525. for (int i = 0; i < c; i++) {
  526. idGuiScript *gs = list[i];
  527. gs->FixupParms(win);
  528. if (gs->ifList) {
  529. gs->ifList->FixupParms(win);
  530. }
  531. if (gs->elseList) {
  532. gs->elseList->FixupParms(win);
  533. }
  534. }
  535. }
  536. /*
  537. =========================
  538. idGuiScriptList::WriteToSaveGame
  539. =========================
  540. */
  541. void idGuiScriptList::WriteToSaveGame( idFile *savefile ) {
  542. int i;
  543. for ( i = 0; i < list.Num(); i++ ) {
  544. list[i]->WriteToSaveGame( savefile );
  545. }
  546. }
  547. /*
  548. =========================
  549. idGuiScriptList::ReadFromSaveGame
  550. =========================
  551. */
  552. void idGuiScriptList::ReadFromSaveGame( idFile *savefile ) {
  553. int i;
  554. for ( i = 0; i < list.Num(); i++ ) {
  555. list[i]->ReadFromSaveGame( savefile );
  556. }
  557. }