DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }