Scripts.cpp 70 KB

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