Scripts.cpp 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program 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. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Scripts.cpp /////////////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: Generals
  34. //
  35. // File name: Scripts.cpp
  36. //
  37. // Created: John Ahlquist, Nov 2001
  38. //
  39. // Desc: Contains the information describing scripts.
  40. //
  41. //-----------------------------------------------------------------------------
  42. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  43. #include "Lib/BaseType.h"
  44. #define DEFINE_BUILDABLE_STATUS_NAMES
  45. #define DEFINE_OBJECT_STATUS_NAMES
  46. #define DEFINE_SCIENCE_AVAILABILITY_NAMES
  47. #include "Common/BorderColors.h"
  48. #include "Common/DataChunk.h"
  49. #include "Common/GameState.h"
  50. #include "Common/KindOf.h"
  51. #include "Common/Radar.h"
  52. #include "Common/ThingTemplate.h"
  53. #include "Common/Player.h"
  54. #include "Common/Xfer.h"
  55. #include "GameClient/ShellHooks.h"
  56. #include "GameLogic/Ai.h"
  57. #include "GameLogic/Object.h"
  58. #include "GameLogic/ScriptEngine.h"
  59. #include "GameLogic/SidesList.h"
  60. #include "GameLogic/Module/ContainModule.h"
  61. #ifdef _INTERNAL
  62. // for occasional debugging...
  63. //#pragma optimize("", off)
  64. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  65. #endif
  66. static Script *s_mtScript = NULL;
  67. static ScriptGroup *s_mtGroup = NULL;
  68. //
  69. // These strings must be in the same order as they are in their definitions
  70. // (See SHELL_SCRIPT_HOOK_* )
  71. //
  72. char *TheShellHookNames[]=
  73. {
  74. "ShellMainMenuCampaignPushed", //SHELL_SCRIPT_HOOK_MAIN_MENU_CAMPAIGN_SELECTED,
  75. "ShellMainMenuCampaignHighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_CAMPAIGN_HIGHLIGHTED,
  76. "ShellMainMenuCampaignUnhighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_CAMPAIGN_UNHIGHLIGHTED,
  77. "ShellMainMenuSkirmishPushed", //SHELL_SCRIPT_HOOK_MAIN_MENU_SKIRMISH_SELECTED,
  78. "ShellMainMenuSkirmishHighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_SKIRMISH_HIGHLIGHTED,
  79. "ShellMainMenuSkirmishUnhighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_SKIRMISH_UNHIGHLIGHTED,
  80. "ShellMainMenuOptionsPushed", //SHELL_SCRIPT_HOOK_MAIN_MENU_OPTIONS_SELECTED,
  81. "ShellMainMenuOptionsHighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_OPTIONS_HIGHLIGHTED,
  82. "ShellMainMenuOptionsUnhighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_OPTIONS_UNHIGHLIGHTED,
  83. "ShellMainMenuOnlinePushed", //SHELL_SCRIPT_HOOK_MAIN_MENU_ONLINE_SELECTED,
  84. "ShellMainMenuOnlineHighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_ONLINE_HIGHLIGHTED,
  85. "ShellMainMenuOnlineUnhighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_ONLINE_UNHIGHLIGHTED,
  86. "ShellMainMenuNetworkPushed", //SHELL_SCRIPT_HOOK_MAIN_MENU_NETWORK_SELECTED,
  87. "ShellMainMenuNetworkHighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_NETWORK_HIGHLIGHTED,
  88. "ShellMainMenuNetworkUnhighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_NETWORK_UNHIGHLIGHTED,
  89. "ShellMainMenuExitPushed", //SHELL_SCRIPT_HOOK_MAIN_MENU_EXIT_SELECTED,
  90. "ShellMainMenuExitHighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_EXIT_HIGHLIGHTED,
  91. "ShellMainMenuExitUnhighlighted", //SHELL_SCRIPT_HOOK_MAIN_MENU_EXIT_UNHIGHLIGHTED,
  92. "ShellGeneralsOnlineLogin", //SHELL_SCRIPT_HOOK_GENERALS_ONLINE_LOGIN,
  93. "ShellGeneralsOnlineLogout", //SHELL_SCRIPT_HOOK_GENERALS_ONLINE_LOGOUT,
  94. "ShellGeneralsOnlineEnteredFromGame", //SHELL_SCRIPT_HOOK_GENERALS_ONLINE_ENTERED_FROM_GAME,
  95. "ShellOptionsOpened", //SHELL_SCRIPT_HOOK_OPTIONS_OPENED,
  96. "ShellOptionsClosed", //SHELL_SCRIPT_HOOK_OPTIONS_CLOSED,
  97. "ShellSkirmishOpened", //SHELL_SCRIPT_HOOK_SKIRMISH_OPENED,
  98. "ShellSkirmishClosed", //SHELL_SCRIPT_HOOK_SKIRMISH_CLOSED,
  99. "ShellSkirmishEnteredFromGame", //SHELL_SCRIPT_HOOK_SKIRMISH_ENTERED_FROM_GAME,
  100. "ShellLANOpened", //SHELL_SCRIPT_HOOK_LAN_OPENED,
  101. "ShellLANClosed", //SHELL_SCRIPT_HOOK_LAN_CLOSED,
  102. "ShellLANEnteredFromGame", //SHELL_SCRIPT_HOOK_LAN_ENTERED_FROM_GAME,
  103. };
  104. void SignalUIInteraction(Int interaction)
  105. {
  106. if (TheScriptEngine)
  107. TheScriptEngine->signalUIInteract(TheShellHookNames[interaction]);
  108. }
  109. // Changing the order or meaning of either of these will require you to update the maps
  110. // in a meaningful way. If there are new entries, add them to the end, rather than the middle.
  111. const char *Surfaces[] = { "Ground", "Air", "Ground or Air", };
  112. const char *ShakeIntensities[] = { "Subtle", "Normal", "Strong", "Severe", "Cine_Extreme", "Cine_Insane" };
  113. enum { K_SCRIPT_LIST_DATA_VERSION_1 = 1,
  114. K_SCRIPT_GROUP_DATA_VERSION_1 = 1,
  115. K_SCRIPT_GROUP_DATA_VERSION_2 = 2,
  116. K_SCRIPT_DATA_VERSION_1 = 1,
  117. K_SCRIPT_DATA_VERSION_2 = 2,
  118. K_SCRIPT_OR_CONDITION_DATA_VERSION_1=1,
  119. K_SCRIPT_ACTION_VERSION_1 = 1,
  120. K_SCRIPT_ACTION_VERSION_2 = 2,
  121. K_SCRIPT_CONDITION_VERSION_1 = 1,
  122. K_SCRIPT_CONDITION_VERSION_2 = 2,
  123. K_SCRIPT_CONDITION_VERSION_3 = 3,
  124. K_SCRIPT_CONDITION_VERSION_4 = 4,
  125. K_SCRIPTS_DATA_VERSION_1,
  126. end_of_the_enumeration
  127. };
  128. static Condition::ConditionType ParameterChangesVer2[] =
  129. {
  130. // Seven Changed from version 1.
  131. Condition::TEAM_INSIDE_AREA_PARTIALLY,
  132. Condition::TEAM_INSIDE_AREA_ENTIRELY,
  133. Condition::TEAM_OUTSIDE_AREA_ENTIRELY,
  134. Condition::TEAM_ENTERED_AREA_PARTIALLY,
  135. Condition::TEAM_ENTERED_AREA_ENTIRELY,
  136. Condition::TEAM_EXITED_AREA_ENTIRELY,
  137. Condition::TEAM_EXITED_AREA_PARTIALLY,
  138. (Condition::ConditionType) -1,
  139. };
  140. enum { AT_END = 0x00FFFFFF };
  141. //-------------------------------------------------------------------------------------------------
  142. // ******************************** class ScriptList *********************************************
  143. //-------------------------------------------------------------------------------------------------
  144. // Statics ///////////////////////////////////////////////////////////////////////////////////////
  145. ScriptList *ScriptList::s_readLists[MAX_PLAYER_COUNT] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
  146. Int ScriptList::s_numInReadList = 0;
  147. Int ScriptList::m_curId = 0;
  148. /**
  149. ScriptList::updateDefaults - checks for empty script lists, and adds some default stuff
  150. so you don't get a totally blank screen in the editor.
  151. */
  152. void ScriptList::updateDefaults(void)
  153. {
  154. Int i;
  155. for (i=0; i<TheSidesList->getNumSides(); i++)
  156. {
  157. ScriptList* pList = TheSidesList->getSideInfo(i)->getScriptList();
  158. if (pList == NULL) {
  159. pList = newInstance(ScriptList);
  160. TheSidesList->getSideInfo(i)->setScriptList(pList);
  161. }
  162. }
  163. }
  164. /**
  165. Deletes any script lists attached to sides. Used for editor cleanup.
  166. */
  167. void ScriptList::reset(void)
  168. {
  169. Int i;
  170. if (TheSidesList == NULL) return; /// @todo - move this code into sides list.
  171. for (i=0; i<TheSidesList->getNumSides(); i++)
  172. {
  173. ScriptList* pList = TheSidesList->getSideInfo(i)->getScriptList();
  174. TheSidesList->getSideInfo(i)->setScriptList(NULL);
  175. pList->deleteInstance();
  176. }
  177. }
  178. /**
  179. Ctor.
  180. */
  181. ScriptList::ScriptList(void) :
  182. m_firstGroup(NULL),
  183. m_firstScript(NULL)
  184. {
  185. }
  186. /**
  187. Dtor. Deletes any script lists or group lists. Note that dtors for groups and script lists
  188. delete the whole list, so don't need to traverse here.
  189. */
  190. ScriptList::~ScriptList(void)
  191. {
  192. if (m_firstGroup) {
  193. m_firstGroup->deleteInstance();
  194. m_firstGroup = NULL;
  195. }
  196. if (m_firstScript) {
  197. m_firstScript->deleteInstance();
  198. m_firstScript = NULL;
  199. }
  200. }
  201. // ------------------------------------------------------------------------------------------------
  202. /** CRC */
  203. // ------------------------------------------------------------------------------------------------
  204. void ScriptList::crc( Xfer *xfer )
  205. {
  206. }
  207. // ------------------------------------------------------------------------------------------------
  208. /** Xfer method
  209. * Version Info:
  210. * 1: Initial version */
  211. // ------------------------------------------------------------------------------------------------
  212. void ScriptList::xfer( Xfer *xfer )
  213. {
  214. UnsignedShort countVerify;
  215. // version
  216. XferVersion currentVersion = 1;
  217. XferVersion version = currentVersion;
  218. xfer->xferVersion( &version, currentVersion );
  219. // count of scripts here
  220. Script *script;
  221. UnsignedShort scriptCount = 0;
  222. for( script = getScript(); script; script = script->getNext() )
  223. scriptCount++;
  224. countVerify = scriptCount;
  225. xfer->xferUnsignedShort( &scriptCount );
  226. if( countVerify != scriptCount )
  227. {
  228. DEBUG_CRASH(( "ScriptList::xfer - Script list count has changed, attempting to recover."));
  229. // throw SC_INVALID_DATA; try to recover. jba.
  230. } // end if
  231. // all script data here
  232. for( script = getScript(); script; script = script->getNext() ) {
  233. xfer->xferSnapshot( script );
  234. scriptCount--;
  235. if (scriptCount==0) break;
  236. }
  237. if (scriptCount>0) {
  238. DEBUG_CRASH(("Stripping out extra scripts - Bad..."));
  239. if (s_mtScript==NULL) s_mtScript = newInstance(Script); // Yes it leaks, but this is unusual recovery only. jba.
  240. while (scriptCount) {
  241. xfer->xferSnapshot(s_mtScript);
  242. scriptCount--;
  243. }
  244. }
  245. // count of script groups
  246. ScriptGroup *scriptGroup;
  247. UnsignedShort scriptGroupCount = 0;
  248. for( scriptGroup = getScriptGroup(); scriptGroup; scriptGroup = scriptGroup->getNext() )
  249. scriptGroupCount++;
  250. countVerify = scriptGroupCount;
  251. xfer->xferUnsignedShort( &scriptGroupCount );
  252. if( countVerify != scriptGroupCount )
  253. {
  254. DEBUG_CRASH(( "ScriptList::xfer - Script group count has changed, attempting to recover."));
  255. } // end if
  256. // all script group data
  257. for( scriptGroup = getScriptGroup(); scriptGroup; scriptGroup = scriptGroup->getNext() ) {
  258. xfer->xferSnapshot( scriptGroup );
  259. scriptGroupCount--;
  260. if (scriptGroupCount==0) break;
  261. }
  262. if (scriptGroupCount>0) {
  263. DEBUG_CRASH(("Stripping out extra groups. - Bad..."));
  264. if (s_mtGroup == NULL) s_mtGroup = newInstance(ScriptGroup); // Yes it leaks, but this is only for recovery.
  265. while (scriptGroupCount) {
  266. xfer->xferSnapshot(s_mtGroup);
  267. scriptGroupCount--;
  268. }
  269. }
  270. }
  271. // ------------------------------------------------------------------------------------------------
  272. /** Load post process */
  273. // ------------------------------------------------------------------------------------------------
  274. void ScriptList::loadPostProcess( void )
  275. {
  276. }
  277. /**
  278. ScriptList::duplicate - Creates a full, "deep" copy of scriptlist.
  279. */
  280. ScriptList *ScriptList::duplicate(void) const
  281. {
  282. ScriptList *pNew = newInstance(ScriptList);
  283. {
  284. const ScriptGroup *src = this->m_firstGroup;
  285. ScriptGroup *dst = NULL;
  286. while (src)
  287. {
  288. ScriptGroup *tmp = src->duplicate();
  289. if (dst)
  290. dst->setNextGroup(tmp);
  291. else
  292. pNew->m_firstGroup = tmp;
  293. src = src->getNext();
  294. dst = tmp;
  295. }
  296. }
  297. {
  298. const Script *src = this->m_firstScript;
  299. Script *dst = NULL;
  300. while (src)
  301. {
  302. Script *tmp = src->duplicate();
  303. if (dst)
  304. dst->setNextScript(tmp);
  305. else
  306. pNew->m_firstScript = tmp;
  307. src = src->getNext();
  308. dst = tmp;
  309. }
  310. }
  311. return pNew;
  312. }
  313. /**
  314. ScriptList::duplicateAndQualify - Creates a full, "deep" copy of scriptlist,
  315. adding the qualifier to names.
  316. */
  317. ScriptList *ScriptList::duplicateAndQualify(const AsciiString& qualifier,
  318. const AsciiString& playerTemplateName, const AsciiString& newPlayerName) const
  319. {
  320. ScriptList *pNew = newInstance(ScriptList);
  321. {
  322. const ScriptGroup *src = this->m_firstGroup;
  323. ScriptGroup *dst = NULL;
  324. while (src)
  325. {
  326. ScriptGroup *tmp = src->duplicateAndQualify( qualifier, playerTemplateName, newPlayerName);
  327. if (dst)
  328. dst->setNextGroup(tmp);
  329. else
  330. pNew->m_firstGroup = tmp;
  331. src = src->getNext();
  332. dst = tmp;
  333. }
  334. }
  335. {
  336. const Script *src = this->m_firstScript;
  337. Script *dst = NULL;
  338. while (src)
  339. {
  340. Script *tmp = src->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  341. if (dst)
  342. dst->setNextScript(tmp);
  343. else
  344. pNew->m_firstScript = tmp;
  345. src = src->getNext();
  346. dst = tmp;
  347. }
  348. }
  349. return pNew;
  350. }
  351. /**
  352. ScriptList::discard - Deletes a script list, but not any children.
  353. */
  354. void ScriptList::discard(void)
  355. {
  356. m_firstGroup = NULL;
  357. m_firstScript = NULL;
  358. this->deleteInstance();
  359. }
  360. /**
  361. Add a script group to the current list of groups. Offset to position ndx.
  362. */
  363. void ScriptList::addGroup(ScriptGroup *pGrp, Int ndx)
  364. {
  365. ScriptGroup *pPrev = NULL;
  366. ScriptGroup *pCur = m_firstGroup;
  367. DEBUG_ASSERTCRASH(pGrp->getNext()==NULL, ("Adding already linked group."));
  368. while (ndx && pCur) {
  369. pPrev = pCur;
  370. pCur = pCur->getNext();
  371. ndx--;
  372. }
  373. if (pPrev) {
  374. // Weave into prev link.
  375. pGrp->setNextGroup(pPrev->getNext());
  376. pPrev->setNextGroup(pGrp);
  377. } else {
  378. // Goes at head of list.
  379. pGrp->setNextGroup(m_firstGroup);
  380. m_firstGroup = pGrp;
  381. }
  382. }
  383. /**
  384. Add a script to the current list of scripts. Offset to position ndx.
  385. */
  386. void ScriptList::addScript(Script *pScr, Int ndx)
  387. {
  388. Script *pPrev = NULL;
  389. Script *pCur = m_firstScript;
  390. DEBUG_ASSERTCRASH(pScr->getNext()==NULL, ("Adding already linked group."));
  391. while (ndx && pCur) {
  392. pPrev = pCur;
  393. pCur = pCur->getNext();
  394. ndx--;
  395. }
  396. if (pPrev) {
  397. pScr->setNextScript(pPrev->getNext());
  398. pPrev->setNextScript(pScr);
  399. } else {
  400. pScr->setNextScript(m_firstScript);
  401. m_firstScript = pScr;
  402. }
  403. }
  404. /**
  405. Delete a script from the current list of scripts.
  406. */
  407. void ScriptList::deleteScript(Script *pScr)
  408. {
  409. Script *pPrev = NULL;
  410. Script *pCur = m_firstScript;
  411. while (pCur != pScr) {
  412. pPrev = pCur;
  413. pCur = pCur->getNext();
  414. }
  415. DEBUG_ASSERTCRASH(pCur, ("Couldn't find script."));
  416. if (pCur==NULL) return;
  417. if (pPrev) {
  418. // unlink from previous script.
  419. pPrev->setNextScript(pCur->getNext());
  420. } else {
  421. // Unlink from head of list.
  422. m_firstScript = pCur->getNext();
  423. }
  424. // Clear the link & delete.
  425. pCur->setNextScript(NULL);
  426. pCur->deleteInstance();
  427. }
  428. /**
  429. Delete a group from the current list of groups.
  430. */
  431. void ScriptList::deleteGroup(ScriptGroup *pGrp)
  432. {
  433. ScriptGroup *pPrev = NULL;
  434. ScriptGroup *pCur = m_firstGroup;
  435. while (pCur != pGrp) {
  436. pPrev = pCur;
  437. pCur = pCur->getNext();
  438. }
  439. DEBUG_ASSERTCRASH(pCur, ("Couldn't find group."));
  440. if (pCur==NULL) return;
  441. if (pPrev) {
  442. // unlink from previous group.
  443. pPrev->setNextGroup(pCur->getNext());
  444. } else {
  445. // Unlink from head of list.
  446. m_firstGroup = pCur->getNext();
  447. }
  448. // Clear the link & delete.
  449. pCur->setNextGroup(NULL);
  450. pCur->deleteInstance();
  451. }
  452. /**
  453. * ScriptList::ParseScriptsDataChunk - read a Scripts chunk.
  454. * Format is the newer CHUNKY format.
  455. * See ScriptList::ScriptList for the writer.
  456. * Input: DataChunkInput
  457. *
  458. */
  459. Bool ScriptList::ParseScriptsDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  460. {
  461. Int i;
  462. file.registerParser( AsciiString("ScriptList"), info->label, ScriptList::ParseScriptListDataChunk );
  463. DEBUG_ASSERTCRASH(s_numInReadList==0, ("Leftover scripts floating aroung."));
  464. for (i=0; i<s_numInReadList; i++) {
  465. if (s_readLists[i]) {
  466. s_readLists[i]->deleteInstance();
  467. s_readLists[i] = NULL;
  468. }
  469. }
  470. TScriptListReadInfo readInfo;
  471. for (i=0; i<MAX_PLAYER_COUNT; i++) {
  472. readInfo.readLists[i] = 0;
  473. }
  474. readInfo.numLists = 0;
  475. if (file.parse(&readInfo)) {
  476. DEBUG_ASSERTCRASH(readInfo.numLists<MAX_PLAYER_COUNT, ("Read too many, overrun buffer."));
  477. s_numInReadList = readInfo.numLists;
  478. for (i=0; i<s_numInReadList; i++) {
  479. s_readLists[i] = readInfo.readLists[i];
  480. }
  481. return true;
  482. }
  483. return false;
  484. }
  485. /**
  486. * ScriptList::getReadScripts - Gets the scripts read in from a file by .
  487. * ScriptList::ParseScriptsDataChunk.
  488. *
  489. */
  490. Int ScriptList::getReadScripts(ScriptList *scriptLists[MAX_PLAYER_COUNT])
  491. {
  492. Int i;
  493. Int count = s_numInReadList;
  494. s_numInReadList = 0;
  495. for (i=0; i<count; i++) {
  496. scriptLists[i] = s_readLists[i];
  497. s_readLists[i] = NULL;
  498. }
  499. return count;
  500. }
  501. /**
  502. * ScriptList::WriteScriptsDataChunk - Writes a Scripts chunk.
  503. * Format is the newer CHUNKY format.
  504. * See ScriptEngine::ParseScriptsDataChunk for the reader.
  505. * Input: DataChunkInput
  506. *
  507. */
  508. void ScriptList::WriteScriptsDataChunk(DataChunkOutput &chunkWriter, ScriptList *scriptLists[], Int numLists )
  509. {
  510. /**********SCRIPTS DATA ***********************/
  511. chunkWriter.openDataChunk("PlayerScriptsList", K_SCRIPTS_DATA_VERSION_1);
  512. Int i;
  513. for (i=0; i<numLists; i++) {
  514. chunkWriter.openDataChunk("ScriptList", K_SCRIPT_LIST_DATA_VERSION_1);
  515. if (scriptLists[i]) scriptLists[i]->WriteScriptListDataChunk(chunkWriter);
  516. chunkWriter.closeDataChunk();
  517. }
  518. chunkWriter.closeDataChunk();
  519. }
  520. /**
  521. * ScriptList::WriteScriptListDataChunk - Writes a Scripts chunk.
  522. * Format is the newer CHUNKY format.
  523. * Input: DataChunkInput
  524. *
  525. */
  526. void ScriptList::WriteScriptListDataChunk(DataChunkOutput &chunkWriter)
  527. {
  528. /**********SCRIPTS DATA ***********************/
  529. if (m_firstScript) m_firstScript->WriteScriptDataChunk(chunkWriter, m_firstScript);
  530. if (m_firstGroup) m_firstGroup->WriteGroupDataChunk(chunkWriter, m_firstGroup);
  531. }
  532. /**
  533. * ScriptList::ParseScriptListDataChunk - read a Scripts chunk.
  534. * Format is the newer CHUNKY format.
  535. * See ScriptList::WriteScriptListDataChunk for the writer.
  536. * Input: DataChunkInput
  537. *
  538. */
  539. Bool ScriptList::ParseScriptListDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  540. {
  541. TScriptListReadInfo *pInfo = (TScriptListReadInfo*)userData;
  542. DEBUG_ASSERTCRASH(pInfo->numLists < MAX_PLAYER_COUNT, ("Too many."));
  543. if (pInfo->numLists >= MAX_PLAYER_COUNT) return false;
  544. pInfo->readLists[pInfo->numLists] = newInstance(ScriptList);
  545. Int cur = pInfo->numLists;
  546. pInfo->numLists++;
  547. file.registerParser( AsciiString("Script"), info->label, Script::ParseScriptFromListDataChunk );
  548. file.registerParser( AsciiString("ScriptGroup"), info->label, ScriptGroup::ParseGroupDataChunk );
  549. return file.parse(pInfo->readLists[cur]);
  550. }
  551. //-------------------------------------------------------------------------------------------------
  552. // ******************************** class ScriptGroup *********************************************
  553. //-------------------------------------------------------------------------------------------------
  554. /**
  555. Ctor - gives it a default name.
  556. */
  557. ScriptGroup::ScriptGroup(void) :
  558. m_firstScript(NULL),
  559. m_hasWarnings(false),
  560. m_isGroupActive(true),
  561. m_isGroupSubroutine(false),
  562. //Added By Sadullah Nader
  563. //Initializations inserted
  564. m_nextGroup(NULL)
  565. //
  566. {
  567. m_groupName.format("Script Group %d", ScriptList::getNextID());
  568. }
  569. /**
  570. Dtor - The script list deletes the rest of the list, but we have to loop & delete
  571. sll the script groups in out list.
  572. */
  573. ScriptGroup::~ScriptGroup(void)
  574. {
  575. if (m_firstScript) {
  576. // Delete the first script. m_firstScript deletes the entire list.
  577. m_firstScript->deleteInstance();
  578. m_firstScript = NULL;
  579. }
  580. if (m_nextGroup) {
  581. // Delete all the subsequent groups in our list.
  582. ScriptGroup *cur = m_nextGroup;
  583. ScriptGroup *next;
  584. while (cur) {
  585. next = cur->getNext();
  586. cur->setNextGroup(NULL); // prevents recursion.
  587. cur->deleteInstance();
  588. cur = next;
  589. }
  590. }
  591. }
  592. // ------------------------------------------------------------------------------------------------
  593. /** CRC */
  594. // ------------------------------------------------------------------------------------------------
  595. void ScriptGroup::crc( Xfer *xfer )
  596. {
  597. } // end crc
  598. // ------------------------------------------------------------------------------------------------
  599. /** Xfer method
  600. * Version Info:
  601. * 1: Initial version
  602. * 2: m_isGroupActive, since it is twiddled by other scripts. Only its initial state is determined by the map.
  603. */
  604. // ------------------------------------------------------------------------------------------------
  605. void ScriptGroup::xfer( Xfer *xfer )
  606. {
  607. // version
  608. XferVersion currentVersion = 2;
  609. XferVersion version = currentVersion;
  610. xfer->xferVersion( &version, currentVersion );
  611. if( version >= 2 )
  612. xfer->xferBool(&m_isGroupActive);
  613. // count of scripts here
  614. UnsignedShort scriptCount = 0;
  615. Script *script;
  616. for( script = getScript(); script; script = script->getNext() )
  617. scriptCount++;
  618. UnsignedShort countVerify = scriptCount;
  619. xfer->xferUnsignedShort( &scriptCount );
  620. if( countVerify != scriptCount )
  621. {
  622. DEBUG_CRASH(( "ScriptGroup::xfer - Script list count has changed, attempting to recover."));
  623. // throw SC_INVALID_DATA; try to recover. jba.
  624. } // end if
  625. // xfer script data
  626. for( script = getScript(); script; script = script->getNext() ) {
  627. xfer->xferSnapshot( script );
  628. scriptCount--;
  629. if (scriptCount==0) break;
  630. }
  631. if (scriptCount>0) {
  632. DEBUG_CRASH(("Stripping out extra scripts - Bad..."));
  633. if (s_mtScript==NULL) s_mtScript = newInstance(Script); // Yes it leaks, but this is unusual recovery only. jba.
  634. while (scriptCount) {
  635. xfer->xferSnapshot(s_mtScript);
  636. scriptCount--;
  637. }
  638. }
  639. } // end xfer
  640. // ------------------------------------------------------------------------------------------------
  641. /** Load post process */
  642. // ------------------------------------------------------------------------------------------------
  643. void ScriptGroup::loadPostProcess( void )
  644. {
  645. } // end loadPostProcess
  646. /**
  647. ScriptGroup::duplicate - Creates a full, "deep" copy of ScriptGroup.
  648. m_nextGroup is NULL on the copy.
  649. */
  650. ScriptGroup *ScriptGroup::duplicate(void) const
  651. {
  652. ScriptGroup *pNew = newInstance(ScriptGroup);
  653. {
  654. Script *src = this->m_firstScript;
  655. Script *dst = NULL;
  656. while (src)
  657. {
  658. Script *tmp = src->duplicate();
  659. if (dst)
  660. dst->setNextScript(tmp);
  661. else
  662. pNew->m_firstScript = tmp;
  663. src = src->getNext();
  664. dst = tmp;
  665. }
  666. }
  667. pNew->m_groupName = this->m_groupName;
  668. pNew->m_isGroupActive = this->m_isGroupActive;
  669. pNew->m_isGroupSubroutine = this->m_isGroupSubroutine;
  670. pNew->m_nextGroup = NULL;
  671. return pNew;
  672. }
  673. /**
  674. ScriptGroup::duplicateAndQualify - Creates a full, "deep" copy of ScriptGroup,
  675. adding qualifier to names.
  676. m_nextGroup is NULL on the copy.
  677. */
  678. ScriptGroup *ScriptGroup::duplicateAndQualify(const AsciiString& qualifier,
  679. const AsciiString& playerTemplateName, const AsciiString& newPlayerName) const
  680. {
  681. ScriptGroup *pNew = newInstance(ScriptGroup);
  682. {
  683. Script *src = this->m_firstScript;
  684. Script *dst = NULL;
  685. while (src)
  686. {
  687. Script *tmp = src->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  688. if (dst)
  689. dst->setNextScript(tmp);
  690. else
  691. pNew->m_firstScript = tmp;
  692. src = src->getNext();
  693. dst = tmp;
  694. }
  695. }
  696. pNew->m_groupName = this->m_groupName;
  697. pNew->m_groupName.concat(qualifier);
  698. pNew->m_isGroupActive = this->m_isGroupActive;
  699. pNew->m_isGroupSubroutine = this->m_isGroupSubroutine;
  700. pNew->m_nextGroup = NULL;
  701. return pNew;
  702. }
  703. /**
  704. Delete a script from the current list of scripts.
  705. */
  706. void ScriptGroup::deleteScript(Script *pScr)
  707. {
  708. Script *pPrev = NULL;
  709. Script *pCur = m_firstScript;
  710. while (pScr != pCur) {
  711. pPrev = pCur;
  712. pCur = pCur->getNext();
  713. }
  714. DEBUG_ASSERTCRASH(pCur, ("Couldn't find script."));
  715. if (pCur==NULL) return;
  716. if (pPrev) {
  717. pPrev->setNextScript(pCur->getNext());
  718. } else {
  719. m_firstScript = pCur->getNext();
  720. }
  721. // Clear link & delete.
  722. pCur->setNextScript(NULL);
  723. pCur->deleteInstance();
  724. }
  725. /**
  726. Add a script to the current list of scripts. Offset to position ndx.
  727. */
  728. void ScriptGroup::addScript(Script *pScr, Int ndx)
  729. {
  730. Script *pPrev = NULL;
  731. Script *pCur = m_firstScript;
  732. DEBUG_ASSERTCRASH(pScr->getNext()==NULL, ("Adding already linked group."));
  733. while (ndx && pCur) {
  734. pPrev = pCur;
  735. pCur = pCur->getNext();
  736. ndx--;
  737. }
  738. if (pPrev) {
  739. // link to pPrev
  740. pScr->setNextScript(pPrev->getNext());
  741. pPrev->setNextScript(pScr);
  742. } else {
  743. // add to head of list.
  744. pScr->setNextScript(m_firstScript);
  745. m_firstScript = pScr;
  746. }
  747. }
  748. /**
  749. * ScriptGroup::WriteGroupDataChunk - Writes a Scripts chunk.
  750. * Format is the newer CHUNKY format.
  751. * Input: DataChunkInput
  752. *
  753. */
  754. void ScriptGroup::WriteGroupDataChunk(DataChunkOutput &chunkWriter, ScriptGroup *pGroup)
  755. {
  756. /**********SCRIPT GROUP DATA ***********************/
  757. while (pGroup) {
  758. chunkWriter.openDataChunk("ScriptGroup", K_SCRIPT_GROUP_DATA_VERSION_2);
  759. chunkWriter.writeAsciiString(pGroup->m_groupName);
  760. chunkWriter.writeByte(pGroup->m_isGroupActive);
  761. chunkWriter.writeByte(pGroup->m_isGroupSubroutine);
  762. if (pGroup->m_firstScript) Script::WriteScriptDataChunk(chunkWriter, pGroup->m_firstScript);
  763. chunkWriter.closeDataChunk();
  764. pGroup = pGroup->getNext();
  765. }
  766. }
  767. /**
  768. * ScriptGroup::ParseGroupDataChunk - read a Group chunk.
  769. * Format is the newer CHUNKY format.
  770. * See ScriptList::WriteScriptListDataChunk for the writer.
  771. * Input: DataChunkInput
  772. *
  773. */
  774. Bool ScriptGroup::ParseGroupDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  775. {
  776. ScriptList *pList = (ScriptList *)userData;
  777. ScriptGroup *pGroup = newInstance(ScriptGroup);
  778. pGroup->m_groupName = file.readAsciiString();
  779. pGroup->m_isGroupActive = file.readByte();
  780. if (info->version == K_SCRIPT_GROUP_DATA_VERSION_2) {
  781. pGroup->m_isGroupSubroutine= file.readByte();
  782. }
  783. pList->addGroup(pGroup, AT_END);
  784. file.registerParser( AsciiString("Script"), info->label, Script::ParseScriptFromGroupDataChunk );
  785. return file.parse(pGroup);
  786. }
  787. //-------------------------------------------------------------------------------------------------
  788. // ******************************** class Script *********************************************
  789. //-------------------------------------------------------------------------------------------------
  790. /**
  791. Ctor - initializes members.
  792. */
  793. Script::Script(void) :
  794. m_isActive(true),
  795. m_isOneShot(true),
  796. m_easy(true),
  797. m_normal(true),
  798. m_hard(true),
  799. m_delayEvaluationSeconds(0),
  800. m_conditionTime(0),
  801. m_conditionExecutedCount(0),
  802. m_frameToEvaluateAt(0),
  803. m_isSubroutine(false),
  804. m_hasWarnings(false),
  805. m_nextScript(NULL),
  806. m_condition(NULL),
  807. m_action(NULL),
  808. //Added By Sadullah Nader
  809. //Initializations inserted
  810. m_actionFalse(NULL),
  811. m_curTime(0.0f)
  812. //
  813. {
  814. }
  815. /**
  816. Dtor - The condition and action deletes the rest of the list, but we have to loop & delete
  817. all the scripts in out list.
  818. */
  819. Script::~Script(void)
  820. {
  821. if (m_nextScript) {
  822. Script *cur = m_nextScript;
  823. Script *next;
  824. while (cur) {
  825. next = cur->getNext();
  826. cur->setNextScript(NULL); // prevents recursion.
  827. cur->deleteInstance();
  828. cur = next;
  829. }
  830. }
  831. if (m_condition) {
  832. m_condition->deleteInstance();
  833. }
  834. if (m_action) {
  835. m_action->deleteInstance();
  836. }
  837. if (m_actionFalse) {
  838. m_actionFalse->deleteInstance();
  839. }
  840. }
  841. // ------------------------------------------------------------------------------------------------
  842. /** CRC */
  843. // ------------------------------------------------------------------------------------------------
  844. void Script::crc( Xfer *xfer )
  845. {
  846. } // end crc
  847. // ------------------------------------------------------------------------------------------------
  848. /** Xfer method
  849. * Version Info:
  850. * 1: Initial version */
  851. // ------------------------------------------------------------------------------------------------
  852. void Script::xfer( Xfer *xfer )
  853. {
  854. // version
  855. XferVersion currentVersion = 1;
  856. XferVersion version = currentVersion;
  857. xfer->xferVersion( &version, currentVersion );
  858. // active
  859. Bool active = isActive();
  860. xfer->xferBool( &active );
  861. setActive( active );
  862. } // end xfer
  863. // ------------------------------------------------------------------------------------------------
  864. /** Load post process */
  865. // ------------------------------------------------------------------------------------------------
  866. void Script::loadPostProcess( void )
  867. {
  868. } // end loadPostProcess
  869. /**
  870. Script::duplicate - Creates a full, "deep" copy of script. Condition list and action
  871. list is duplicated as well. Note - just the script, doesn't
  872. duplicate a list of scripts. m_nextScript is NULL on the copy.
  873. */
  874. Script *Script::duplicate(void) const
  875. {
  876. Script *pNew = newInstance(Script);
  877. if (pNew->m_condition) {
  878. pNew->m_condition->deleteInstance();
  879. }
  880. if (pNew->m_action) {
  881. pNew->m_action->deleteInstance();
  882. }
  883. pNew->m_scriptName = m_scriptName;
  884. pNew->m_comment = m_comment;
  885. pNew->m_conditionComment = m_conditionComment;
  886. pNew->m_actionComment = m_actionComment;
  887. pNew->m_isActive = m_isActive;
  888. pNew->m_isOneShot = m_isOneShot;
  889. pNew->m_isSubroutine = m_isSubroutine;
  890. pNew->m_easy = m_easy;
  891. pNew->m_normal = m_normal;
  892. pNew->m_hard = m_hard;
  893. pNew->m_delayEvaluationSeconds = m_delayEvaluationSeconds;
  894. if (m_condition) {
  895. pNew->m_condition = m_condition->duplicate();
  896. }
  897. if (m_action) {
  898. pNew->m_action = m_action->duplicate();
  899. }
  900. if (m_actionFalse) {
  901. pNew->m_actionFalse = m_actionFalse->duplicate();
  902. }
  903. return pNew;
  904. }
  905. /**
  906. Script::duplicate - Creates a full, "deep" copy of script, with qualifier
  907. added to names. Condition list and action
  908. list is duplicated as well. Note - just the script, doesn't
  909. duplicate a list of scripts. m_nextScript is NULL on the copy.
  910. */
  911. Script *Script::duplicateAndQualify(const AsciiString& qualifier,
  912. const AsciiString& playerTemplateName, const AsciiString& newPlayerName) const
  913. {
  914. Script *pNew = newInstance(Script);
  915. if (pNew->m_condition) {
  916. pNew->m_condition->deleteInstance();
  917. }
  918. if (pNew->m_action) {
  919. pNew->m_action->deleteInstance();
  920. }
  921. pNew->m_scriptName = m_scriptName;
  922. pNew->m_scriptName.concat(qualifier);
  923. pNew->m_comment = m_comment;
  924. pNew->m_conditionComment = m_conditionComment;
  925. pNew->m_actionComment = m_actionComment;
  926. pNew->m_isActive = m_isActive;
  927. pNew->m_isOneShot = m_isOneShot;
  928. pNew->m_isSubroutine = m_isSubroutine;
  929. pNew->m_easy = m_easy;
  930. pNew->m_normal = m_normal;
  931. pNew->m_hard = m_hard;
  932. pNew->m_delayEvaluationSeconds = m_delayEvaluationSeconds;
  933. if (m_condition) {
  934. pNew->m_condition = m_condition->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  935. }
  936. if (m_action) {
  937. pNew->m_action = m_action->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  938. }
  939. if (m_actionFalse) {
  940. pNew->m_actionFalse = m_actionFalse->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  941. }
  942. return pNew;
  943. }
  944. /**
  945. Script::updateFrom - Copies all the data from pSrc into this. Any data in this
  946. is deleted (conditions, actions). Note that this guts pSrc, and removes it's conditions
  947. and actions. Intended for use in an edit dialog, where pSrc is a copy edited, and if cancelled
  948. discarded, and if not cancelled, updated into the real script, then discarded.
  949. */
  950. void Script::updateFrom(Script *pSrc)
  951. {
  952. this->m_scriptName = pSrc->m_scriptName;
  953. this->m_comment = pSrc->m_comment;
  954. this->m_conditionComment = pSrc->m_conditionComment;
  955. this->m_actionComment = pSrc->m_actionComment;
  956. this->m_isActive = pSrc->m_isActive;
  957. this->m_isSubroutine = pSrc->m_isSubroutine;
  958. this->m_delayEvaluationSeconds = pSrc->m_delayEvaluationSeconds;
  959. this->m_isOneShot = pSrc->m_isOneShot;
  960. this->m_easy = pSrc->m_easy;
  961. this->m_normal = pSrc->m_normal;
  962. this->m_hard = pSrc->m_hard;
  963. if (this->m_condition) {
  964. this->m_condition->deleteInstance();
  965. }
  966. this->m_condition = pSrc->m_condition;
  967. pSrc->m_condition = NULL;
  968. if (this->m_action) {
  969. this->m_action->deleteInstance();
  970. }
  971. this->m_action = pSrc->m_action;
  972. pSrc->m_action = NULL;
  973. if (this->m_actionFalse) {
  974. this->m_actionFalse->deleteInstance();
  975. }
  976. this->m_actionFalse = pSrc->m_actionFalse;
  977. pSrc->m_actionFalse = NULL;
  978. }
  979. /**
  980. Script::deleteOrCondition - delete pCond from the or condition list.
  981. */
  982. void Script::deleteOrCondition(OrCondition *pCond)
  983. {
  984. OrCondition *pPrev = NULL;
  985. OrCondition *pCur = m_condition;
  986. while (pCond != pCur) {
  987. pPrev = pCur;
  988. pCur = pCur->getNextOrCondition();
  989. }
  990. DEBUG_ASSERTCRASH(pCur, ("Couldn't find condition."));
  991. if (pCur==NULL) return;
  992. if (pPrev) {
  993. pPrev->setNextOrCondition(pCur->getNextOrCondition());
  994. } else {
  995. m_condition = pCur->getNextOrCondition();
  996. }
  997. pCur->setNextOrCondition(NULL);
  998. pCur->deleteInstance();
  999. }
  1000. /**
  1001. Script::deleteAction - delete pAct from the action list.
  1002. */
  1003. void Script::deleteAction(ScriptAction *pAct)
  1004. {
  1005. ScriptAction *pPrev = NULL;
  1006. ScriptAction *pCur = m_action;
  1007. while (pAct != pCur) {
  1008. pPrev = pCur;
  1009. pCur = pCur->getNext();
  1010. }
  1011. DEBUG_ASSERTCRASH(pCur, ("Couldn't find action."));
  1012. if (pCur==NULL) return;
  1013. if (pPrev) {
  1014. pPrev->setNextAction(pCur->getNext());
  1015. } else {
  1016. m_action = pCur->getNext();
  1017. }
  1018. pCur->setNextAction(NULL);
  1019. pCur->deleteInstance();
  1020. }
  1021. /**
  1022. Script::deleteFalseAction - delete pAct from the false action list.
  1023. */
  1024. void Script::deleteFalseAction(ScriptAction *pAct)
  1025. {
  1026. ScriptAction *pPrev = NULL;
  1027. ScriptAction *pCur = m_actionFalse;
  1028. while (pAct != pCur) {
  1029. pPrev = pCur;
  1030. pCur = pCur->getNext();
  1031. }
  1032. DEBUG_ASSERTCRASH(pCur, ("Couldn't find action."));
  1033. if (pCur==NULL) return;
  1034. if (pPrev) {
  1035. pPrev->setNextAction(pCur->getNext());
  1036. } else {
  1037. m_actionFalse = pCur->getNext();
  1038. }
  1039. pCur->setNextAction(NULL);
  1040. pCur->deleteInstance();
  1041. }
  1042. /**
  1043. Script::getUiText - Creates the string to display in the scripts dialog box.
  1044. */
  1045. AsciiString Script::getUiText(void)
  1046. {
  1047. AsciiString uiText("*** IF ***\r\n");
  1048. OrCondition *pOr = m_condition;
  1049. Int count=0;
  1050. while (pOr) {
  1051. Condition *pCond = pOr->getFirstAndCondition();
  1052. if (count>0) uiText.concat(" *** OR ***\r\n");
  1053. count = 0;
  1054. while (pCond) {
  1055. if (count>0) {
  1056. uiText.concat(" *AND* ");
  1057. } else {
  1058. uiText.concat(" ");
  1059. }
  1060. uiText.concat(pCond->getUiText());
  1061. uiText.concat("\r\n");
  1062. pCond = pCond->getNext();
  1063. count++;
  1064. }
  1065. pOr = pOr->getNextOrCondition();
  1066. }
  1067. uiText.concat("*** THEN ***\r\n");
  1068. ScriptAction *pAction = m_action;
  1069. while (pAction) {
  1070. uiText.concat(" ");
  1071. uiText.concat(pAction->getUiText());
  1072. uiText.concat("\r\n");
  1073. pAction = pAction->getNext();
  1074. }
  1075. pAction = m_actionFalse;
  1076. if (pAction) {
  1077. uiText.concat("*** ELSE ***\r\n");
  1078. while (pAction) {
  1079. uiText.concat(" ");
  1080. uiText.concat(pAction->getUiText());
  1081. uiText.concat("\r\n");
  1082. pAction = pAction->getNext();
  1083. }
  1084. }
  1085. return uiText;
  1086. }
  1087. /**
  1088. * Script::WriteScriptDataChunk - Writes a Scripts chunk.
  1089. * Format is the newer CHUNKY format.
  1090. * Input: DataChunkInput
  1091. *
  1092. */
  1093. void Script::WriteScriptDataChunk(DataChunkOutput &chunkWriter, Script *pScript)
  1094. {
  1095. /**********SCRIPT DATA ***********************/
  1096. while (pScript) {
  1097. chunkWriter.openDataChunk("Script", K_SCRIPT_DATA_VERSION_2);
  1098. chunkWriter.writeAsciiString(pScript->m_scriptName);
  1099. chunkWriter.writeAsciiString(pScript->m_comment);
  1100. chunkWriter.writeAsciiString(pScript->m_conditionComment);
  1101. chunkWriter.writeAsciiString(pScript->m_actionComment);
  1102. chunkWriter.writeByte(pScript->m_isActive);
  1103. chunkWriter.writeByte(pScript->m_isOneShot);
  1104. chunkWriter.writeByte(pScript->m_easy);
  1105. chunkWriter.writeByte(pScript->m_normal);
  1106. chunkWriter.writeByte(pScript->m_hard);
  1107. chunkWriter.writeByte(pScript->m_isSubroutine);
  1108. chunkWriter.writeInt(pScript->m_delayEvaluationSeconds);
  1109. if (pScript->m_condition) OrCondition::WriteOrConditionDataChunk(chunkWriter, pScript->m_condition);
  1110. if (pScript->m_action) ScriptAction::WriteActionDataChunk(chunkWriter, pScript->m_action);
  1111. if (pScript->m_actionFalse) ScriptAction::WriteActionFalseDataChunk(chunkWriter, pScript->m_actionFalse);
  1112. chunkWriter.closeDataChunk();
  1113. pScript = pScript->getNext();
  1114. }
  1115. }
  1116. /**
  1117. * Script::ParseScript - read a script chunk.
  1118. * Format is the newer CHUNKY format.
  1119. * See ScriptList::WriteScriptDataChunk for the writer.
  1120. * Input: DataChunkInput
  1121. *
  1122. */
  1123. Script *Script::ParseScript(DataChunkInput &file, unsigned short version)
  1124. {
  1125. Script *pScript = newInstance(Script);
  1126. pScript->m_scriptName = file.readAsciiString();
  1127. pScript->m_comment = file.readAsciiString();
  1128. pScript->m_conditionComment = file.readAsciiString();
  1129. pScript->m_actionComment = file.readAsciiString();
  1130. pScript->m_isActive = file.readByte();
  1131. pScript->m_isOneShot = file.readByte();
  1132. pScript->m_easy = file.readByte();
  1133. pScript->m_normal = file.readByte();
  1134. pScript->m_hard = file.readByte();
  1135. pScript->m_isSubroutine = file.readByte();
  1136. if (version>=K_SCRIPT_DATA_VERSION_2) {
  1137. pScript->m_delayEvaluationSeconds = file.readInt();
  1138. }
  1139. file.registerParser( AsciiString("OrCondition"), AsciiString("Script"), OrCondition::ParseOrConditionDataChunk );
  1140. file.registerParser( AsciiString("ScriptAction"), AsciiString("Script"), ScriptAction::ParseActionDataChunk );
  1141. file.registerParser( AsciiString("ScriptActionFalse"), AsciiString("Script"), ScriptAction::ParseActionFalseDataChunk );
  1142. if (! file.parse(pScript) )
  1143. {
  1144. return NULL;
  1145. }
  1146. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  1147. return pScript;
  1148. }
  1149. /**
  1150. * Script::ParseScriptFromListDataChunk - read a script chunk in a script list.
  1151. * Format is the newer CHUNKY format.
  1152. * See ScriptList::WriteScriptListDataChunk for the writer.
  1153. * Input: DataChunkInput
  1154. *
  1155. */
  1156. Bool Script::ParseScriptFromListDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  1157. {
  1158. ScriptList *pList = (ScriptList *)userData;
  1159. Script *pScript = ParseScript(file, info->version);
  1160. pList->addScript(pScript, AT_END);
  1161. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  1162. return true;
  1163. }
  1164. /**
  1165. * Script::ParseScriptFromGroupDataChunk - read a script chunk in a script group.
  1166. * Format is the newer CHUNKY format.
  1167. * See ScriptList::WriteScriptListDataChunk for the writer.
  1168. * Input: DataChunkInput
  1169. *
  1170. */
  1171. Bool Script::ParseScriptFromGroupDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  1172. {
  1173. ScriptGroup *pGroup = (ScriptGroup *)userData;
  1174. Script *pScript = ParseScript(file, info->version);
  1175. pGroup->addScript(pScript, AT_END);
  1176. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  1177. return true;
  1178. }
  1179. /**
  1180. * Script::findPreviousOrCondition - find the OrCondition that immediately proceeds curOr.
  1181. * Input: OrCondition
  1182. *
  1183. */
  1184. OrCondition *Script::findPreviousOrCondition( OrCondition *curOr )
  1185. {
  1186. OrCondition *myConditions = getOrCondition();
  1187. if ( myConditions == curOr ) {
  1188. return NULL;
  1189. }
  1190. while (myConditions) {
  1191. if (myConditions->getNextOrCondition() == curOr) {
  1192. return myConditions;
  1193. }
  1194. myConditions = myConditions->getNextOrCondition();
  1195. }
  1196. DEBUG_CRASH(("Tried to find an OrCondition that doesn't seem to exist (jkmcd)"));
  1197. return NULL;
  1198. }
  1199. //-------------------------------------------------------------------------------------------------
  1200. // ******************************** class OrCondition *********************************************
  1201. //-------------------------------------------------------------------------------------------------
  1202. OrCondition::~OrCondition(void)
  1203. {
  1204. if (m_firstAnd) {
  1205. m_firstAnd->deleteInstance();
  1206. m_firstAnd = NULL;
  1207. }
  1208. if (m_nextOr) {
  1209. OrCondition *cur = m_nextOr;
  1210. OrCondition *next;
  1211. while (cur) {
  1212. next = cur->getNextOrCondition();
  1213. cur->setNextOrCondition(NULL); // prevents recursion.
  1214. cur->deleteInstance();
  1215. cur = next;
  1216. }
  1217. }
  1218. }
  1219. OrCondition *OrCondition::duplicate(void) const
  1220. {
  1221. OrCondition *pNew = newInstance(OrCondition);
  1222. if (m_firstAnd) {
  1223. pNew->m_firstAnd = m_firstAnd->duplicate();
  1224. }
  1225. OrCondition *pLink = m_nextOr;
  1226. OrCondition *pCur = pNew;
  1227. while (pLink) {
  1228. pCur->m_nextOr = newInstance(OrCondition);
  1229. pCur = pCur->m_nextOr;
  1230. if (pLink->m_firstAnd) {
  1231. pCur->m_firstAnd = pLink->m_firstAnd->duplicate();
  1232. }
  1233. pLink = pLink->m_nextOr;
  1234. }
  1235. return pNew;
  1236. }
  1237. OrCondition *OrCondition::duplicateAndQualify(const AsciiString& qualifier,
  1238. const AsciiString& playerTemplateName, const AsciiString& newPlayerName) const
  1239. {
  1240. OrCondition *pNew = newInstance(OrCondition);
  1241. if (m_firstAnd) {
  1242. pNew->m_firstAnd = m_firstAnd->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  1243. }
  1244. OrCondition *pLink = m_nextOr;
  1245. OrCondition *pCur = pNew;
  1246. while (pLink) {
  1247. pCur->m_nextOr = newInstance(OrCondition);
  1248. pCur = pCur->m_nextOr;
  1249. if (pLink->m_firstAnd) {
  1250. pCur->m_firstAnd = pLink->m_firstAnd->duplicateAndQualify(qualifier, playerTemplateName, newPlayerName);
  1251. }
  1252. pLink = pLink->m_nextOr;
  1253. }
  1254. return pNew;
  1255. }
  1256. Condition *OrCondition::removeCondition(Condition *pCond)
  1257. {
  1258. Condition *pPrev = NULL;
  1259. Condition *pCur = m_firstAnd;
  1260. while (pCond != pCur) {
  1261. pPrev = pCur;
  1262. pCur = pCur->getNext();
  1263. }
  1264. DEBUG_ASSERTCRASH(pCur, ("Couldn't find condition."));
  1265. if (pCur==NULL)
  1266. return NULL;
  1267. if (pPrev) {
  1268. pPrev->setNextCondition(pCur->getNext());
  1269. } else {
  1270. m_firstAnd = pCur->getNext();
  1271. }
  1272. pCur->setNextCondition(NULL);
  1273. return pCur;
  1274. }
  1275. void OrCondition::deleteCondition(Condition *pCond)
  1276. {
  1277. Condition *pCur = removeCondition(pCond);
  1278. DEBUG_ASSERTCRASH(pCur, ("Couldn't find condition."));
  1279. if (pCur==NULL)
  1280. return;
  1281. pCur->deleteInstance();
  1282. }
  1283. /**
  1284. * OrCondition::WriteOrConditionDataChunk - Writes a Or condition chunk.
  1285. * Format is the newer CHUNKY format.
  1286. * Input: DataChunkInput
  1287. *
  1288. */
  1289. void OrCondition::WriteOrConditionDataChunk(DataChunkOutput &chunkWriter, OrCondition *pOrCondition)
  1290. {
  1291. /**********OR CONDITION DATA ***********************/
  1292. while (pOrCondition) {
  1293. chunkWriter.openDataChunk("OrCondition", K_SCRIPT_OR_CONDITION_DATA_VERSION_1);
  1294. if (pOrCondition->m_firstAnd) Condition::WriteConditionDataChunk(chunkWriter, pOrCondition->m_firstAnd);
  1295. chunkWriter.closeDataChunk();
  1296. pOrCondition = pOrCondition->getNextOrCondition();
  1297. }
  1298. }
  1299. /**
  1300. * OrCondition::ParseOrConditionDataChunk - read a Or condition chunk.
  1301. * Format is the newer CHUNKY format.
  1302. * See OrCondition::WriteOrConditionDataChunk for the writer.
  1303. * Input: DataChunkInput
  1304. *
  1305. */
  1306. Bool OrCondition::ParseOrConditionDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  1307. {
  1308. Script *pScript = (Script *)userData;
  1309. OrCondition *pOrCondition = newInstance(OrCondition);
  1310. OrCondition *pFirst = pScript->getOrCondition();
  1311. while (pFirst && pFirst->getNextOrCondition()) {
  1312. pFirst = pFirst->getNextOrCondition();
  1313. }
  1314. if (pFirst) {
  1315. pFirst->setNextOrCondition(pOrCondition);
  1316. } else {
  1317. pScript->setOrCondition(pOrCondition);
  1318. }
  1319. file.registerParser( AsciiString("Condition"), info->label, Condition::ParseConditionDataChunk );
  1320. return file.parse(pOrCondition);
  1321. }
  1322. /**
  1323. * OrCondition::findPreviousCondition - find the condition that immediately proceeds curCond.
  1324. * Format is the newer CHUNKY format.
  1325. * See OrCondition::WriteOrConditionDataChunk for the writer.
  1326. * Input: DataChunkInput
  1327. *
  1328. */
  1329. Condition *OrCondition::findPreviousCondition( Condition *curCond )
  1330. {
  1331. Condition *myConditions = getFirstAndCondition();
  1332. if (myConditions == curCond) {
  1333. return NULL;
  1334. }
  1335. while (myConditions) {
  1336. if (myConditions->getNext() == curCond) {
  1337. return myConditions;
  1338. }
  1339. myConditions = myConditions->getNext();
  1340. }
  1341. DEBUG_CRASH(("Searched for non-existent And Condition. (jkmcd)"));
  1342. return NULL;
  1343. }
  1344. //-------------------------------------------------------------------------------------------------
  1345. // ******************************** class Condition *********************************************
  1346. //-------------------------------------------------------------------------------------------------
  1347. Condition::Condition():
  1348. m_conditionType(CONDITION_FALSE),
  1349. m_hasWarnings(false),
  1350. m_customData(0),
  1351. m_customFrame(0),
  1352. m_numParms(0),
  1353. m_nextAndCondition(NULL)
  1354. {
  1355. Int i;
  1356. for (i = 0; i < MAX_PARMS; i++)
  1357. {
  1358. m_parms[i] = NULL;
  1359. }
  1360. }
  1361. Condition::Condition(enum ConditionType type):
  1362. m_conditionType(type),
  1363. m_hasWarnings(false),
  1364. m_customData(0),
  1365. m_customFrame(0),
  1366. m_numParms(0),
  1367. m_nextAndCondition(NULL)
  1368. {
  1369. Int i;
  1370. for (i=0; i<MAX_PARMS; i++) {
  1371. m_parms[i] = NULL;
  1372. }
  1373. setConditionType(type);
  1374. }
  1375. void Condition::setConditionType(enum ConditionType type)
  1376. {
  1377. Int i;
  1378. for (i=0; i<m_numParms; i++) {
  1379. if (m_parms[i])
  1380. m_parms[i]->deleteInstance();
  1381. m_parms[i] = NULL;
  1382. }
  1383. m_conditionType = type;
  1384. const ConditionTemplate *pTemplate = TheScriptEngine->getConditionTemplate(m_conditionType);
  1385. m_numParms = pTemplate->getNumParameters();
  1386. for (i=0; i<m_numParms; i++) {
  1387. m_parms[i] = newInstance(Parameter)(pTemplate->getParameterType(i));
  1388. }
  1389. }
  1390. Condition *Condition::duplicate(void) const
  1391. {
  1392. Condition *pNew = newInstance(Condition)(m_conditionType);
  1393. Int i;
  1394. for (i=0; i<m_numParms && i<pNew->m_numParms; i++) {
  1395. *pNew->m_parms[i] = *m_parms[i];
  1396. }
  1397. Condition *pLink = m_nextAndCondition;
  1398. Condition *pCur = pNew;
  1399. while (pLink) {
  1400. pCur->m_nextAndCondition = newInstance(Condition)(pLink->getConditionType());
  1401. pCur = pCur->m_nextAndCondition;
  1402. for (i=0; i<pLink->m_numParms; i++) {
  1403. *pCur->m_parms[i] = *pLink->m_parms[i];
  1404. }
  1405. pLink = pLink->m_nextAndCondition;
  1406. }
  1407. return pNew;
  1408. }
  1409. Condition *Condition::duplicateAndQualify(const AsciiString& qualifier,
  1410. const AsciiString& playerTemplateName, const AsciiString& newPlayerName) const
  1411. {
  1412. Condition *pNew = newInstance(Condition)(m_conditionType);
  1413. Int i;
  1414. for (i=0; i<m_numParms && i<pNew->m_numParms; i++) {
  1415. *pNew->m_parms[i] = *m_parms[i];
  1416. pNew->m_parms[i]->qualify(qualifier, playerTemplateName, newPlayerName);
  1417. }
  1418. Condition *pLink = m_nextAndCondition;
  1419. Condition *pCur = pNew;
  1420. while (pLink) {
  1421. pCur->m_nextAndCondition = newInstance(Condition)(pLink->getConditionType());
  1422. pCur = pCur->m_nextAndCondition;
  1423. for (i=0; i<pLink->m_numParms; i++) {
  1424. *pCur->m_parms[i] = *pLink->m_parms[i];
  1425. pCur->m_parms[i]->qualify(qualifier, playerTemplateName, newPlayerName);
  1426. }
  1427. pLink = pLink->m_nextAndCondition;
  1428. }
  1429. return pNew;
  1430. }
  1431. Condition::~Condition(void)
  1432. {
  1433. Int i;
  1434. for (i=0; i<m_numParms; i++) {
  1435. m_parms[i]->deleteInstance();
  1436. m_parms[i] = NULL;
  1437. }
  1438. if (m_nextAndCondition) {
  1439. Condition *cur = m_nextAndCondition;
  1440. Condition *next;
  1441. while (cur) {
  1442. next = cur->getNext();
  1443. cur->setNextCondition(NULL); // prevents recursion.
  1444. cur->deleteInstance();
  1445. cur = next;
  1446. }
  1447. }
  1448. }
  1449. Int Condition::getUiStrings(AsciiString strings[MAX_PARMS])
  1450. {
  1451. const ConditionTemplate *pTemplate = TheScriptEngine->getConditionTemplate(m_conditionType);
  1452. return pTemplate->getUiStrings(strings);
  1453. }
  1454. AsciiString Condition::getUiText(void)
  1455. {
  1456. AsciiString uiText;
  1457. AsciiString strings[MAX_PARMS];
  1458. Int numStrings = getUiStrings(strings);
  1459. Int i;
  1460. if (m_hasWarnings) {
  1461. uiText = "[???]";
  1462. }
  1463. for (i=0; i<MAX_PARMS; i++) {
  1464. if (i<numStrings) {
  1465. uiText.concat(strings[i]);
  1466. }
  1467. if (i<m_numParms) {
  1468. uiText.concat(m_parms[i]->getUiText());
  1469. }
  1470. }
  1471. return uiText;
  1472. }
  1473. /**
  1474. * Condition::WriteConditionDataChunk - Writes a condition chunk.
  1475. * Format is the newer CHUNKY format.
  1476. * Input: DataChunkInput
  1477. *
  1478. */
  1479. void Condition::WriteConditionDataChunk(DataChunkOutput &chunkWriter, Condition *pCondition)
  1480. {
  1481. /**********Condition DATA ***********************/
  1482. while (pCondition) {
  1483. chunkWriter.openDataChunk("Condition", K_SCRIPT_CONDITION_VERSION_4);
  1484. chunkWriter.writeInt(pCondition->m_conditionType);
  1485. const ConditionTemplate* ct = TheScriptEngine->getConditionTemplate(pCondition->m_conditionType);
  1486. if (ct) {
  1487. chunkWriter.writeNameKey(ct->m_internalNameKey);
  1488. } else {
  1489. DEBUG_CRASH(("Invalid condition."));
  1490. chunkWriter.writeNameKey(NAMEKEY("Bogus"));
  1491. }
  1492. chunkWriter.writeInt(pCondition->m_numParms);
  1493. Int i;
  1494. for (i=0; i<pCondition->m_numParms; i++) {
  1495. pCondition->m_parms[i]->WriteParameter(chunkWriter);
  1496. }
  1497. chunkWriter.closeDataChunk();
  1498. pCondition = pCondition->getNext();
  1499. }
  1500. }
  1501. /**
  1502. * Condition::ParseConditionDataChunk - read a condition.
  1503. * Format is the newer CHUNKY format.
  1504. * See Condition::WriteActionDataChunk for the writer.
  1505. * Input: DataChunkInput
  1506. *
  1507. */
  1508. Bool Condition::ParseConditionDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  1509. {
  1510. Condition *pCondition = newInstance(Condition);
  1511. OrCondition *pOr = (OrCondition *)userData;
  1512. pCondition->m_conditionType = (enum ConditionType)file.readInt();
  1513. const ConditionTemplate* ct = TheScriptEngine->getConditionTemplate(pCondition->m_conditionType);
  1514. if (info->version >= K_SCRIPT_CONDITION_VERSION_4) {
  1515. NameKeyType key = file.readNameKey();
  1516. Bool match = false;
  1517. if (ct && ct->m_internalNameKey == key) {
  1518. match = TRUE; // All good. jba. [3/20/2003]
  1519. }
  1520. if (!match) {
  1521. // name and id don't match. Find the name [3/20/2003]
  1522. Int i;
  1523. for (i=0; i<Condition::NUM_ITEMS; i++) {
  1524. ct = TheScriptEngine->getConditionTemplate(i);
  1525. if (key == ct->m_internalNameKey) {
  1526. match = true;
  1527. DEBUG_LOG(("Rematching script condition %s\n", KEYNAME(key).str()));
  1528. pCondition->m_conditionType = (enum ConditionType)i;
  1529. break;
  1530. }
  1531. }
  1532. }
  1533. if (!match) {
  1534. // Invalid script [3/20/2003]
  1535. DEBUG_CRASH(("Invalid script condition. Making it false. jba."));
  1536. pCondition->m_conditionType = CONDITION_FALSE;
  1537. pCondition->m_numParms = 0;
  1538. }
  1539. }
  1540. pCondition->m_numParms =file.readInt();
  1541. Int i;
  1542. for (i=0; i<pCondition->m_numParms; i++)
  1543. {
  1544. pCondition->m_parms[i] = Parameter::ReadParameter(file);
  1545. }
  1546. if (file.getChunkVersion() < K_SCRIPT_CONDITION_VERSION_2) {
  1547. for (int j = 0; ParameterChangesVer2[j] != -1; ++j) {
  1548. if (pCondition->m_conditionType == ParameterChangesVer2[j]) {
  1549. pCondition->m_parms[pCondition->m_numParms] = newInstance(Parameter)(Parameter::SURFACES_ALLOWED, 3);
  1550. pCondition->m_numParms = 3;
  1551. }
  1552. }
  1553. }
  1554. // heal old files.
  1555. switch (pCondition->getConditionType())
  1556. {
  1557. case SKIRMISH_SPECIAL_POWER_READY:
  1558. if (pCondition->m_numParms == 1)
  1559. {
  1560. pCondition->m_numParms = 2;
  1561. pCondition->m_parms[1] = pCondition->m_parms[0];
  1562. pCondition->m_parms[0] = newInstance(Parameter)(Parameter::SIDE, 0);
  1563. pCondition->m_parms[0]->friend_setString(THIS_PLAYER);
  1564. }
  1565. break;
  1566. }
  1567. #ifdef COUNT_SCRIPT_USAGE
  1568. const ConditionTemplate* conT = TheScriptEngine->getConditionTemplate(pCondition->m_conditionType);
  1569. conT->m_numTimesUsed++;
  1570. conT->m_firstMapUsed = TheGlobalData->m_mapName;
  1571. #endif
  1572. if (ct->getNumParameters() != pCondition->getNumParameters()) {
  1573. // Invalid script [3/20/2003]
  1574. DEBUG_CRASH(("Invalid script condition. Making it false. jba."));
  1575. pCondition->m_conditionType = ConditionType::CONDITION_FALSE;
  1576. pCondition->m_numParms = 0;
  1577. }
  1578. Condition *pLast = pOr->getFirstAndCondition();
  1579. while (pLast && pLast->getNext()) {
  1580. pLast = pLast->getNext();
  1581. }
  1582. if (pLast) {
  1583. pLast->setNextCondition(pCondition);
  1584. } else {
  1585. pOr->setFirstAndCondition(pCondition);
  1586. }
  1587. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  1588. return true;
  1589. }
  1590. //-------------------------------------------------------------------------------------------------
  1591. // ******************************** class Template *********************************************
  1592. //-------------------------------------------------------------------------------------------------
  1593. Template::Template() :
  1594. m_numUiStrings(0),
  1595. m_numParameters(0),
  1596. #ifdef COUNT_SCRIPT_USAGE
  1597. m_numTimesUsed(0),
  1598. #endif
  1599. m_uiName("UNUSED/(placeholder)/placeholder")
  1600. {
  1601. }
  1602. Int Template::getUiStrings(AsciiString strings[MAX_PARMS]) const
  1603. {
  1604. Int i;
  1605. for (i=0; i<m_numUiStrings; i++) {
  1606. strings[i] = m_uiStrings[i];
  1607. }
  1608. return m_numUiStrings;
  1609. }
  1610. //-------------------------------------------------------------------------------------------------
  1611. // ******************************** class Parameter ***********************************************
  1612. //-------------------------------------------------------------------------------------------------
  1613. enum Parameter::ParameterType Template::getParameterType(Int ndx) const
  1614. {
  1615. if (ndx >= 0 && ndx < m_numParameters) {
  1616. return m_parameters[ndx];
  1617. }
  1618. DEBUG_CRASH(("Index out of range."));
  1619. return Parameter::INT;
  1620. }
  1621. void Parameter::getCoord3D(Coord3D *pLoc) const
  1622. {
  1623. DEBUG_ASSERTCRASH(m_paramType==COORD3D, ("Wrong parameter type."));
  1624. pLoc->x = pLoc->y = pLoc->z = 0;
  1625. if (m_paramType==COORD3D) {
  1626. *pLoc = m_coord;
  1627. }
  1628. }
  1629. void Parameter::setCoord3D(const Coord3D *pLoc)
  1630. {
  1631. DEBUG_ASSERTCRASH(m_paramType==COORD3D, ("Wrong parameter type."));
  1632. if (m_paramType==COORD3D) {
  1633. m_coord= *pLoc ;
  1634. }
  1635. }
  1636. void Parameter::qualify(const AsciiString& qualifier,
  1637. const AsciiString& playerTemplateName, const AsciiString& newPlayerName)
  1638. {
  1639. AsciiString tmpString;
  1640. switch (m_paramType) {
  1641. case SIDE:
  1642. tmpString = m_string;
  1643. tmpString.concat(qualifier);
  1644. if (tmpString==playerTemplateName) {
  1645. m_string = newPlayerName;
  1646. }
  1647. break;
  1648. case TEAM:
  1649. if (m_string == THIS_TEAM) {
  1650. break;
  1651. }
  1652. /// otherwise drop down & qualify.
  1653. case SCRIPT:
  1654. case COUNTER:
  1655. case FLAG:
  1656. case SCRIPT_SUBROUTINE: m_string.concat(qualifier); break;
  1657. default: break;
  1658. }
  1659. }
  1660. AsciiString Parameter::getUiText(void) const
  1661. {
  1662. AsciiString uiText;
  1663. AsciiString uiString = m_string;
  1664. if (uiString.isEmpty()) {
  1665. uiString = "???";
  1666. }
  1667. Coord3D pos;
  1668. switch (m_paramType)
  1669. {
  1670. default:
  1671. DEBUG_CRASH(("Unknown parameter type."));
  1672. break;
  1673. case SOUND:
  1674. uiText.format("Sound '%s'", uiString.str());
  1675. break;
  1676. case SCRIPT:
  1677. uiText.format("Script '%s'", uiString.str());
  1678. break;
  1679. case TEAM_STATE:
  1680. uiText.format("'%s'", uiString.str());
  1681. break;
  1682. case SCRIPT_SUBROUTINE:
  1683. uiText.format("Subroutine '%s'", uiString.str());
  1684. break;
  1685. case ATTACK_PRIORITY_SET:
  1686. uiText.format("Attack priority set '%s'", uiString.str());
  1687. break;
  1688. case WAYPOINT:
  1689. uiText.format("Waypoint '%s'", uiString.str());
  1690. break;
  1691. case WAYPOINT_PATH:
  1692. uiText.format("Waypoint Path '%s'", uiString.str());
  1693. break;
  1694. case TRIGGER_AREA:
  1695. uiText.format(" area '%s'", uiString.str());
  1696. break;
  1697. case COMMAND_BUTTON:
  1698. uiText.format("Command button: '%s'", uiString.str());
  1699. break;
  1700. case FONT_NAME:
  1701. uiText.format("Font: '%s'", uiString.str());
  1702. break;
  1703. case LOCALIZED_TEXT:
  1704. uiText.format("Localized String: '%s'", uiString.str());
  1705. break;
  1706. case TEXT_STRING:
  1707. uiText.format("String: '%s'", uiString.str());
  1708. break;
  1709. case TEAM:
  1710. uiText.format("Team '%s'", uiString.str());
  1711. break;
  1712. case UNIT:
  1713. uiText.format("Unit '%s'", uiString.str());
  1714. break;
  1715. case BRIDGE:
  1716. uiText.format("Bridge '%s'", uiString.str());
  1717. break;
  1718. case ANGLE:
  1719. uiText.format("%.2f degrees", m_real*180/PI);
  1720. break;
  1721. case PERCENT:
  1722. uiText.format("%.2f%%", m_real*100.0f);
  1723. break;
  1724. case COORD3D:
  1725. getCoord3D(&pos);
  1726. uiText.format("(%.2f,%.2f,%.2f)", pos.x,pos.y,pos.z);
  1727. break;
  1728. case OBJECT_TYPE:
  1729. uiText.format("'%s'", uiString.str());
  1730. break;
  1731. case KIND_OF_PARAM:
  1732. if (m_int >= KINDOF_FIRST && m_int < KINDOF_COUNT )
  1733. uiText.format("Kind is '%s'", KindOfMaskType::getNameFromSingleBit(m_int));
  1734. else
  1735. uiText.format("Kind is '???'");
  1736. break;
  1737. case SIDE:
  1738. uiText.format("Player '%s'", uiString.str());
  1739. break;
  1740. case COUNTER:
  1741. uiText.format("'%s'", uiString.str());
  1742. break;
  1743. case INT:
  1744. uiText.format(" %d ", m_int);
  1745. break;
  1746. case BOOLEAN:
  1747. uiText.concat(m_int?"TRUE":"FALSE");
  1748. break;
  1749. case REAL:
  1750. uiText.format("%.2f", m_real);
  1751. break;
  1752. case FLAG:
  1753. uiText.format("Flag named '%s'", uiString.str());
  1754. break;
  1755. case COMPARISON:
  1756. switch (m_int) {
  1757. case LESS_THAN: uiText.format("Less Than"); break;
  1758. case LESS_EQUAL: uiText.format("Less Than or Equal"); break;
  1759. case EQUAL: uiText.format("Equal To"); break;
  1760. case GREATER_EQUAL: uiText.format("Greater Than or Equal To"); break;
  1761. case GREATER: uiText.format("Greater Than"); break;
  1762. case NOT_EQUAL: uiText.format("Not Equal To"); break;
  1763. default : DEBUG_CRASH(("Unknown comparison type."));
  1764. }
  1765. break;
  1766. case RELATION:
  1767. switch (m_int) {
  1768. case REL_ENEMY: uiText.format("Enemy"); break;
  1769. case REL_NEUTRAL: uiText.format("Neutral"); break;
  1770. case REL_FRIEND: uiText.format("Friend"); break;
  1771. default : DEBUG_CRASH(("Unknown Relation type."));
  1772. }
  1773. break;
  1774. case AI_MOOD:
  1775. switch (m_int) {
  1776. case AI_SLEEP: uiText.format("Sleep"); break;
  1777. case AI_PASSIVE: uiText.format("Passive"); break;
  1778. case AI_NORMAL: uiText.format("Normal"); break;
  1779. case AI_ALERT: uiText.format("Alert"); break;
  1780. case AI_AGGRESSIVE: uiText.format("Aggressive"); break;
  1781. default : DEBUG_CRASH(("Unknown AI Mood type."));
  1782. }
  1783. break;
  1784. case RADAR_EVENT_TYPE:
  1785. switch (m_int) {
  1786. //case RADAR_EVENT_INVALID: ++m_int; // continue to the next case.
  1787. case RADAR_EVENT_INVALID: DEBUG_CRASH(("Invalid radar event\n")); uiText.format("Construction"); break;
  1788. case RADAR_EVENT_CONSTRUCTION: uiText.format("Construction"); break;
  1789. case RADAR_EVENT_UPGRADE: uiText.format("Upgrade"); break;
  1790. case RADAR_EVENT_UNDER_ATTACK: uiText.format("Under Attack"); break;
  1791. case RADAR_EVENT_INFORMATION: uiText.format("Information"); break;
  1792. case RADAR_EVENT_INFILTRATION: uiText.format("Infiltration"); break;
  1793. default : DEBUG_CRASH(("Unknown Radar event type."));
  1794. }
  1795. break;
  1796. case LEFT_OR_RIGHT:
  1797. switch (m_int)
  1798. {
  1799. case EVAC_BURST_FROM_CENTER: uiText.format("normal (burst from center)"); break;
  1800. case EVAC_TO_LEFT: uiText.format("left"); break;
  1801. case EVAC_TO_RIGHT: uiText.format("right"); break;
  1802. default : uiText.format("unspecified"); break;
  1803. }
  1804. break;
  1805. case DIALOG:
  1806. uiText.format("'%s'", uiString.str());
  1807. break;
  1808. case SKIRMISH_WAYPOINT_PATH:
  1809. uiText.format("'%s'", uiString.str());
  1810. break;
  1811. case COLOR:
  1812. uiText.format(" R:%d G:%d B:%d ", (m_int&0x00ff0000)>>16, (m_int&0x0000ff00)>>8, (m_int&0x000000ff) );
  1813. break;
  1814. case MUSIC:
  1815. uiText.format("'%s'", uiString.str());
  1816. break;
  1817. case MOVIE:
  1818. uiText.format("'%s'", uiString.str());
  1819. break;
  1820. case SPECIAL_POWER:
  1821. uiText.format("Special power '%s'", uiString.str());
  1822. break;
  1823. case SCIENCE:
  1824. uiText.format("Science '%s'", uiString.str());
  1825. break;
  1826. case SCIENCE_AVAILABILITY:
  1827. uiText.format( "Science availability '%s'", uiString.str() );
  1828. break;
  1829. case UPGRADE:
  1830. uiText.format("Upgrade '%s'", uiString.str());
  1831. break;
  1832. case COMMANDBUTTON_ABILITY:
  1833. case COMMANDBUTTON_ALL_ABILITIES:
  1834. uiText.format( "Ability '%s'", uiString.str() );
  1835. break;
  1836. case EMOTICON:
  1837. uiText.format( "Emoticon '%s'", uiString.str() );
  1838. break;
  1839. case BOUNDARY:
  1840. uiText.format("Boundary %s", BORDER_COLORS[m_int % BORDER_COLORS_SIZE].m_colorName);
  1841. break;
  1842. case BUILDABLE:
  1843. if (m_int >= BSTATUS_YES && m_int < BSTATUS_NUM_TYPES )
  1844. uiText.format("Buildable (%s)", BuildableStatusNames[m_int - BSTATUS_YES]);
  1845. else
  1846. uiText.format("Buildable (???)");
  1847. break;
  1848. case SURFACES_ALLOWED:
  1849. {
  1850. if (m_int > 0 && m_int <= 3)
  1851. uiText.format("Surfaces Allowed: %s", Surfaces[m_int - 1]);
  1852. else
  1853. uiText.format("Surfaces Allowed: ???");
  1854. break;
  1855. }
  1856. case SHAKE_INTENSITY:
  1857. {
  1858. if (m_int > 0 && m_int < View::SHAKE_COUNT)
  1859. uiText.format("Shake Intensity: %s", ShakeIntensities[m_int]);
  1860. else
  1861. uiText.format("Shake Intensity: ???");
  1862. break;
  1863. }
  1864. case OBJECT_STATUS:
  1865. {
  1866. if (m_string.isEmpty()) {
  1867. uiText.format("Object Status is '???'");
  1868. } else {
  1869. uiText.format("Object Status is '%s'", m_string.str());
  1870. }
  1871. break;
  1872. }
  1873. case FACTION_NAME:
  1874. {
  1875. uiText.format("Faction Name: %s", uiString.str());
  1876. break;
  1877. }
  1878. case OBJECT_TYPE_LIST:
  1879. uiText.format("'%s'", uiString.str());
  1880. break;
  1881. case REVEALNAME:
  1882. uiText.format("Reveal Name: %s", uiString.str());
  1883. break;
  1884. case OBJECT_PANEL_FLAG:
  1885. uiText.format("Object Flag: %s", uiString.str());
  1886. break;
  1887. }
  1888. return uiText;
  1889. }
  1890. /**
  1891. * Parameter::WriteParameter - Writes an Parameter.
  1892. * Format is the newer CHUNKY format.
  1893. * Input: DataChunkInput
  1894. *
  1895. */
  1896. void Parameter::WriteParameter(DataChunkOutput &chunkWriter)
  1897. {
  1898. /**********Parameter DATA ***********************/
  1899. chunkWriter.writeInt(m_paramType);
  1900. if (m_paramType == KIND_OF_PARAM) {
  1901. // To get the proper kindof string stored.
  1902. m_string = KindOfMaskType::getNameFromSingleBit(m_int);
  1903. }
  1904. if (m_paramType == COORD3D) {
  1905. chunkWriter.writeReal(m_coord.x);
  1906. chunkWriter.writeReal(m_coord.y);
  1907. chunkWriter.writeReal(m_coord.z);
  1908. } else {
  1909. chunkWriter.writeInt(m_int);
  1910. chunkWriter.writeReal(m_real);
  1911. chunkWriter.writeAsciiString(m_string);
  1912. }
  1913. }
  1914. /**
  1915. * Parameter::ReadParameter - read a parameter.
  1916. * Format is the newer CHUNKY format.
  1917. * See Parameter::WriteParameter for the writer.
  1918. * Input: DataChunkInput
  1919. *
  1920. */
  1921. Parameter *Parameter::ReadParameter(DataChunkInput &file)
  1922. {
  1923. Parameter *pParm = newInstance(Parameter)( (ParameterType)file.readInt());
  1924. pParm->m_initialized = true;
  1925. if (pParm->getParameterType() == COORD3D) {
  1926. Coord3D pos;
  1927. pos.x = file.readReal();
  1928. pos.y = file.readReal();
  1929. pos.z = file.readReal();
  1930. pParm->setCoord3D(&pos);
  1931. }
  1932. else
  1933. {
  1934. pParm->m_int = file.readInt();
  1935. pParm->m_real = file.readReal();
  1936. pParm->m_string = file.readAsciiString();
  1937. }
  1938. if (pParm->getParameterType() == OBJECT_TYPE)
  1939. {
  1940. // quick hack to make loading models with "Fundamentalist" switch to "GLA"
  1941. if (pParm->m_string.startsWith("Fundamentalist"))
  1942. {
  1943. char oldName[256];
  1944. char newName[256];
  1945. strcpy(oldName, pParm->m_string.str());
  1946. strcpy(newName, "GLA");
  1947. strcat(newName, oldName+strlen("Fundamentalist"));
  1948. pParm->m_string.set(newName);
  1949. DEBUG_LOG(("Changing Script Ref from %s to %s\n", oldName, newName));
  1950. }
  1951. }
  1952. if (pParm->getParameterType() == UPGRADE)
  1953. {
  1954. // quick hack to make obsolete capture building upgrades switch to the new one. jba.
  1955. if (pParm->m_string == "Upgrade_AmericaRangerCaptureBuilding" ||
  1956. pParm->m_string == "Upgrade_ChinaRedguardCaptureBuilding" ||
  1957. pParm->m_string == "Upgrade_GLARebelCaptureBuilding")
  1958. {
  1959. pParm->m_string.set("Upgrade_InfantryCaptureBuilding");
  1960. }
  1961. }
  1962. if (pParm->getParameterType() == OBJECT_STATUS)
  1963. {
  1964. // Need to change the string to an ObjectStatusMaskType
  1965. for( int i = 0; i < OBJECT_STATUS_COUNT; ++i )
  1966. {
  1967. if( !pParm->m_string.compareNoCase( ObjectStatusMaskType::getBitNames()[i] ) )
  1968. {
  1969. pParm->setStatus( MAKE_OBJECT_STATUS_MASK( i ) );
  1970. break;
  1971. }
  1972. }
  1973. }
  1974. if (pParm->getParameterType() == KIND_OF_PARAM)
  1975. {
  1976. // Need to change the string to an integer
  1977. const char** kindofNames = KindOfMaskType::getBitNames();
  1978. if (!pParm->m_string.isEmpty())
  1979. {
  1980. Bool found = false;
  1981. for (int i = 0; kindofNames[i]; ++i)
  1982. {
  1983. if (pParm->m_string.compareNoCase(kindofNames[i]) == 0)
  1984. {
  1985. pParm->setInt(i);
  1986. found = true;
  1987. break;
  1988. }
  1989. if( !pParm->m_string.compareNoCase( "CRUSHER" ) )
  1990. {
  1991. //????
  1992. pParm->setInt(i);
  1993. found = true;
  1994. DEBUG_CRASH(( "Kindof CRUSHER no longer exists -- in order to get your map to load, it has been switched to OBSTACLE, please call Kris (x36844).", pParm->m_string.str()));
  1995. break;
  1996. }
  1997. else if( !pParm->m_string.compareNoCase( "CRUSHABLE" ) )
  1998. {
  1999. //????
  2000. pParm->setInt(i);
  2001. found = true;
  2002. DEBUG_CRASH(( "Kindof CRUSHABLE no longer exists -- in order to get your map to load, it has been switched to OBSTACLE, please call Kris (x36844).", pParm->m_string.str()));
  2003. break;
  2004. }
  2005. else if( !pParm->m_string.compareNoCase( "OVERLAPPABLE" ) )
  2006. {
  2007. //????
  2008. pParm->setInt(i);
  2009. found = true;
  2010. DEBUG_CRASH(( "Kindof OVERLAPPABLE no longer exists -- in order to get your map to load, it has been switched to OBSTACLE, please call Kris (x36844).", pParm->m_string.str()));
  2011. break;
  2012. }
  2013. else if( !pParm->m_string.compareNoCase( "MISSILE" ) )
  2014. {
  2015. //MISSILE was split into two kinds -- SMALL_MISSILE and BALLISTIC_MISSILE.
  2016. pParm->m_string.format( "SMALL_MISSILE" );
  2017. for( i = 0; kindofNames[i]; ++i )
  2018. {
  2019. if (pParm->m_string.compareNoCase("SMALL_MISSILE") == 0)
  2020. {
  2021. pParm->setInt(i);
  2022. found = true;
  2023. break;
  2024. }
  2025. }
  2026. DEBUG_CRASH(("Unable to find Kindof SMALL_MISSILE', please call KrisM (x36844).", pParm->m_string.str()));
  2027. }
  2028. }
  2029. if (!found)
  2030. {
  2031. DEBUG_CRASH(("Unable to find Kindof '%s', please call JKM (x36872).", pParm->m_string.str()));
  2032. throw ERROR_BUG;
  2033. }
  2034. }
  2035. else
  2036. {
  2037. // Seems weird, but this is so WB will load them into the proper format.
  2038. pParm->m_string = kindofNames[pParm->m_int];
  2039. }
  2040. }
  2041. return pParm;
  2042. }
  2043. //-------------------------------------------------------------------------------------------------
  2044. // ******************************** class ScriptAction ***********************************************
  2045. //-------------------------------------------------------------------------------------------------
  2046. ScriptAction::ScriptAction():
  2047. m_actionType(NO_OP),
  2048. m_hasWarnings(false),
  2049. m_numParms(0),
  2050. //Added By Sadullah Nader
  2051. //Initializations inserted
  2052. m_nextAction(NULL)
  2053. //
  2054. {
  2055. }
  2056. ScriptAction::ScriptAction(enum ScriptActionType type):
  2057. m_actionType(type),
  2058. m_numParms(0)
  2059. {
  2060. Int i;
  2061. for (i=0; i<MAX_PARMS; i++) {
  2062. m_parms[i] = NULL;
  2063. }
  2064. setActionType(type);
  2065. }
  2066. void ScriptAction::setActionType(enum ScriptActionType type)
  2067. {
  2068. Int i;
  2069. for (i=0; i<m_numParms; i++) {
  2070. if (m_parms[i])
  2071. m_parms[i]->deleteInstance();
  2072. m_parms[i] = NULL;
  2073. }
  2074. m_actionType = type;
  2075. const ActionTemplate *pTemplate = TheScriptEngine->getActionTemplate(m_actionType);
  2076. m_numParms = pTemplate->getNumParameters();
  2077. for (i=0; i<m_numParms; i++) {
  2078. m_parms[i] = newInstance(Parameter)(pTemplate->getParameterType(i));
  2079. }
  2080. }
  2081. ScriptAction *ScriptAction::duplicate(void) const
  2082. {
  2083. ScriptAction *pNew = newInstance(ScriptAction)(m_actionType);
  2084. Int i;
  2085. for (i=0; i<m_numParms; i++) {
  2086. if (pNew->m_parms[i]) {
  2087. *pNew->m_parms[i] = *m_parms[i];
  2088. }
  2089. }
  2090. ScriptAction *pLink = m_nextAction;
  2091. ScriptAction *pCur = pNew;
  2092. while (pLink) {
  2093. pCur->m_nextAction = newInstance(ScriptAction)(pLink->m_actionType);
  2094. pCur = pCur->m_nextAction;
  2095. for (i=0; i<pLink->m_numParms; i++) {
  2096. if (pCur->m_parms[i] && pLink->m_parms[i]) {
  2097. *pCur->m_parms[i] = *pLink->m_parms[i];
  2098. }
  2099. }
  2100. pLink = pLink->m_nextAction;
  2101. }
  2102. return pNew;
  2103. }
  2104. ScriptAction *ScriptAction::duplicateAndQualify(const AsciiString& qualifier,
  2105. const AsciiString& playerTemplateName, const AsciiString& newPlayerName) const
  2106. {
  2107. ScriptAction *pNew = newInstance(ScriptAction)(m_actionType);
  2108. Int i;
  2109. for (i=0; i<m_numParms; i++) {
  2110. if (pNew->m_parms[i]) {
  2111. *pNew->m_parms[i] = *m_parms[i];
  2112. pNew->m_parms[i]->qualify(qualifier, playerTemplateName, newPlayerName);
  2113. }
  2114. }
  2115. ScriptAction *pLink = m_nextAction;
  2116. ScriptAction *pCur = pNew;
  2117. while (pLink) {
  2118. pCur->m_nextAction = newInstance(ScriptAction)(pLink->m_actionType);
  2119. pCur = pCur->m_nextAction;
  2120. for (i=0; i<pLink->m_numParms; i++) {
  2121. if (pCur->m_parms[i] && pLink->m_parms[i]) {
  2122. *pCur->m_parms[i] = *pLink->m_parms[i];
  2123. pCur->m_parms[i]->qualify(qualifier, playerTemplateName, newPlayerName);
  2124. }
  2125. }
  2126. pLink = pLink->m_nextAction;
  2127. }
  2128. return pNew;
  2129. }
  2130. ScriptAction::~ScriptAction(void)
  2131. {
  2132. Int i;
  2133. for (i=0; i<m_numParms; i++) {
  2134. m_parms[i]->deleteInstance();
  2135. m_parms[i] = NULL;
  2136. }
  2137. if (m_nextAction) {
  2138. ScriptAction *cur = m_nextAction;
  2139. ScriptAction *next;
  2140. while (cur) {
  2141. next = cur->getNext();
  2142. cur->setNextAction(NULL); // prevents recursion.
  2143. cur->deleteInstance();
  2144. cur = next;
  2145. }
  2146. }
  2147. }
  2148. Int ScriptAction::getUiStrings(AsciiString strings[MAX_PARMS])
  2149. {
  2150. const ActionTemplate *pTemplate = TheScriptEngine->getActionTemplate(m_actionType);
  2151. return pTemplate->getUiStrings(strings);
  2152. }
  2153. AsciiString ScriptAction::getUiText(void)
  2154. {
  2155. AsciiString uiText;
  2156. AsciiString strings[MAX_PARMS];
  2157. Int numStrings = getUiStrings(strings);
  2158. Int i;
  2159. if (m_hasWarnings) {
  2160. uiText = "[???]";
  2161. }
  2162. for (i=0; i<MAX_PARMS; i++) {
  2163. if (i<numStrings) {
  2164. uiText.concat(strings[i]);
  2165. }
  2166. if (i<m_numParms) {
  2167. uiText.concat(m_parms[i]->getUiText());
  2168. }
  2169. }
  2170. return uiText;
  2171. }
  2172. /**
  2173. * ScriptAction::WriteActionDataChunk - Writes an Action chunk.
  2174. * Format is the newer CHUNKY format.
  2175. * Input: DataChunkInput
  2176. *
  2177. */
  2178. void ScriptAction::WriteActionDataChunk(DataChunkOutput &chunkWriter, ScriptAction *pScriptAction)
  2179. {
  2180. /**********ACTION DATA ***********************/
  2181. while (pScriptAction) {
  2182. chunkWriter.openDataChunk("ScriptAction", K_SCRIPT_ACTION_VERSION_2);
  2183. chunkWriter.writeInt(pScriptAction->m_actionType);
  2184. const ActionTemplate* at = TheScriptEngine->getActionTemplate(pScriptAction->m_actionType);
  2185. if (at) {
  2186. chunkWriter.writeNameKey(at->m_internalNameKey);
  2187. } else {
  2188. DEBUG_CRASH(("Invalid action."));
  2189. chunkWriter.writeNameKey(NAMEKEY("Bogus"));
  2190. }
  2191. chunkWriter.writeInt(pScriptAction->m_numParms);
  2192. Int i;
  2193. for (i=0; i<pScriptAction->m_numParms; i++) {
  2194. pScriptAction->m_parms[i]->WriteParameter(chunkWriter);
  2195. }
  2196. chunkWriter.closeDataChunk();
  2197. pScriptAction = pScriptAction->getNext();
  2198. }
  2199. }
  2200. /**
  2201. * ScriptAction::ParseAction - read an action chunk in a script list.
  2202. * Format is the newer CHUNKY format.
  2203. * See ScriptAction::WriteActionDataChunk for the writer.
  2204. * Input: DataChunkInput
  2205. *
  2206. */
  2207. ScriptAction *ScriptAction::ParseAction(DataChunkInput &file, DataChunkInfo *info, void *userData)
  2208. {
  2209. ScriptAction *pScriptAction = newInstance(ScriptAction);
  2210. pScriptAction->m_actionType = (enum ScriptActionType)file.readInt();
  2211. const ActionTemplate* at = TheScriptEngine->getActionTemplate(pScriptAction->m_actionType);
  2212. if (info->version >= K_SCRIPT_ACTION_VERSION_2) {
  2213. NameKeyType key = file.readNameKey();
  2214. Bool match = false;
  2215. if (at && at->m_internalNameKey == key) {
  2216. match = TRUE; // All good. jba. [3/20/2003]
  2217. }
  2218. if (!match) {
  2219. // name and id don't match. Find the name [3/20/2003]
  2220. Int i;
  2221. for (i=0; i<ScriptAction::NUM_ITEMS; i++) {
  2222. at = TheScriptEngine->getActionTemplate(i);
  2223. if (key == at->m_internalNameKey) {
  2224. match = true;
  2225. DEBUG_LOG(("Rematching script action %s\n", KEYNAME(key).str()));
  2226. pScriptAction->m_actionType = (enum ScriptActionType)i;
  2227. break;
  2228. }
  2229. }
  2230. if (!match) {
  2231. // Invalid script [3/20/2003]
  2232. DEBUG_CRASH(("Invalid script action. Making it noop. jba."));
  2233. pScriptAction->m_actionType = ScriptAction::NO_OP;
  2234. pScriptAction->m_numParms = 0;
  2235. }
  2236. }
  2237. }
  2238. #if defined(_DEBUG) || defined(_INTERNAL)
  2239. Script *pScript = (Script *)userData;
  2240. if (at && (at->getName().isEmpty() || (at->getName().compareNoCase("(placeholder)") == 0))) {
  2241. DEBUG_CRASH(("Invalid Script Action found in script '%s'\n", pScript->getName().str()));
  2242. }
  2243. #endif
  2244. #ifdef COUNT_SCRIPT_USAGE
  2245. const ActionTemplate* at2 = TheScriptEngine->getActionTemplate(pScriptAction->m_actionType);
  2246. at2->m_numTimesUsed++;
  2247. at2->m_firstMapUsed = TheGlobalData->m_mapName;
  2248. #endif
  2249. pScriptAction->m_numParms =file.readInt();
  2250. Int i;
  2251. for (i=0; i<pScriptAction->m_numParms; i++)
  2252. {
  2253. pScriptAction->m_parms[i] = Parameter::ReadParameter(file);
  2254. }
  2255. // heal old files.
  2256. switch (pScriptAction->getActionType())
  2257. {
  2258. case SKIRMISH_FIRE_SPECIAL_POWER_AT_MOST_COST:
  2259. if (pScriptAction->m_numParms == 1)
  2260. {
  2261. pScriptAction->m_numParms = 2;
  2262. pScriptAction->m_parms[1] = pScriptAction->m_parms[0];
  2263. pScriptAction->m_parms[0] = newInstance(Parameter)(Parameter::SIDE, 0);
  2264. pScriptAction->m_parms[0]->friend_setString(THIS_PLAYER);
  2265. }
  2266. break;
  2267. case TEAM_FOLLOW_WAYPOINTS:
  2268. if (pScriptAction->m_numParms == 2)
  2269. {
  2270. pScriptAction->m_numParms = 3;
  2271. pScriptAction->m_parms[2] = newInstance(Parameter)(Parameter::BOOLEAN, 1);
  2272. }
  2273. break;
  2274. case SKIRMISH_BUILD_BASE_DEFENSE_FRONT:
  2275. if (pScriptAction->m_numParms == 1)
  2276. {
  2277. Bool flank = pScriptAction->m_parms[0]->getInt()!=0;
  2278. pScriptAction->m_parms[0]->deleteInstance();
  2279. pScriptAction->m_numParms = 0;
  2280. if (flank) pScriptAction->m_actionType = SKIRMISH_BUILD_BASE_DEFENSE_FLANK;
  2281. }
  2282. break;
  2283. case NAMED_SET_ATTITUDE:
  2284. case TEAM_SET_ATTITUDE:
  2285. if (pScriptAction->m_numParms >= 2 && pScriptAction->m_parms[1]->getParameterType() == Parameter::INT)
  2286. {
  2287. pScriptAction->m_parms[1] = newInstance(Parameter)(Parameter::AI_MOOD, pScriptAction->m_parms[1]->getInt());
  2288. }
  2289. break;
  2290. case MAP_REVEAL_AT_WAYPOINT:
  2291. case MAP_SHROUD_AT_WAYPOINT:
  2292. if (pScriptAction->getNumParameters() == 2)
  2293. {
  2294. pScriptAction->m_numParms = 3;
  2295. pScriptAction->m_parms[2] = newInstance(Parameter)(Parameter::SIDE);
  2296. }
  2297. break;
  2298. case MAP_REVEAL_ALL:
  2299. case MAP_REVEAL_ALL_PERM:
  2300. case MAP_REVEAL_ALL_UNDO_PERM:
  2301. case MAP_SHROUD_ALL:
  2302. if (pScriptAction->getNumParameters() == 0)
  2303. {
  2304. pScriptAction->m_numParms = 1;
  2305. pScriptAction->m_parms[0] = newInstance(Parameter)(Parameter::SIDE);
  2306. }
  2307. break;
  2308. case SPEECH_PLAY:
  2309. if (pScriptAction->getNumParameters() == 1)
  2310. {
  2311. pScriptAction->m_numParms = 2;
  2312. // Default it to TRUE, as per conversation with JohnL
  2313. pScriptAction->m_parms[1] = newInstance(Parameter)(Parameter::BOOLEAN, 1);
  2314. break;
  2315. }
  2316. case CAMERA_MOD_SET_FINAL_ZOOM:
  2317. case CAMERA_MOD_SET_FINAL_PITCH:
  2318. if (pScriptAction->getNumParameters() == 1)
  2319. {
  2320. pScriptAction->m_numParms = 3;
  2321. pScriptAction->m_parms[1] = newInstance(Parameter)(Parameter::PERCENT, 0.0f);
  2322. pScriptAction->m_parms[2] = newInstance(Parameter)(Parameter::PERCENT, 0.0f);
  2323. }
  2324. break;
  2325. case MOVE_CAMERA_TO:
  2326. case MOVE_CAMERA_ALONG_WAYPOINT_PATH:
  2327. case CAMERA_LOOK_TOWARD_OBJECT:
  2328. if (pScriptAction->getNumParameters() == 3)
  2329. {
  2330. pScriptAction->m_numParms = 5;
  2331. pScriptAction->m_parms[3] = newInstance(Parameter)(Parameter::REAL, 0.0f);
  2332. pScriptAction->m_parms[4] = newInstance(Parameter)(Parameter::REAL, 0.0f);
  2333. }
  2334. break;
  2335. case RESET_CAMERA:
  2336. case ZOOM_CAMERA:
  2337. case PITCH_CAMERA:
  2338. case ROTATE_CAMERA:
  2339. if (pScriptAction->getNumParameters() == 2)
  2340. {
  2341. pScriptAction->m_numParms = 4;
  2342. pScriptAction->m_parms[2] = newInstance(Parameter)(Parameter::REAL, 0.0f);
  2343. pScriptAction->m_parms[3] = newInstance(Parameter)(Parameter::REAL, 0.0f);
  2344. }
  2345. break;
  2346. case CAMERA_LOOK_TOWARD_WAYPOINT:
  2347. if (pScriptAction->getNumParameters() == 2)
  2348. {
  2349. pScriptAction->m_numParms = 5;
  2350. pScriptAction->m_parms[2] = newInstance(Parameter)(Parameter::REAL, 0.0f);
  2351. pScriptAction->m_parms[3] = newInstance(Parameter)(Parameter::REAL, 0.0f);
  2352. pScriptAction->m_parms[4] = newInstance(Parameter)(Parameter::BOOLEAN, FALSE);
  2353. }
  2354. else if (pScriptAction->getNumParameters() == 4)
  2355. {
  2356. pScriptAction->m_numParms = 5;
  2357. pScriptAction->m_parms[4] = newInstance(Parameter)(Parameter::BOOLEAN, FALSE);
  2358. }
  2359. break;
  2360. }
  2361. if (at->getNumParameters() != pScriptAction->getNumParameters()) {
  2362. // Invalid script [3/20/2003]
  2363. DEBUG_CRASH(("Invalid script action. Making it noop. jba."));
  2364. pScriptAction->m_actionType = ScriptAction::NO_OP;
  2365. pScriptAction->m_numParms = 0;
  2366. }
  2367. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  2368. return pScriptAction;
  2369. }
  2370. /**
  2371. * ScriptAction::ParseActionDataChunk - read an action chunk in a script list.
  2372. * Format is the newer CHUNKY format.
  2373. * See ScriptAction::WriteActionDataChunk for the writer.
  2374. * Input: DataChunkInput
  2375. *
  2376. */
  2377. Bool ScriptAction::ParseActionDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  2378. {
  2379. Script *pScript = (Script *)userData;
  2380. ScriptAction *pScriptAction = ParseAction(file, info, userData);
  2381. ScriptAction *pLast = pScript->getAction();
  2382. while (pLast && pLast->getNext())
  2383. {
  2384. pLast = pLast->getNext();
  2385. }
  2386. if (pLast)
  2387. {
  2388. pLast->setNextAction(pScriptAction);
  2389. }
  2390. else
  2391. {
  2392. pScript->setAction(pScriptAction);
  2393. }
  2394. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  2395. return true;
  2396. }
  2397. /**
  2398. * ScriptAction::WriteActionFalseDataChunk - Writes a false Action chunk.
  2399. * Format is the newer CHUNKY format.
  2400. * Input: DataChunkInput
  2401. *
  2402. */
  2403. void ScriptAction::WriteActionFalseDataChunk(DataChunkOutput &chunkWriter, ScriptAction *pScriptAction)
  2404. {
  2405. /**********ACTION DATA ***********************/
  2406. while (pScriptAction) {
  2407. chunkWriter.openDataChunk("ScriptActionFalse", K_SCRIPT_ACTION_VERSION_2);
  2408. chunkWriter.writeInt(pScriptAction->m_actionType);
  2409. const ActionTemplate* at = TheScriptEngine->getActionTemplate(pScriptAction->m_actionType);
  2410. if (at) {
  2411. chunkWriter.writeNameKey(at->m_internalNameKey);
  2412. } else {
  2413. DEBUG_CRASH(("Invalid action."));
  2414. chunkWriter.writeNameKey(NAMEKEY("Bogus"));
  2415. }
  2416. chunkWriter.writeInt(pScriptAction->m_numParms);
  2417. Int i;
  2418. for (i=0; i<pScriptAction->m_numParms; i++) {
  2419. pScriptAction->m_parms[i]->WriteParameter(chunkWriter);
  2420. }
  2421. chunkWriter.closeDataChunk();
  2422. pScriptAction = pScriptAction->getNext();
  2423. }
  2424. }
  2425. /**
  2426. * ScriptAction::ParseActionFalseDataChunk - read a false action chunk in a script list.
  2427. * Format is the newer CHUNKY format.
  2428. * See ScriptAction::WriteActionDataChunk for the writer.
  2429. * Input: DataChunkInput
  2430. *
  2431. */
  2432. Bool ScriptAction::ParseActionFalseDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData)
  2433. {
  2434. Script *pScript = (Script *)userData;
  2435. ScriptAction *pScriptAction = ParseAction(file, info, userData);
  2436. ScriptAction *pLast = pScript->getFalseAction();
  2437. while (pLast && pLast->getNext()) {
  2438. pLast = pLast->getNext();
  2439. }
  2440. if (pLast) {
  2441. pLast->setNextAction(pScriptAction);
  2442. } else {
  2443. pScript->setFalseAction(pScriptAction);
  2444. }
  2445. DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over."));
  2446. return true;
  2447. }
  2448. // NOTE: Changing these or adding ot TheOBjectFlagNames requires changes to
  2449. // ScriptActions::changeObjectPanelFlagForSingleObject
  2450. // THEY SHOULD STAY IN SYNC.
  2451. const char* TheObjectFlagsNames[] =
  2452. {
  2453. "Enabled",
  2454. "Powered",
  2455. "Indestructible",
  2456. "Unsellable",
  2457. "Selectable",
  2458. "AI Recruitable",
  2459. "Player Targetable",
  2460. NULL,
  2461. };