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