script.c 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // All rights reserved.
  5. //
  6. // Based on PALx Project by palxex.
  7. // Copyright (c) 2006-2008, Pal Lockheart <palxex@gmail.com>.
  8. //
  9. // This file is part of SDLPAL.
  10. //
  11. // SDLPAL is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 3 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. //
  24. // Modified by Lou Yihua <louyihua@21cn.com> with Unicode support, 2015
  25. //
  26. #include "main.h"
  27. BOOL g_fScriptSuccess = TRUE;
  28. static int g_iCurEquipPart = -1;
  29. static BOOL
  30. PAL_NPCWalkTo(
  31. WORD wEventObjectID,
  32. INT x,
  33. INT y,
  34. INT h,
  35. INT iSpeed
  36. )
  37. /*++
  38. Purpose:
  39. Make the specified event object walk to the map position specified by (x, y, h)
  40. at the speed of iSpeed.
  41. Parameters:
  42. [IN] wEventObjectID - the event object to move.
  43. [IN] x - Column number of the tile.
  44. [IN] y - Line number in the map.
  45. [IN] h - Each line in the map has two lines of tiles, 0 and 1.
  46. (See map.h for details.)
  47. [IN] iSpeed - the speed to move.
  48. Return value:
  49. TRUE if the event object has successfully moved to the specified position,
  50. FALSE if still need more moving.
  51. --*/
  52. {
  53. LPEVENTOBJECT pEvtObj;
  54. int xOffset, yOffset;
  55. pEvtObj = &(gpGlobals->g.lprgEventObject[wEventObjectID - 1]);
  56. xOffset = (x * 32 + h * 16) - pEvtObj->x;
  57. yOffset = (y * 16 + h * 8) - pEvtObj->y;
  58. if (yOffset < 0)
  59. {
  60. pEvtObj->wDirection = ((xOffset < 0) ? kDirWest : kDirNorth);
  61. }
  62. else
  63. {
  64. pEvtObj->wDirection = ((xOffset < 0) ? kDirSouth: kDirEast);
  65. }
  66. if (abs(xOffset) < iSpeed * 2 || abs(yOffset) < iSpeed * 2)
  67. {
  68. pEvtObj->x = x * 32 + h * 16;
  69. pEvtObj->y = y * 16 + h * 8;
  70. }
  71. else
  72. {
  73. PAL_NPCWalkOneStep(wEventObjectID, iSpeed);
  74. }
  75. if (pEvtObj->x == x * 32 + h * 16 && pEvtObj->y == y * 16 + h * 8)
  76. {
  77. pEvtObj->wCurrentFrameNum = 0;
  78. return TRUE;
  79. }
  80. return FALSE;
  81. }
  82. static VOID
  83. PAL_PartyWalkTo(
  84. INT x,
  85. INT y,
  86. INT h,
  87. INT iSpeed
  88. )
  89. /*++
  90. Purpose:
  91. Make the party walk to the map position specified by (x, y, h)
  92. at the speed of iSpeed.
  93. Parameters:
  94. [IN] x - Column number of the tile.
  95. [IN] y - Line number in the map.
  96. [IN] h - Each line in the map has two lines of tiles, 0 and 1.
  97. (See map.h for details.)
  98. [IN] iSpeed - the speed to move.
  99. Return value:
  100. None.
  101. --*/
  102. {
  103. int xOffset, yOffset, i, dx, dy;
  104. DWORD t;
  105. xOffset = x * 32 + h * 16 - PAL_X(gpGlobals->viewport) - PAL_X(gpGlobals->partyoffset);
  106. yOffset = y * 16 + h * 8 - PAL_Y(gpGlobals->viewport) - PAL_Y(gpGlobals->partyoffset);
  107. t = 0;
  108. while (xOffset != 0 || yOffset != 0)
  109. {
  110. PAL_ProcessEvent();
  111. while (SDL_GetTicks() <= t)
  112. {
  113. PAL_ProcessEvent();
  114. SDL_Delay(1);
  115. }
  116. t = SDL_GetTicks() + FRAME_TIME;
  117. //
  118. // Store trail
  119. //
  120. for (i = 3; i >= 0; i--)
  121. {
  122. gpGlobals->rgTrail[i + 1] = gpGlobals->rgTrail[i];
  123. }
  124. gpGlobals->rgTrail[0].wDirection = gpGlobals->wPartyDirection;
  125. gpGlobals->rgTrail[0].x = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset);
  126. gpGlobals->rgTrail[0].y = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset);
  127. if (yOffset < 0)
  128. {
  129. gpGlobals->wPartyDirection = ((xOffset < 0) ? kDirWest : kDirNorth);
  130. }
  131. else
  132. {
  133. gpGlobals->wPartyDirection = ((xOffset < 0) ? kDirSouth: kDirEast);
  134. }
  135. dx = PAL_X(gpGlobals->viewport);
  136. dy = PAL_Y(gpGlobals->viewport);
  137. if (abs(xOffset) <= iSpeed * 2)
  138. {
  139. dx += xOffset;
  140. }
  141. else
  142. {
  143. dx += iSpeed * (xOffset < 0 ? -2 : 2);
  144. }
  145. if (abs(yOffset) <= iSpeed)
  146. {
  147. dy += yOffset;
  148. }
  149. else
  150. {
  151. dy += iSpeed * (yOffset < 0 ? -1 : 1);
  152. }
  153. //
  154. // Move the viewport
  155. //
  156. gpGlobals->viewport = PAL_XY(dx, dy);
  157. PAL_UpdatePartyGestures(TRUE);
  158. PAL_GameUpdate(FALSE);
  159. PAL_MakeScene();
  160. VIDEO_UpdateScreen(NULL);
  161. xOffset = x * 32 + h * 16 - PAL_X(gpGlobals->viewport) - PAL_X(gpGlobals->partyoffset);
  162. yOffset = y * 16 + h * 8 - PAL_Y(gpGlobals->viewport) - PAL_Y(gpGlobals->partyoffset);
  163. }
  164. PAL_UpdatePartyGestures(FALSE);
  165. }
  166. static VOID
  167. PAL_PartyRideEventObject(
  168. WORD wEventObjectID,
  169. INT x,
  170. INT y,
  171. INT h,
  172. INT iSpeed
  173. )
  174. /*++
  175. Purpose:
  176. Move the party to the specified position, riding the specified event object.
  177. Parameters:
  178. [IN] wEventObjectID - the event object to be ridden.
  179. [IN] x - Column number of the tile.
  180. [IN] y - Line number in the map.
  181. [IN] h - Each line in the map has two lines of tiles, 0 and 1.
  182. (See map.h for details.)
  183. [IN] iSpeed - the speed to move.
  184. Return value:
  185. TRUE if the party and event object has successfully moved to the specified
  186. position, FALSE if still need more moving.
  187. --*/
  188. {
  189. int xOffset, yOffset, dx, dy, i;
  190. DWORD t;
  191. LPEVENTOBJECT p;
  192. p = &(gpGlobals->g.lprgEventObject[wEventObjectID - 1]);
  193. xOffset = x * 32 + h * 16 - PAL_X(gpGlobals->viewport) - PAL_X(gpGlobals->partyoffset);
  194. yOffset = y * 16 + h * 8 - PAL_Y(gpGlobals->viewport) - PAL_Y(gpGlobals->partyoffset);
  195. t = 0;
  196. while (xOffset != 0 || yOffset != 0)
  197. {
  198. PAL_ProcessEvent();
  199. while (SDL_GetTicks() <= t)
  200. {
  201. PAL_ProcessEvent();
  202. SDL_Delay(1);
  203. }
  204. t = SDL_GetTicks() + FRAME_TIME;
  205. if (yOffset < 0)
  206. {
  207. gpGlobals->wPartyDirection = ((xOffset < 0) ? kDirWest : kDirNorth);
  208. }
  209. else
  210. {
  211. gpGlobals->wPartyDirection = ((xOffset < 0) ? kDirSouth: kDirEast);
  212. }
  213. if (abs(xOffset) > iSpeed * 2)
  214. {
  215. dx = iSpeed * (xOffset < 0 ? -2 : 2);
  216. }
  217. else
  218. {
  219. dx = xOffset;
  220. }
  221. if (abs(yOffset) > iSpeed)
  222. {
  223. dy = iSpeed * (yOffset < 0 ? -1 : 1);
  224. }
  225. else
  226. {
  227. dy = yOffset;
  228. }
  229. //
  230. // Store trail
  231. //
  232. for (i = 3; i >= 0; i--)
  233. {
  234. gpGlobals->rgTrail[i + 1] = gpGlobals->rgTrail[i];
  235. }
  236. gpGlobals->rgTrail[0].wDirection = gpGlobals->wPartyDirection;
  237. gpGlobals->rgTrail[0].x = PAL_X(gpGlobals->viewport) + dx + PAL_X(gpGlobals->partyoffset);
  238. gpGlobals->rgTrail[0].y = PAL_Y(gpGlobals->viewport) + dy + PAL_Y(gpGlobals->partyoffset);
  239. //
  240. // Move the viewport
  241. //
  242. gpGlobals->viewport =
  243. PAL_XY(PAL_X(gpGlobals->viewport) + dx, PAL_Y(gpGlobals->viewport) + dy);
  244. p->x += dx;
  245. p->y += dy;
  246. PAL_GameUpdate(FALSE);
  247. PAL_MakeScene();
  248. VIDEO_UpdateScreen(NULL);
  249. xOffset = x * 32 + h * 16 - PAL_X(gpGlobals->viewport) - PAL_X(gpGlobals->partyoffset);
  250. yOffset = y * 16 + h * 8 - PAL_Y(gpGlobals->viewport) - PAL_Y(gpGlobals->partyoffset);
  251. }
  252. }
  253. static VOID
  254. PAL_MonsterChasePlayer(
  255. WORD wEventObjectID,
  256. WORD wSpeed,
  257. WORD wChaseRange,
  258. BOOL fFloating
  259. )
  260. /*++
  261. Purpose:
  262. Make the specified event object chase the players.
  263. Parameters:
  264. [IN] wEventObjectID - the event object ID of the monster.
  265. [IN] wSpeed - the speed of chasing.
  266. [IN] wChaseRange - sensitive range of the monster.
  267. [IN] fFloating - TRUE if monster is floating (i.e., ignore the obstacles)
  268. Return value:
  269. None.
  270. --*/
  271. {
  272. LPEVENTOBJECT pEvtObj = &gpGlobals->g.lprgEventObject[wEventObjectID - 1];
  273. WORD wMonsterSpeed = 0, prevx, prevy;
  274. int x, y, i, j, l;
  275. if (gpGlobals->wChaseRange != 0)
  276. {
  277. x = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset) - pEvtObj->x;
  278. y = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset) - pEvtObj->y;
  279. if (x == 0)
  280. {
  281. x = RandomLong(0, 1) ? -1 : 1;
  282. }
  283. if (y == 0)
  284. {
  285. y = RandomLong(0, 1) ? -1 : 1;
  286. }
  287. prevx = pEvtObj->x;
  288. prevy = pEvtObj->y;
  289. i = prevx % 32;
  290. j = prevy % 16;
  291. prevx /= 32;
  292. prevy /= 16;
  293. l = 0;
  294. if (i + j * 2 >= 16)
  295. {
  296. if (i + j * 2 >= 48)
  297. {
  298. prevx++;
  299. prevy++;
  300. }
  301. else if (32 - i + j * 2 < 16)
  302. {
  303. prevx++;
  304. }
  305. else if (32 - i + j * 2 < 48)
  306. {
  307. l = 1;
  308. }
  309. else
  310. {
  311. prevy++;
  312. }
  313. }
  314. prevx = prevx * 32 + l * 16;
  315. prevy = prevy * 16 + l * 8;
  316. //
  317. // Is the party near to the event object?
  318. //
  319. if (abs(x) + abs(y) * 2 < wChaseRange * 32 * gpGlobals->wChaseRange)
  320. {
  321. if (x < 0)
  322. {
  323. if (y < 0)
  324. {
  325. pEvtObj->wDirection = kDirWest;
  326. }
  327. else
  328. {
  329. pEvtObj->wDirection = kDirSouth;
  330. }
  331. }
  332. else
  333. {
  334. if (y < 0)
  335. {
  336. pEvtObj->wDirection = kDirNorth;
  337. }
  338. else
  339. {
  340. pEvtObj->wDirection = kDirEast;
  341. }
  342. }
  343. if (x != 0)
  344. {
  345. x = pEvtObj->x + x / abs(x) * 16;
  346. }
  347. else
  348. {
  349. x = pEvtObj->x;
  350. }
  351. if (y != 0)
  352. {
  353. y = pEvtObj->y + y / abs(y) * 8;
  354. }
  355. else
  356. {
  357. y = pEvtObj->y;
  358. }
  359. if (fFloating)
  360. {
  361. wMonsterSpeed = wSpeed;
  362. }
  363. else
  364. {
  365. if (!PAL_CheckObstacle(PAL_XY(x, y), TRUE, wEventObjectID))
  366. {
  367. wMonsterSpeed = wSpeed;
  368. }
  369. else
  370. {
  371. pEvtObj->x = prevx;
  372. pEvtObj->y = prevy;
  373. }
  374. for (l = 0; l < 4; l++)
  375. {
  376. switch (l)
  377. {
  378. case 0:
  379. pEvtObj->x -= 4;
  380. pEvtObj->y += 2;
  381. break;
  382. case 1:
  383. pEvtObj->x -= 4;
  384. pEvtObj->y -= 2;
  385. break;
  386. case 2:
  387. pEvtObj->x += 4;
  388. pEvtObj->y -= 2;
  389. break;
  390. case 3:
  391. pEvtObj->x += 4;
  392. pEvtObj->y += 2;
  393. break;
  394. }
  395. if (PAL_CheckObstacle(PAL_XY(pEvtObj->x, pEvtObj->y), FALSE, 0))
  396. {
  397. pEvtObj->x = prevx;
  398. pEvtObj->y = prevy;
  399. }
  400. }
  401. }
  402. }
  403. }
  404. PAL_NPCWalkOneStep(wEventObjectID, wMonsterSpeed);
  405. }
  406. static VOID
  407. PAL_AdditionalCredits(
  408. VOID
  409. )
  410. /*++
  411. Purpose:
  412. Show the additional credits.
  413. Parameters:
  414. None.
  415. Return value:
  416. None.
  417. --*/
  418. {
  419. LPCWSTR rgszcps[][CP_MAX] = {
  420. // Traditional Chinese, Simplified Chinese, Japanese
  421. { L"", L"", L"" },
  422. { L" (\x7D93\x5178\x7279\x5225\x7BC7", L" (\x7ECF\x5178\x7279\x522B\x7BC7", L"(\x30AF\x30E9\x30B7\x30C3\x30AF\x7279\x5225\x7DE8" },
  423. { L"", L"", L"" },
  424. { L"", L"", L"" },
  425. { L"", L"", L"" },
  426. #if defined(__SYMBIAN32__) || defined(GPH) || defined(GEKKO) || defined(DINGOO) || defined(ANDROID)
  427. { L"", L"", L"" },
  428. #endif
  429. { L"", L"", L"" },
  430. { L"\x672C\x7A0B\x5F0F\x662F\x81EA\x7531\x8EDF\x9AD4\xFF0C\x6309\x7167 GNU General",
  431. L"\x672C\x7A0B\x5E8F\x662F\x81EA\x7531\x8F6F\x4EF6\xFF0C\x6309\x7167 GNU General",
  432. L"\x3053\x306E\x30D7\x30ED\x30B0\x30E9\x30E0\x306F\x81EA\x7531\x30BD\x30D5\x30C8\x30A6\x30A7\x30A2\x3067"
  433. },
  434. { L"Public License v3 \x767C\x4F48", L"Public License v3 \x53D1\x5E03", L"\x3059\x3001GNU General Public License v3" },
  435. { L"", L"", L"\x306E\x4E0B\x3067\x914D\x5E03\x3055\x308C\x3066\x3044\x307E\x3059\x3002" },
  436. { L" ...\x6309 Enter \x7D50\x675F", L" ...\x6309 Enter \x7ED3\x675F", L"...Enter\x30AD\x30FC\x3092\x62BC\x3057\x3066\x7D42\x4E86\x3057\x307E\x3059" }
  437. };
  438. LPCWSTR rgszStrings[] = {
  439. L"SDLPAL (http://sdlpal.codeplex.com/)",
  440. # ifdef PAL_CLASSIC
  441. L" %s " WIDETEXT(__DATE__) L")",
  442. # else
  443. L" (" WIDETEXT(__DATE__) L")",
  444. # endif
  445. L" ",
  446. L" (c) 2009-2015, Wei Mingzhi",
  447. L" <whistler_wmz@users.sf.net>.",
  448. # ifdef __SYMBIAN32__
  449. L" Symbian S60 \x79FB\x690D (c) 2009, netwan.",
  450. # endif
  451. # ifdef GPH
  452. L" GPH Caanoo & Wiz \x79FB\x690D (c) 2011, Rikku2000.",
  453. # endif
  454. # ifdef GEKKO
  455. L" Nintendo WII \x79FB\x690D (c) 2012, Rikku2000.",
  456. # endif
  457. # ifdef DINGOO
  458. L" DINGOO & Dingux \x79FB\x690D (c) 2011, Rikku2000.",
  459. # endif
  460. # ifdef ANDROID
  461. L" ANDROID \x79FB\x690D (c) 2013, Rikku2000.",
  462. # endif
  463. L" ",
  464. L"%s",
  465. L"%s",
  466. L"%s",
  467. L" %s",
  468. NULL
  469. };
  470. int i = 0;
  471. PAL_DrawOpeningMenuBackground();
  472. for (i = 0; rgszStrings[i]; i++)
  473. {
  474. WCHAR buffer[50];
  475. swprintf(buffer, 50, rgszStrings[i], rgszcps[i][gpGlobals->iCodePage]);
  476. PAL_DrawText(buffer, PAL_XY(25, 20 + i * 16), DESCTEXT_COLOR, TRUE, FALSE);
  477. }
  478. PAL_SetPalette(0, FALSE);
  479. VIDEO_UpdateScreen(NULL);
  480. PAL_WaitForKey(0);
  481. }
  482. static WORD
  483. PAL_InterpretInstruction(
  484. WORD wScriptEntry,
  485. WORD wEventObjectID
  486. )
  487. /*++
  488. Purpose:
  489. Interpret and execute one instruction in the script.
  490. Parameters:
  491. [IN] wScriptEntry - The script entry to execute.
  492. [IN] wEventObjectID - The event object ID which invoked the script.
  493. Return value:
  494. The address of the next script instruction to execute.
  495. --*/
  496. {
  497. LPEVENTOBJECT pEvtObj, pCurrent;
  498. LPSCRIPTENTRY pScript;
  499. int iPlayerRole, i, j, x, y;
  500. WORD w, wCurEventObjectID;
  501. pScript = &(gpGlobals->g.lprgScriptEntry[wScriptEntry]);
  502. if (wEventObjectID != 0)
  503. {
  504. pEvtObj = &(gpGlobals->g.lprgEventObject[wEventObjectID - 1]);
  505. }
  506. else
  507. {
  508. pEvtObj = NULL;
  509. }
  510. if (pScript->rgwOperand[0] == 0 || pScript->rgwOperand[0] == 0xFFFF)
  511. {
  512. pCurrent = pEvtObj;
  513. wCurEventObjectID = wEventObjectID;
  514. }
  515. else
  516. {
  517. i = pScript->rgwOperand[0] - 1;
  518. if (i > 0x9000)
  519. {
  520. // HACK for Dream 2.11 to avoid crash
  521. i -= 0x9000;
  522. }
  523. pCurrent = &(gpGlobals->g.lprgEventObject[i]);
  524. wCurEventObjectID = pScript->rgwOperand[0];
  525. }
  526. if (pScript->rgwOperand[0] < MAX_PLAYABLE_PLAYER_ROLES)
  527. {
  528. iPlayerRole = gpGlobals->rgParty[pScript->rgwOperand[0]].wPlayerRole;
  529. }
  530. else
  531. {
  532. iPlayerRole = gpGlobals->rgParty[0].wPlayerRole;
  533. }
  534. switch (pScript->wOperation)
  535. {
  536. case 0x000B:
  537. case 0x000C:
  538. case 0x000D:
  539. case 0x000E:
  540. //
  541. // walk one step
  542. //
  543. pEvtObj->wDirection = pScript->wOperation - 0x000B;
  544. PAL_NPCWalkOneStep(wEventObjectID, 2);
  545. break;
  546. case 0x000F:
  547. //
  548. // Set the direction and/or gesture for event object
  549. //
  550. if (pScript->rgwOperand[0] != 0xFFFF)
  551. {
  552. pEvtObj->wDirection = pScript->rgwOperand[0];
  553. }
  554. if (pScript->rgwOperand[1] != 0xFFFF)
  555. {
  556. pEvtObj->wCurrentFrameNum = pScript->rgwOperand[1];
  557. }
  558. break;
  559. case 0x0010:
  560. //
  561. // Walk straight to the specified position
  562. //
  563. if (!PAL_NPCWalkTo(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  564. pScript->rgwOperand[2], 3))
  565. {
  566. wScriptEntry--;
  567. }
  568. break;
  569. case 0x0011:
  570. //
  571. // Walk straight to the specified position, at a lower speed
  572. //
  573. if ((wEventObjectID & 1) ^ (gpGlobals->dwFrameNum & 1))
  574. {
  575. if (!PAL_NPCWalkTo(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  576. pScript->rgwOperand[2], 2))
  577. {
  578. wScriptEntry--;
  579. }
  580. }
  581. else
  582. {
  583. wScriptEntry--;
  584. }
  585. break;
  586. case 0x0012:
  587. //
  588. // Set the position of the event object, relative to the party
  589. //
  590. pCurrent->x =
  591. pScript->rgwOperand[1] + PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset);
  592. pCurrent->y =
  593. pScript->rgwOperand[2] + PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset);
  594. break;
  595. case 0x0013:
  596. //
  597. // Set the position of the event object
  598. //
  599. pCurrent->x = pScript->rgwOperand[1];
  600. pCurrent->y = pScript->rgwOperand[2];
  601. break;
  602. case 0x0014:
  603. //
  604. // Set the gesture of the event object
  605. //
  606. pEvtObj->wCurrentFrameNum = pScript->rgwOperand[0];
  607. pEvtObj->wDirection = kDirSouth;
  608. break;
  609. case 0x0015:
  610. //
  611. // Set the direction and gesture for a party member
  612. //
  613. gpGlobals->wPartyDirection = pScript->rgwOperand[0];
  614. gpGlobals->rgParty[pScript->rgwOperand[2]].wFrame =
  615. gpGlobals->wPartyDirection * 3 + pScript->rgwOperand[1];
  616. break;
  617. case 0x0016:
  618. //
  619. // Set the direction and gesture for an event object
  620. //
  621. if (pScript->rgwOperand[0] != 0)
  622. {
  623. pCurrent->wDirection = pScript->rgwOperand[1];
  624. pCurrent->wCurrentFrameNum = pScript->rgwOperand[2];
  625. }
  626. break;
  627. case 0x0017:
  628. //
  629. // set the player's extra attribute
  630. //
  631. {
  632. WORD *p;
  633. i = pScript->rgwOperand[0] - 0xB;
  634. p = (WORD *)(&gpGlobals->rgEquipmentEffect[i]); // HACKHACK
  635. p[pScript->rgwOperand[1] * MAX_PLAYER_ROLES + wEventObjectID] =
  636. (SHORT)pScript->rgwOperand[2];
  637. }
  638. break;
  639. case 0x0018:
  640. //
  641. // Equip the selected item
  642. //
  643. i = pScript->rgwOperand[0] - 0x0B;
  644. g_iCurEquipPart = i;
  645. //
  646. // The wEventObjectID parameter here should indicate the player role
  647. //
  648. PAL_RemoveEquipmentEffect(wEventObjectID, i);
  649. if (gpGlobals->g.PlayerRoles.rgwEquipment[i][wEventObjectID] != pScript->rgwOperand[1])
  650. {
  651. w = gpGlobals->g.PlayerRoles.rgwEquipment[i][wEventObjectID];
  652. gpGlobals->g.PlayerRoles.rgwEquipment[i][wEventObjectID] = pScript->rgwOperand[1];
  653. PAL_AddItemToInventory(pScript->rgwOperand[1], -1);
  654. if (w != 0)
  655. {
  656. PAL_AddItemToInventory(w, 1);
  657. }
  658. gpGlobals->wLastUnequippedItem = w;
  659. }
  660. break;
  661. case 0x0019:
  662. //
  663. // Increase/decrease the player's attribute
  664. //
  665. {
  666. WORD *p = (WORD *)(&gpGlobals->g.PlayerRoles); // HACKHACK
  667. if (pScript->rgwOperand[2] == 0)
  668. {
  669. iPlayerRole = wEventObjectID;
  670. }
  671. else
  672. {
  673. iPlayerRole = pScript->rgwOperand[2] - 1;
  674. }
  675. p[pScript->rgwOperand[0] * MAX_PLAYER_ROLES + iPlayerRole] +=
  676. (SHORT)pScript->rgwOperand[1];
  677. }
  678. break;
  679. case 0x001A:
  680. //
  681. // Set player's stat
  682. //
  683. {
  684. WORD *p = (WORD *)(&gpGlobals->g.PlayerRoles); // HACKHACK
  685. if (g_iCurEquipPart != -1)
  686. {
  687. //
  688. // In the progress of equipping items
  689. //
  690. p = (WORD *)&(gpGlobals->rgEquipmentEffect[g_iCurEquipPart]);
  691. }
  692. if (pScript->rgwOperand[2] == 0)
  693. {
  694. //
  695. // Apply to the current player. The wEventObjectID should
  696. // indicate the player role.
  697. //
  698. iPlayerRole = wEventObjectID;
  699. }
  700. else
  701. {
  702. iPlayerRole = pScript->rgwOperand[2] - 1;
  703. }
  704. p[pScript->rgwOperand[0] * MAX_PLAYER_ROLES + iPlayerRole] =
  705. (SHORT)pScript->rgwOperand[1];
  706. }
  707. break;
  708. case 0x001B:
  709. //
  710. // Increase/decrease player's HP
  711. //
  712. if (pScript->rgwOperand[0])
  713. {
  714. //
  715. // Apply to everyone
  716. //
  717. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  718. {
  719. w = gpGlobals->rgParty[i].wPlayerRole;
  720. PAL_IncreaseHPMP(w, (SHORT)(pScript->rgwOperand[1]), 0);
  721. }
  722. }
  723. else
  724. {
  725. //
  726. // Apply to one player. The wEventObjectID parameter should indicate the player role.
  727. //
  728. if (!PAL_IncreaseHPMP(wEventObjectID, (SHORT)(pScript->rgwOperand[1]), 0))
  729. {
  730. g_fScriptSuccess = FALSE;
  731. }
  732. }
  733. break;
  734. case 0x001C:
  735. //
  736. // Increase/decrease player's MP
  737. //
  738. if (pScript->rgwOperand[0])
  739. {
  740. //
  741. // Apply to everyone
  742. //
  743. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  744. {
  745. w = gpGlobals->rgParty[i].wPlayerRole;
  746. PAL_IncreaseHPMP(w, 0, (SHORT)(pScript->rgwOperand[1]));
  747. }
  748. }
  749. else
  750. {
  751. //
  752. // Apply to one player. The wEventObjectID parameter should indicate the player role.
  753. //
  754. if (!PAL_IncreaseHPMP(wEventObjectID, 0, (SHORT)(pScript->rgwOperand[1])))
  755. {
  756. g_fScriptSuccess = FALSE;
  757. }
  758. }
  759. break;
  760. case 0x001D:
  761. //
  762. // Increase/decrease player's HP and MP
  763. //
  764. if (pScript->rgwOperand[0])
  765. {
  766. //
  767. // Apply to everyone
  768. //
  769. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  770. {
  771. w = gpGlobals->rgParty[i].wPlayerRole;
  772. PAL_IncreaseHPMP(w,
  773. (SHORT)(pScript->rgwOperand[1]), (SHORT)(pScript->rgwOperand[1]));
  774. }
  775. }
  776. else
  777. {
  778. //
  779. // Apply to one player. The wEventObjectID parameter should indicate the player role.
  780. //
  781. if (!PAL_IncreaseHPMP(wEventObjectID,
  782. (SHORT)(pScript->rgwOperand[1]), (SHORT)(pScript->rgwOperand[1])))
  783. {
  784. g_fScriptSuccess = FALSE;
  785. }
  786. }
  787. break;
  788. case 0x001E:
  789. //
  790. // Increase or decrease cash by the specified amount
  791. //
  792. if ((SHORT)(pScript->rgwOperand[0]) < 0 &&
  793. gpGlobals->dwCash < (WORD)(-(SHORT)(pScript->rgwOperand[0])))
  794. {
  795. //
  796. // not enough cash
  797. //
  798. wScriptEntry = pScript->rgwOperand[1] - 1;
  799. }
  800. else
  801. {
  802. gpGlobals->dwCash += (SHORT)(pScript->rgwOperand[0]);
  803. }
  804. break;
  805. case 0x001F:
  806. //
  807. // Add item to inventory
  808. //
  809. PAL_AddItemToInventory(pScript->rgwOperand[0], (SHORT)(pScript->rgwOperand[1]));
  810. break;
  811. case 0x0020:
  812. //
  813. // Remove item from inventory
  814. //
  815. if (!PAL_AddItemToInventory(pScript->rgwOperand[0],
  816. -((pScript->rgwOperand[1] == 0) ? 1 : pScript->rgwOperand[1])))
  817. {
  818. //
  819. // Try removing equipped item
  820. //
  821. x = pScript->rgwOperand[1];
  822. if (x == 0)
  823. {
  824. x = 1;
  825. }
  826. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  827. {
  828. w = gpGlobals->rgParty[i].wPlayerRole;
  829. for (j = 0; j < MAX_PLAYER_EQUIPMENTS; j++)
  830. {
  831. if (gpGlobals->g.PlayerRoles.rgwEquipment[j][w] == pScript->rgwOperand[0])
  832. {
  833. PAL_RemoveEquipmentEffect(w, j);
  834. gpGlobals->g.PlayerRoles.rgwEquipment[j][w] = 0;
  835. if (--x == 0)
  836. {
  837. i = 9999;
  838. break;
  839. }
  840. }
  841. }
  842. }
  843. if (x > 0 && pScript->rgwOperand[2] != 0)
  844. {
  845. wScriptEntry = pScript->rgwOperand[2] - 1;
  846. }
  847. }
  848. break;
  849. case 0x0021:
  850. //
  851. // Inflict damage to the enemy
  852. //
  853. if (pScript->rgwOperand[0])
  854. {
  855. //
  856. // Inflict damage to all enemies
  857. //
  858. for (i = 0;i <= g_Battle.wMaxEnemyIndex; i++)
  859. {
  860. if (g_Battle.rgEnemy[i].wObjectID != 0)
  861. {
  862. g_Battle.rgEnemy[i].e.wHealth -= pScript->rgwOperand[1];
  863. }
  864. }
  865. }
  866. else
  867. {
  868. //
  869. // Inflict damage to one enemy
  870. //
  871. g_Battle.rgEnemy[wEventObjectID].e.wHealth -= pScript->rgwOperand[1];
  872. }
  873. break;
  874. case 0x0022:
  875. //
  876. // Revive player
  877. //
  878. if (pScript->rgwOperand[0])
  879. {
  880. //
  881. // Apply to everyone
  882. //
  883. g_fScriptSuccess = FALSE;
  884. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  885. {
  886. w = gpGlobals->rgParty[i].wPlayerRole;
  887. if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0)
  888. {
  889. gpGlobals->g.PlayerRoles.rgwHP[w] =
  890. gpGlobals->g.PlayerRoles.rgwMaxHP[w] * pScript->rgwOperand[1] / 10;
  891. PAL_CurePoisonByLevel(w, 3);
  892. for (x = 0; x < kStatusAll; x++)
  893. {
  894. PAL_RemovePlayerStatus(w, x);
  895. }
  896. g_fScriptSuccess = TRUE;
  897. }
  898. }
  899. }
  900. else
  901. {
  902. //
  903. // Apply to one player
  904. //
  905. if (gpGlobals->g.PlayerRoles.rgwHP[wEventObjectID] == 0)
  906. {
  907. gpGlobals->g.PlayerRoles.rgwHP[wEventObjectID] =
  908. gpGlobals->g.PlayerRoles.rgwMaxHP[wEventObjectID] * pScript->rgwOperand[1] / 10;
  909. PAL_CurePoisonByLevel(wEventObjectID, 3);
  910. for (x = 0; x < kStatusAll; x++)
  911. {
  912. PAL_RemovePlayerStatus(wEventObjectID, x);
  913. }
  914. }
  915. else
  916. {
  917. g_fScriptSuccess = FALSE;
  918. }
  919. }
  920. break;
  921. case 0x0023:
  922. //
  923. // Remove equipment from the specified player
  924. //
  925. if (pScript->rgwOperand[1] == 0)
  926. {
  927. //
  928. // Remove all equipments
  929. //
  930. for (i = 0; i < MAX_PLAYER_EQUIPMENTS; i++)
  931. {
  932. w = gpGlobals->g.PlayerRoles.rgwEquipment[i][iPlayerRole];
  933. if (w != 0)
  934. {
  935. PAL_AddItemToInventory(w, 1);
  936. gpGlobals->g.PlayerRoles.rgwEquipment[i][iPlayerRole] = 0;
  937. }
  938. PAL_RemoveEquipmentEffect(iPlayerRole, i);
  939. }
  940. }
  941. else
  942. {
  943. w = gpGlobals->g.PlayerRoles.rgwEquipment[pScript->rgwOperand[1] - 1][iPlayerRole];
  944. if (w != 0)
  945. {
  946. PAL_RemoveEquipmentEffect(iPlayerRole, pScript->rgwOperand[1] - 1);
  947. PAL_AddItemToInventory(w, 1);
  948. gpGlobals->g.PlayerRoles.rgwEquipment[pScript->rgwOperand[1] - 1][iPlayerRole] = 0;
  949. }
  950. }
  951. break;
  952. case 0x0024:
  953. //
  954. // Set the autoscript entry address for an event object
  955. //
  956. if (pScript->rgwOperand[0] != 0)
  957. {
  958. pCurrent->wAutoScript = pScript->rgwOperand[1];
  959. }
  960. break;
  961. case 0x0025:
  962. //
  963. // Set the trigger script entry address for an event object
  964. //
  965. if (pScript->rgwOperand[0] != 0)
  966. {
  967. pCurrent->wTriggerScript = pScript->rgwOperand[1];
  968. }
  969. break;
  970. case 0x0026:
  971. //
  972. // Show the buy item menu
  973. //
  974. PAL_MakeScene();
  975. VIDEO_UpdateScreen(NULL);
  976. PAL_BuyMenu(pScript->rgwOperand[0]);
  977. break;
  978. case 0x0027:
  979. //
  980. // Show the sell item menu
  981. //
  982. PAL_MakeScene();
  983. VIDEO_UpdateScreen(NULL);
  984. PAL_SellMenu();
  985. break;
  986. case 0x0028:
  987. //
  988. // Apply poison to enemy
  989. //
  990. if (pScript->rgwOperand[0])
  991. {
  992. //
  993. // Apply to everyone
  994. //
  995. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  996. {
  997. w = g_Battle.rgEnemy[i].wObjectID;
  998. if (w == 0)
  999. {
  1000. continue;
  1001. }
  1002. if (RandomLong(0, 9) >=
  1003. gpGlobals->g.rgObject[w].enemy.wResistanceToSorcery)
  1004. {
  1005. for (j = 0; j < MAX_POISONS; j++)
  1006. {
  1007. if (g_Battle.rgEnemy[i].rgPoisons[j].wPoisonID ==
  1008. pScript->rgwOperand[1])
  1009. {
  1010. break;
  1011. }
  1012. }
  1013. if (j >= MAX_POISONS)
  1014. {
  1015. for (j = 0; j < MAX_POISONS; j++)
  1016. {
  1017. if (g_Battle.rgEnemy[i].rgPoisons[j].wPoisonID == 0)
  1018. {
  1019. g_Battle.rgEnemy[i].rgPoisons[j].wPoisonID = pScript->rgwOperand[1];
  1020. g_Battle.rgEnemy[i].rgPoisons[j].wPoisonScript =
  1021. PAL_RunTriggerScript(gpGlobals->g.rgObject[pScript->rgwOperand[1]].poison.wEnemyScript, wEventObjectID);
  1022. break;
  1023. }
  1024. }
  1025. }
  1026. }
  1027. }
  1028. }
  1029. else
  1030. {
  1031. //
  1032. // Apply to one enemy
  1033. //
  1034. w = g_Battle.rgEnemy[wEventObjectID].wObjectID;
  1035. if (RandomLong(0, 9) >=
  1036. gpGlobals->g.rgObject[w].enemy.wResistanceToSorcery)
  1037. {
  1038. for (j = 0; j < MAX_POISONS; j++)
  1039. {
  1040. if (g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonID ==
  1041. pScript->rgwOperand[1])
  1042. {
  1043. break;
  1044. }
  1045. }
  1046. if (j >= MAX_POISONS)
  1047. {
  1048. for (j = 0; j < MAX_POISONS; j++)
  1049. {
  1050. if (g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonID == 0)
  1051. {
  1052. g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonID = pScript->rgwOperand[1];
  1053. g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonScript =
  1054. PAL_RunTriggerScript(gpGlobals->g.rgObject[pScript->rgwOperand[1]].poison.wEnemyScript, wEventObjectID);
  1055. break;
  1056. }
  1057. }
  1058. }
  1059. }
  1060. }
  1061. break;
  1062. case 0x0029:
  1063. //
  1064. // Apply poison to player
  1065. //
  1066. if (pScript->rgwOperand[0])
  1067. {
  1068. //
  1069. // Apply to everyone
  1070. //
  1071. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  1072. {
  1073. w = gpGlobals->rgParty[i].wPlayerRole;
  1074. if (RandomLong(1, 100) > PAL_GetPlayerPoisonResistance(w))
  1075. {
  1076. PAL_AddPoisonForPlayer(w, pScript->rgwOperand[1]);
  1077. }
  1078. }
  1079. }
  1080. else
  1081. {
  1082. //
  1083. // Apply to one player
  1084. //
  1085. if (RandomLong(1, 100) > PAL_GetPlayerPoisonResistance(wEventObjectID))
  1086. {
  1087. PAL_AddPoisonForPlayer(wEventObjectID, pScript->rgwOperand[1]);
  1088. }
  1089. }
  1090. break;
  1091. case 0x002A:
  1092. //
  1093. // Cure poison by object ID for enemy
  1094. //
  1095. if (pScript->rgwOperand[0])
  1096. {
  1097. //
  1098. // Apply to all enemies
  1099. //
  1100. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  1101. {
  1102. if (g_Battle.rgEnemy[i].wObjectID == 0)
  1103. {
  1104. continue;
  1105. }
  1106. for (j = 0; j < MAX_POISONS; j++)
  1107. {
  1108. if (g_Battle.rgEnemy[i].rgPoisons[j].wPoisonID == pScript->rgwOperand[1])
  1109. {
  1110. g_Battle.rgEnemy[i].rgPoisons[j].wPoisonID = 0;
  1111. g_Battle.rgEnemy[i].rgPoisons[j].wPoisonScript = 0;
  1112. break;
  1113. }
  1114. }
  1115. }
  1116. }
  1117. else
  1118. {
  1119. //
  1120. // Apply to one enemy
  1121. //
  1122. for (j = 0; j < MAX_POISONS; j++)
  1123. {
  1124. if (g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonID == pScript->rgwOperand[1])
  1125. {
  1126. g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonID = 0;
  1127. g_Battle.rgEnemy[wEventObjectID].rgPoisons[j].wPoisonScript = 0;
  1128. break;
  1129. }
  1130. }
  1131. }
  1132. break;
  1133. case 0x002B:
  1134. //
  1135. // Cure poison by object ID for player
  1136. //
  1137. if (pScript->rgwOperand[0])
  1138. {
  1139. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  1140. {
  1141. w = gpGlobals->rgParty[i].wPlayerRole;
  1142. PAL_CurePoisonByKind(w, pScript->rgwOperand[1]);
  1143. }
  1144. }
  1145. else
  1146. {
  1147. PAL_CurePoisonByKind(wEventObjectID, pScript->rgwOperand[1]);
  1148. }
  1149. break;
  1150. case 0x002C:
  1151. //
  1152. // Cure poisons by level
  1153. //
  1154. if (pScript->rgwOperand[0])
  1155. {
  1156. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  1157. {
  1158. w = gpGlobals->rgParty[i].wPlayerRole;
  1159. PAL_CurePoisonByLevel(w, pScript->rgwOperand[1]);
  1160. }
  1161. }
  1162. else
  1163. {
  1164. PAL_CurePoisonByLevel(wEventObjectID, pScript->rgwOperand[1]);
  1165. }
  1166. break;
  1167. case 0x002D:
  1168. //
  1169. // Set the status for player
  1170. //
  1171. PAL_SetPlayerStatus(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1]);
  1172. break;
  1173. case 0x002E:
  1174. //
  1175. // Set the status for enemy
  1176. //
  1177. w = g_Battle.rgEnemy[wEventObjectID].wObjectID;
  1178. #ifdef PAL_CLASSIC
  1179. i = 9;
  1180. #else
  1181. i = ((pScript->rgwOperand[0] == kStatusSlow) ? 14 : 9);
  1182. #endif
  1183. if (RandomLong(0, i) >= gpGlobals->g.rgObject[w].enemy.wResistanceToSorcery &&
  1184. g_Battle.rgEnemy[wEventObjectID].rgwStatus[pScript->rgwOperand[0]] == 0)
  1185. {
  1186. g_Battle.rgEnemy[wEventObjectID].rgwStatus[pScript->rgwOperand[0]] = pScript->rgwOperand[1];
  1187. }
  1188. else
  1189. {
  1190. wScriptEntry = pScript->rgwOperand[2] - 1;
  1191. }
  1192. break;
  1193. case 0x002F:
  1194. //
  1195. // Remove player's status
  1196. //
  1197. PAL_RemovePlayerStatus(wEventObjectID, pScript->rgwOperand[0]);
  1198. break;
  1199. case 0x0030:
  1200. //
  1201. // Increase player's stat temporarily by percent
  1202. //
  1203. {
  1204. WORD *p = (WORD *)(&gpGlobals->rgEquipmentEffect[kBodyPartExtra]); // HACKHACK
  1205. WORD *p1 = (WORD *)(&gpGlobals->g.PlayerRoles);
  1206. if (pScript->rgwOperand[2] == 0)
  1207. {
  1208. iPlayerRole = wEventObjectID;
  1209. }
  1210. else
  1211. {
  1212. iPlayerRole = pScript->rgwOperand[2] - 1;
  1213. }
  1214. p[pScript->rgwOperand[0] * MAX_PLAYER_ROLES + iPlayerRole] =
  1215. p1[pScript->rgwOperand[0] * MAX_PLAYER_ROLES + iPlayerRole] *
  1216. (SHORT)pScript->rgwOperand[1] / 100;
  1217. }
  1218. break;
  1219. case 0x0031:
  1220. //
  1221. // Change battle sprite temporarily for player
  1222. //
  1223. gpGlobals->rgEquipmentEffect[kBodyPartExtra].rgwSpriteNumInBattle[wEventObjectID] =
  1224. pScript->rgwOperand[0];
  1225. break;
  1226. case 0x0033:
  1227. //
  1228. // collect the enemy for items
  1229. //
  1230. if (g_Battle.rgEnemy[wEventObjectID].e.wCollectValue != 0)
  1231. {
  1232. gpGlobals->wCollectValue +=
  1233. g_Battle.rgEnemy[wEventObjectID].e.wCollectValue;
  1234. }
  1235. else
  1236. {
  1237. wScriptEntry = pScript->rgwOperand[0] - 1;
  1238. }
  1239. break;
  1240. case 0x0034:
  1241. //
  1242. // Transform collected enemies into items
  1243. //
  1244. if (gpGlobals->wCollectValue > 0)
  1245. {
  1246. WCHAR s[256];
  1247. #ifdef PAL_CLASSIC
  1248. i = RandomLong(1, gpGlobals->wCollectValue);
  1249. if (i > 9)
  1250. {
  1251. i = 9;
  1252. }
  1253. #else
  1254. i = RandomLong(1, 9);
  1255. if (i > gpGlobals->wCollectValue)
  1256. {
  1257. i = gpGlobals->wCollectValue;
  1258. }
  1259. #endif
  1260. gpGlobals->wCollectValue -= i;
  1261. i--;
  1262. PAL_AddItemToInventory(gpGlobals->g.lprgStore[0].rgwItems[i], 1);
  1263. PAL_StartDialog(kDialogCenterWindow, 0, 0, FALSE);
  1264. wcscpy(s, PAL_GetWord(42));
  1265. wcscat(s, PAL_GetWord(gpGlobals->g.lprgStore[0].rgwItems[i]));
  1266. PAL_ShowDialogText(s);
  1267. }
  1268. else
  1269. {
  1270. wScriptEntry = pScript->rgwOperand[0] - 1;
  1271. }
  1272. break;
  1273. case 0x0035:
  1274. //
  1275. // Shake the screen
  1276. //
  1277. i = pScript->rgwOperand[1];
  1278. if (i == 0)
  1279. {
  1280. i = 4;
  1281. }
  1282. VIDEO_ShakeScreen(pScript->rgwOperand[0], i);
  1283. if (!pScript->rgwOperand[0])
  1284. {
  1285. VIDEO_UpdateScreen(NULL);
  1286. }
  1287. break;
  1288. case 0x0036:
  1289. //
  1290. // Set the current playing RNG animation
  1291. //
  1292. gpGlobals->iCurPlayingRNG = pScript->rgwOperand[0];
  1293. break;
  1294. case 0x0037:
  1295. //
  1296. // Play RNG animation
  1297. //
  1298. PAL_RNGPlay(gpGlobals->iCurPlayingRNG,
  1299. pScript->rgwOperand[0],
  1300. pScript->rgwOperand[1] > 0 ? pScript->rgwOperand[1] : 999,
  1301. pScript->rgwOperand[2] > 0 ? pScript->rgwOperand[2] : 16);
  1302. break;
  1303. case 0x0038:
  1304. //
  1305. // Teleport the party out of the scene
  1306. //
  1307. if (!gpGlobals->fInBattle &&
  1308. gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wScriptOnTeleport != 0)
  1309. {
  1310. gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wScriptOnTeleport =
  1311. PAL_RunTriggerScript(gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wScriptOnTeleport, 0xFFFF);
  1312. }
  1313. else
  1314. {
  1315. //
  1316. // failed
  1317. //
  1318. g_fScriptSuccess = FALSE;
  1319. wScriptEntry = pScript->rgwOperand[0] - 1;
  1320. }
  1321. break;
  1322. case 0x0039:
  1323. //
  1324. // Drain HP from enemy
  1325. //
  1326. w = gpGlobals->rgParty[g_Battle.wMovingPlayerIndex].wPlayerRole;
  1327. g_Battle.rgEnemy[wEventObjectID].e.wHealth -= pScript->rgwOperand[0];
  1328. gpGlobals->g.PlayerRoles.rgwHP[w] += pScript->rgwOperand[0];
  1329. if (gpGlobals->g.PlayerRoles.rgwHP[w] > gpGlobals->g.PlayerRoles.rgwMaxHP[w])
  1330. {
  1331. gpGlobals->g.PlayerRoles.rgwHP[w] = gpGlobals->g.PlayerRoles.rgwMaxHP[w];
  1332. }
  1333. break;
  1334. case 0x003A:
  1335. //
  1336. // Player flee from the battle
  1337. //
  1338. if (g_Battle.fIsBoss)
  1339. {
  1340. //
  1341. // Cannot flee from bosses
  1342. //
  1343. wScriptEntry = pScript->rgwOperand[0] - 1;
  1344. }
  1345. else
  1346. {
  1347. PAL_BattlePlayerEscape();
  1348. }
  1349. break;
  1350. case 0x003F:
  1351. //
  1352. // Ride the event object to the specified position, at a low speed
  1353. //
  1354. PAL_PartyRideEventObject(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  1355. pScript->rgwOperand[2], 2);
  1356. break;
  1357. case 0x0040:
  1358. //
  1359. // set the trigger method for a event object
  1360. //
  1361. if (pScript->rgwOperand[0] != 0)
  1362. {
  1363. pCurrent->wTriggerMode = pScript->rgwOperand[1];
  1364. }
  1365. break;
  1366. case 0x0041:
  1367. //
  1368. // Mark the script as failed
  1369. //
  1370. g_fScriptSuccess = FALSE;
  1371. break;
  1372. case 0x0042:
  1373. //
  1374. // Simulate a magic for player
  1375. //
  1376. i = (SHORT)(pScript->rgwOperand[2]) - 1;
  1377. if (i < 0)
  1378. {
  1379. i = wEventObjectID;
  1380. }
  1381. PAL_BattleSimulateMagic(i, pScript->rgwOperand[0], pScript->rgwOperand[1]);
  1382. break;
  1383. case 0x0043:
  1384. //
  1385. // Set background music
  1386. //
  1387. gpGlobals->wNumMusic = pScript->rgwOperand[0];
  1388. SOUND_PlayMUS(pScript->rgwOperand[0], (pScript->rgwOperand[0] != 0x3D), pScript->rgwOperand[1]);
  1389. break;
  1390. case 0x0044:
  1391. //
  1392. // Ride the event object to the specified position, at the normal speed
  1393. //
  1394. PAL_PartyRideEventObject(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  1395. pScript->rgwOperand[2], 4);
  1396. break;
  1397. case 0x0045:
  1398. //
  1399. // Set battle music
  1400. //
  1401. gpGlobals->wNumBattleMusic = pScript->rgwOperand[0];
  1402. break;
  1403. case 0x0046:
  1404. //
  1405. // Set the party position on the map
  1406. //
  1407. {
  1408. int xOffset, yOffset, x, y;
  1409. xOffset =
  1410. ((gpGlobals->wPartyDirection == kDirWest || gpGlobals->wPartyDirection == kDirSouth)
  1411. ? 16 : -16);
  1412. yOffset =
  1413. ((gpGlobals->wPartyDirection == kDirWest || gpGlobals->wPartyDirection == kDirNorth)
  1414. ? 8 : -8);
  1415. x = pScript->rgwOperand[0] * 32 + pScript->rgwOperand[2] * 16;
  1416. y = pScript->rgwOperand[1] * 16 + pScript->rgwOperand[2] * 8;
  1417. x -= PAL_X(gpGlobals->partyoffset);
  1418. y -= PAL_Y(gpGlobals->partyoffset);
  1419. gpGlobals->viewport = PAL_XY(x, y);
  1420. x = PAL_X(gpGlobals->partyoffset);
  1421. y = PAL_Y(gpGlobals->partyoffset);
  1422. for (i = 0; i < MAX_PLAYABLE_PLAYER_ROLES; i++)
  1423. {
  1424. gpGlobals->rgParty[i].x = x;
  1425. gpGlobals->rgParty[i].y = y;
  1426. gpGlobals->rgTrail[i].x = x + PAL_X(gpGlobals->viewport);
  1427. gpGlobals->rgTrail[i].y = y + PAL_Y(gpGlobals->viewport);
  1428. gpGlobals->rgTrail[i].wDirection = gpGlobals->wPartyDirection;
  1429. x += xOffset;
  1430. y += yOffset;
  1431. }
  1432. }
  1433. break;
  1434. case 0x0047:
  1435. //
  1436. // Play sound effect
  1437. //
  1438. SOUND_Play(pScript->rgwOperand[0]);
  1439. break;
  1440. case 0x0049:
  1441. //
  1442. // Set the state of event object
  1443. //
  1444. pCurrent->sState = pScript->rgwOperand[1];
  1445. break;
  1446. case 0x004A:
  1447. //
  1448. // Set the current battlefield
  1449. //
  1450. gpGlobals->wNumBattleField = pScript->rgwOperand[0];
  1451. break;
  1452. case 0x004B:
  1453. //
  1454. // Nullify the event object for a short while
  1455. //
  1456. pEvtObj->sVanishTime = -15;
  1457. break;
  1458. case 0x004C:
  1459. //
  1460. // chase the player
  1461. //
  1462. i = pScript->rgwOperand[0]; // max. distance
  1463. j = pScript->rgwOperand[1]; // speed
  1464. if (i == 0)
  1465. {
  1466. i = 8;
  1467. }
  1468. if (j == 0)
  1469. {
  1470. j = 4;
  1471. }
  1472. PAL_MonsterChasePlayer(wEventObjectID, j, i, pScript->rgwOperand[2]);
  1473. break;
  1474. case 0x004D:
  1475. //
  1476. // wait for any key
  1477. //
  1478. PAL_WaitForKey(0);
  1479. break;
  1480. case 0x004E:
  1481. //
  1482. // Load the last saved game
  1483. //
  1484. PAL_FadeOut(1);
  1485. PAL_InitGameData(gpGlobals->bCurrentSaveSlot);
  1486. return 0; // don't go further
  1487. case 0x004F:
  1488. //
  1489. // Fade the screen to red color (game over)
  1490. //
  1491. PAL_FadeToRed();
  1492. break;
  1493. case 0x0050:
  1494. //
  1495. // screen fade out
  1496. //
  1497. VIDEO_UpdateScreen(NULL);
  1498. PAL_FadeOut(pScript->rgwOperand[0] ? pScript->rgwOperand[0] : 1);
  1499. gpGlobals->fNeedToFadeIn = TRUE;
  1500. break;
  1501. case 0x0051:
  1502. //
  1503. // screen fade in
  1504. //
  1505. VIDEO_UpdateScreen(NULL);
  1506. PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette,
  1507. ((SHORT)(pScript->rgwOperand[0]) > 0) ? pScript->rgwOperand[0] : 1);
  1508. gpGlobals->fNeedToFadeIn = FALSE;
  1509. break;
  1510. case 0x0052:
  1511. //
  1512. // hide the event object for a while, default 800 frames
  1513. //
  1514. pEvtObj->sState *= -1;
  1515. pEvtObj->sVanishTime = (pScript->rgwOperand[0] ? pScript->rgwOperand[0] : 800);
  1516. break;
  1517. case 0x0053:
  1518. //
  1519. // use the day palette
  1520. //
  1521. gpGlobals->fNightPalette = FALSE;
  1522. break;
  1523. case 0x0054:
  1524. //
  1525. // use the night palette
  1526. //
  1527. gpGlobals->fNightPalette = TRUE;
  1528. break;
  1529. case 0x0055:
  1530. //
  1531. // Add magic to a player
  1532. //
  1533. i = pScript->rgwOperand[1];
  1534. if (i == 0)
  1535. {
  1536. i = wEventObjectID;
  1537. }
  1538. else
  1539. {
  1540. i--;
  1541. }
  1542. PAL_AddMagic(i, pScript->rgwOperand[0]);
  1543. break;
  1544. case 0x0056:
  1545. //
  1546. // Remove magic from a player
  1547. //
  1548. i = pScript->rgwOperand[1];
  1549. if (i == 0)
  1550. {
  1551. i = wEventObjectID;
  1552. }
  1553. else
  1554. {
  1555. i--;
  1556. }
  1557. PAL_RemoveMagic(i, pScript->rgwOperand[0]);
  1558. break;
  1559. case 0x0057:
  1560. //
  1561. // Set the base damage of magic according to MP value
  1562. //
  1563. i = ((pScript->rgwOperand[1] == 0) ? 8 : pScript->rgwOperand[1]);
  1564. j = gpGlobals->g.rgObject[pScript->rgwOperand[0]].magic.wMagicNumber;
  1565. gpGlobals->g.lprgMagic[j].wBaseDamage =
  1566. gpGlobals->g.PlayerRoles.rgwMP[wEventObjectID] * i;
  1567. gpGlobals->g.PlayerRoles.rgwMP[wEventObjectID] = 0;
  1568. break;
  1569. case 0x0058:
  1570. //
  1571. // Jump if there is less than the specified number of the specified items
  1572. // in the inventory
  1573. //
  1574. if (PAL_GetItemAmount(pScript->rgwOperand[0]) < (SHORT)(pScript->rgwOperand[1]))
  1575. {
  1576. wScriptEntry = pScript->rgwOperand[2] - 1;
  1577. }
  1578. break;
  1579. case 0x0059:
  1580. //
  1581. // Change to the specified scene
  1582. //
  1583. if (pScript->rgwOperand[0] > 0 && pScript->rgwOperand[0] <= MAX_SCENES &&
  1584. gpGlobals->wNumScene != pScript->rgwOperand[0])
  1585. {
  1586. //
  1587. // Set data to load the scene in the next frame
  1588. //
  1589. gpGlobals->wNumScene = pScript->rgwOperand[0];
  1590. PAL_SetLoadFlags(kLoadScene);
  1591. gpGlobals->fEnteringScene = TRUE;
  1592. gpGlobals->wLayer = 0;
  1593. }
  1594. break;
  1595. case 0x005A:
  1596. //
  1597. // Halve the player's HP
  1598. // The wEventObjectID parameter here should indicate the player role
  1599. //
  1600. gpGlobals->g.PlayerRoles.rgwHP[wEventObjectID] /= 2;
  1601. break;
  1602. case 0x005B:
  1603. //
  1604. // Halve the enemy's HP
  1605. //
  1606. w = g_Battle.rgEnemy[wEventObjectID].e.wHealth / 2 + 1;
  1607. if (w > pScript->rgwOperand[0])
  1608. {
  1609. w = pScript->rgwOperand[0];
  1610. }
  1611. g_Battle.rgEnemy[wEventObjectID].e.wHealth -= w;
  1612. break;
  1613. case 0x005C:
  1614. //
  1615. // Hide for a while
  1616. //
  1617. g_Battle.iHidingTime = -(INT)(pScript->rgwOperand[0]);
  1618. break;
  1619. case 0x005D:
  1620. //
  1621. // Jump if player doesn't have the specified poison
  1622. //
  1623. if (!PAL_IsPlayerPoisonedByKind(wEventObjectID, pScript->rgwOperand[0]))
  1624. {
  1625. wScriptEntry = pScript->rgwOperand[1] - 1;
  1626. }
  1627. break;
  1628. case 0x005E:
  1629. //
  1630. // Jump if enemy doesn't have the specified poison
  1631. //
  1632. for (i = 0; i < MAX_POISONS; i++)
  1633. {
  1634. if (g_Battle.rgEnemy[wEventObjectID].rgPoisons[i].wPoisonID == pScript->rgwOperand[0])
  1635. {
  1636. break;
  1637. }
  1638. }
  1639. if (i >= MAX_POISONS)
  1640. {
  1641. wScriptEntry = pScript->rgwOperand[1] - 1;
  1642. }
  1643. break;
  1644. case 0x005F:
  1645. //
  1646. // Kill the player immediately
  1647. // The wEventObjectID parameter here should indicate the player role
  1648. //
  1649. gpGlobals->g.PlayerRoles.rgwHP[wEventObjectID] = 0;
  1650. break;
  1651. case 0x0060:
  1652. //
  1653. // Immediate KO of the enemy
  1654. //
  1655. g_Battle.rgEnemy[wEventObjectID].e.wHealth = 0;
  1656. break;
  1657. case 0x0061:
  1658. //
  1659. // Jump if player is not poisoned
  1660. //
  1661. if (!PAL_IsPlayerPoisonedByLevel(wEventObjectID, 1))
  1662. {
  1663. wScriptEntry = pScript->rgwOperand[0] - 1;
  1664. }
  1665. break;
  1666. case 0x0062:
  1667. //
  1668. // Pause enemy chasing for a while
  1669. //
  1670. gpGlobals->wChasespeedChangeCycles = pScript->rgwOperand[0];
  1671. gpGlobals->wChaseRange = 0;
  1672. break;
  1673. case 0x0063:
  1674. //
  1675. // Speed up enemy chasing for a while
  1676. //
  1677. gpGlobals->wChasespeedChangeCycles = pScript->rgwOperand[0];
  1678. gpGlobals->wChaseRange = 3;
  1679. break;
  1680. case 0x0064:
  1681. //
  1682. // Jump if enemy's HP is more than the specified percentage
  1683. //
  1684. i = gpGlobals->g.rgObject[g_Battle.rgEnemy[wEventObjectID].wObjectID].enemy.wEnemyID;
  1685. if ((INT)(g_Battle.rgEnemy[wEventObjectID].e.wHealth) * 100 >
  1686. (INT)(gpGlobals->g.lprgEnemy[i].wHealth) * pScript->rgwOperand[0])
  1687. {
  1688. wScriptEntry = pScript->rgwOperand[1] - 1;
  1689. }
  1690. break;
  1691. case 0x0065:
  1692. //
  1693. // Set the player's sprite
  1694. //
  1695. gpGlobals->g.PlayerRoles.rgwSpriteNum[pScript->rgwOperand[0]] = pScript->rgwOperand[1];
  1696. if (!gpGlobals->fInBattle && pScript->rgwOperand[2])
  1697. {
  1698. PAL_SetLoadFlags(kLoadPlayerSprite);
  1699. PAL_LoadResources();
  1700. }
  1701. break;
  1702. case 0x0066:
  1703. //
  1704. // Throw weapon to enemy
  1705. //
  1706. w = pScript->rgwOperand[1] * 5;
  1707. w += gpGlobals->g.PlayerRoles.rgwAttackStrength[gpGlobals->rgParty[g_Battle.wMovingPlayerIndex].wPlayerRole];
  1708. w += RandomLong(0, 4);
  1709. PAL_BattleSimulateMagic((SHORT)wEventObjectID, pScript->rgwOperand[0], w);
  1710. break;
  1711. case 0x0067:
  1712. //
  1713. // Enemy use magic
  1714. //
  1715. g_Battle.rgEnemy[wEventObjectID].e.wMagic = pScript->rgwOperand[0];
  1716. g_Battle.rgEnemy[wEventObjectID].e.wMagicRate =
  1717. ((pScript->rgwOperand[1] == 0) ? 10 : pScript->rgwOperand[1]);
  1718. break;
  1719. case 0x0068:
  1720. //
  1721. // Jump if it's enemy's turn
  1722. //
  1723. if (g_Battle.fEnemyMoving)
  1724. {
  1725. wScriptEntry = pScript->rgwOperand[0] - 1;
  1726. }
  1727. break;
  1728. case 0x0069:
  1729. //
  1730. // Enemy escape in battle
  1731. //
  1732. PAL_BattleEnemyEscape();
  1733. break;
  1734. case 0x006A:
  1735. //
  1736. // Steal from the enemy
  1737. //
  1738. PAL_BattleStealFromEnemy(wEventObjectID, pScript->rgwOperand[0]);
  1739. break;
  1740. case 0x006B:
  1741. //
  1742. // Blow away enemies
  1743. //
  1744. g_Battle.iBlow = (SHORT)(pScript->rgwOperand[0]);
  1745. break;
  1746. case 0x006C:
  1747. //
  1748. // Walk the NPC in one step
  1749. //
  1750. pCurrent->x += (SHORT)(pScript->rgwOperand[1]);
  1751. pCurrent->y += (SHORT)(pScript->rgwOperand[2]);
  1752. PAL_NPCWalkOneStep(wCurEventObjectID, 0);
  1753. break;
  1754. case 0x006D:
  1755. //
  1756. // Set the enter script and teleport script for a scene
  1757. //
  1758. if (pScript->rgwOperand[0])
  1759. {
  1760. if (pScript->rgwOperand[1])
  1761. {
  1762. gpGlobals->g.rgScene[pScript->rgwOperand[0] - 1].wScriptOnEnter =
  1763. pScript->rgwOperand[1];
  1764. }
  1765. if (pScript->rgwOperand[2])
  1766. {
  1767. gpGlobals->g.rgScene[pScript->rgwOperand[0] - 1].wScriptOnTeleport =
  1768. pScript->rgwOperand[2];
  1769. }
  1770. if (pScript->rgwOperand[1] == 0 && pScript->rgwOperand[2] == 0)
  1771. {
  1772. gpGlobals->g.rgScene[pScript->rgwOperand[0] - 1].wScriptOnEnter = 0;
  1773. gpGlobals->g.rgScene[pScript->rgwOperand[0] - 1].wScriptOnTeleport = 0;
  1774. }
  1775. }
  1776. break;
  1777. case 0x006E:
  1778. //
  1779. // Move the player to the specified position in one step
  1780. //
  1781. for (i = 3; i >= 0; i--)
  1782. {
  1783. gpGlobals->rgTrail[i + 1] = gpGlobals->rgTrail[i];
  1784. }
  1785. gpGlobals->rgTrail[0].wDirection = gpGlobals->wPartyDirection;
  1786. gpGlobals->rgTrail[0].x = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset);
  1787. gpGlobals->rgTrail[0].y = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset);
  1788. gpGlobals->viewport = PAL_XY(
  1789. PAL_X(gpGlobals->viewport) + (SHORT)(pScript->rgwOperand[0]),
  1790. PAL_Y(gpGlobals->viewport) + (SHORT)(pScript->rgwOperand[1]));
  1791. gpGlobals->wLayer = pScript->rgwOperand[2] * 8;
  1792. if (pScript->rgwOperand[0] != 0 || pScript->rgwOperand[1] != 0)
  1793. {
  1794. PAL_UpdatePartyGestures(TRUE);
  1795. }
  1796. break;
  1797. case 0x006F:
  1798. //
  1799. // Sync the state of current event object with another event object
  1800. //
  1801. if (pCurrent->sState == (SHORT)(pScript->rgwOperand[1]))
  1802. {
  1803. pEvtObj->sState = (SHORT)(pScript->rgwOperand[1]);
  1804. }
  1805. break;
  1806. case 0x0070:
  1807. //
  1808. // Walk the party to the specified position
  1809. //
  1810. PAL_PartyWalkTo(pScript->rgwOperand[0], pScript->rgwOperand[1], pScript->rgwOperand[2], 2);
  1811. break;
  1812. case 0x0071:
  1813. //
  1814. // Wave the screen
  1815. //
  1816. gpGlobals->wScreenWave = pScript->rgwOperand[0];
  1817. gpGlobals->sWaveProgression = (SHORT)(pScript->rgwOperand[1]);
  1818. break;
  1819. case 0x0073:
  1820. //
  1821. // Fade the screen to scene
  1822. //
  1823. VIDEO_BackupScreen();
  1824. PAL_MakeScene();
  1825. VIDEO_FadeScreen(pScript->rgwOperand[0]);
  1826. break;
  1827. case 0x0074:
  1828. //
  1829. // Jump if not all players are full HP
  1830. //
  1831. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  1832. {
  1833. w = gpGlobals->rgParty[i].wPlayerRole;
  1834. if (gpGlobals->g.PlayerRoles.rgwHP[w] < gpGlobals->g.PlayerRoles.rgwMaxHP[w])
  1835. {
  1836. wScriptEntry = pScript->rgwOperand[0] - 1;
  1837. break;
  1838. }
  1839. }
  1840. break;
  1841. case 0x0075:
  1842. //
  1843. // Set the player party
  1844. //
  1845. gpGlobals->wMaxPartyMemberIndex = 0;
  1846. for (i = 0; i < 3; i++)
  1847. {
  1848. if (pScript->rgwOperand[i] != 0)
  1849. {
  1850. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex].wPlayerRole =
  1851. pScript->rgwOperand[i] - 1;
  1852. g_Battle.rgPlayer[gpGlobals->wMaxPartyMemberIndex].action.ActionType =
  1853. kBattleActionAttack;
  1854. gpGlobals->wMaxPartyMemberIndex++;
  1855. }
  1856. }
  1857. if (gpGlobals->wMaxPartyMemberIndex == 0)
  1858. {
  1859. // HACK for Dream 2.11
  1860. gpGlobals->rgParty[0].wPlayerRole = 0;
  1861. gpGlobals->wMaxPartyMemberIndex = 1;
  1862. }
  1863. gpGlobals->wMaxPartyMemberIndex--;
  1864. //
  1865. // Reload the player sprites
  1866. //
  1867. PAL_SetLoadFlags(kLoadPlayerSprite);
  1868. PAL_LoadResources();
  1869. memset(gpGlobals->rgPoisonStatus, 0, sizeof(gpGlobals->rgPoisonStatus));
  1870. PAL_UpdateEquipments();
  1871. break;
  1872. case 0x0076:
  1873. //
  1874. // Show FBP picture
  1875. //
  1876. if (gpGlobals->fIsWIN95)
  1877. {
  1878. SDL_FillRect(gpScreen, NULL, 0);
  1879. VIDEO_UpdateScreen(NULL);
  1880. }
  1881. else
  1882. {
  1883. PAL_EndingSetEffectSprite(0);
  1884. PAL_ShowFBP(pScript->rgwOperand[0], pScript->rgwOperand[1]);
  1885. }
  1886. break;
  1887. case 0x0077:
  1888. //
  1889. // Stop current playing music
  1890. //
  1891. SOUND_PlayMUS(0, FALSE,
  1892. (pScript->rgwOperand[0] == 0) ? 2.0f : (FLOAT)(pScript->rgwOperand[0]) * 2);
  1893. gpGlobals->wNumMusic = 0;
  1894. break;
  1895. case 0x0078:
  1896. //
  1897. // FIXME: ???
  1898. //
  1899. break;
  1900. case 0x0079:
  1901. //
  1902. // Jump if the specified player is in the party
  1903. //
  1904. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  1905. {
  1906. if (gpGlobals->g.PlayerRoles.rgwName[gpGlobals->rgParty[i].wPlayerRole] ==
  1907. pScript->rgwOperand[0])
  1908. {
  1909. wScriptEntry = pScript->rgwOperand[1] - 1;
  1910. break;
  1911. }
  1912. }
  1913. break;
  1914. case 0x007A:
  1915. //
  1916. // Walk the party to the specified position, at a higher speed
  1917. //
  1918. PAL_PartyWalkTo(pScript->rgwOperand[0], pScript->rgwOperand[1], pScript->rgwOperand[2], 4);
  1919. break;
  1920. case 0x007B:
  1921. //
  1922. // Walk the party to the specified position, at the highest speed
  1923. //
  1924. PAL_PartyWalkTo(pScript->rgwOperand[0], pScript->rgwOperand[1], pScript->rgwOperand[2], 8);
  1925. break;
  1926. case 0x007C:
  1927. //
  1928. // Walk straight to the specified position
  1929. //
  1930. if ((wEventObjectID & 1) ^ (gpGlobals->dwFrameNum & 1))
  1931. {
  1932. if (!PAL_NPCWalkTo(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  1933. pScript->rgwOperand[2], 4))
  1934. {
  1935. wScriptEntry--;
  1936. }
  1937. }
  1938. else
  1939. {
  1940. wScriptEntry--;
  1941. }
  1942. break;
  1943. case 0x007D:
  1944. //
  1945. // Move the event object
  1946. //
  1947. pCurrent->x += (SHORT)(pScript->rgwOperand[1]);
  1948. pCurrent->y += (SHORT)(pScript->rgwOperand[2]);
  1949. break;
  1950. case 0x007E:
  1951. //
  1952. // Set the layer of event object
  1953. //
  1954. pCurrent->sLayer = (SHORT)(pScript->rgwOperand[1]);
  1955. break;
  1956. case 0x007F:
  1957. //
  1958. // Move the viewport
  1959. //
  1960. if (pScript->rgwOperand[0] == 0 && pScript->rgwOperand[1] == 0)
  1961. {
  1962. //
  1963. // Move the viewport back to normal state
  1964. //
  1965. x = gpGlobals->rgParty[0].x - 160;
  1966. y = gpGlobals->rgParty[0].y - 112;
  1967. gpGlobals->viewport =
  1968. PAL_XY(PAL_X(gpGlobals->viewport) + x, PAL_Y(gpGlobals->viewport) + y);
  1969. gpGlobals->partyoffset = PAL_XY(160, 112);
  1970. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  1971. {
  1972. gpGlobals->rgParty[i].x -= x;
  1973. gpGlobals->rgParty[i].y -= y;
  1974. }
  1975. if (pScript->rgwOperand[2] != 0xFFFF)
  1976. {
  1977. PAL_MakeScene();
  1978. VIDEO_UpdateScreen(NULL);
  1979. }
  1980. }
  1981. else
  1982. {
  1983. DWORD time;
  1984. i = 0;
  1985. x = (SHORT)(pScript->rgwOperand[0]);
  1986. y = (SHORT)(pScript->rgwOperand[1]);
  1987. time = SDL_GetTicks() + FRAME_TIME;
  1988. do
  1989. {
  1990. if (pScript->rgwOperand[2] == 0xFFFF)
  1991. {
  1992. x = PAL_X(gpGlobals->viewport);
  1993. y = PAL_Y(gpGlobals->viewport);
  1994. gpGlobals->viewport =
  1995. PAL_XY(pScript->rgwOperand[0] * 32 - 160, pScript->rgwOperand[1] * 16 - 112);
  1996. x -= PAL_X(gpGlobals->viewport);
  1997. y -= PAL_Y(gpGlobals->viewport);
  1998. for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)
  1999. {
  2000. gpGlobals->rgParty[j].x += x;
  2001. gpGlobals->rgParty[j].y += y;
  2002. }
  2003. }
  2004. else
  2005. {
  2006. gpGlobals->viewport =
  2007. PAL_XY(PAL_X(gpGlobals->viewport) + x, PAL_Y(gpGlobals->viewport) + y);
  2008. gpGlobals->partyoffset =
  2009. PAL_XY(PAL_X(gpGlobals->partyoffset) - x, PAL_Y(gpGlobals->partyoffset) - y);
  2010. for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)
  2011. {
  2012. gpGlobals->rgParty[j].x -= x;
  2013. gpGlobals->rgParty[j].y -= y;
  2014. }
  2015. }
  2016. if (pScript->rgwOperand[2] != 0xFFFF)
  2017. {
  2018. PAL_GameUpdate(FALSE);
  2019. }
  2020. PAL_MakeScene();
  2021. VIDEO_UpdateScreen(NULL);
  2022. //
  2023. // Delay for one frame
  2024. //
  2025. PAL_ProcessEvent();
  2026. while (SDL_GetTicks() < time)
  2027. {
  2028. PAL_ProcessEvent();
  2029. SDL_Delay(1);
  2030. }
  2031. time = SDL_GetTicks() + FRAME_TIME;
  2032. } while (++i < (SHORT)(pScript->rgwOperand[2]));
  2033. }
  2034. break;
  2035. case 0x0080:
  2036. //
  2037. // Toggle day/night palette
  2038. //
  2039. gpGlobals->fNightPalette = !(gpGlobals->fNightPalette);
  2040. PAL_PaletteFade(gpGlobals->wNumPalette, gpGlobals->fNightPalette,
  2041. !(pScript->rgwOperand[0]));
  2042. break;
  2043. case 0x0081:
  2044. //
  2045. // Jump if the player is not facing the specified event object
  2046. //
  2047. {
  2048. if (pScript->rgwOperand[0] <= gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex ||
  2049. pScript->rgwOperand[0] > gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex)
  2050. {
  2051. //
  2052. // The event object is not in the current scene
  2053. //
  2054. wScriptEntry = pScript->rgwOperand[2] - 1;
  2055. g_fScriptSuccess = FALSE;
  2056. break;
  2057. }
  2058. x = pCurrent->x;
  2059. y = pCurrent->y;
  2060. x +=
  2061. ((gpGlobals->wPartyDirection == kDirWest || gpGlobals->wPartyDirection == kDirSouth)
  2062. ? 16 : -16);
  2063. y +=
  2064. ((gpGlobals->wPartyDirection == kDirWest || gpGlobals->wPartyDirection == kDirNorth)
  2065. ? 8 : -8);
  2066. x -= PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset);
  2067. y -= PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset);
  2068. if (abs(x) + abs(y * 2) < pScript->rgwOperand[1] * 32 + 16)
  2069. {
  2070. if (pScript->rgwOperand[1] > 0)
  2071. {
  2072. //
  2073. // Change the trigger mode so that the object can be triggered in next frame
  2074. //
  2075. pCurrent->wTriggerMode = kTriggerTouchNormal + pScript->rgwOperand[1];
  2076. }
  2077. }
  2078. else
  2079. {
  2080. wScriptEntry = pScript->rgwOperand[2] - 1;
  2081. g_fScriptSuccess = FALSE;
  2082. }
  2083. }
  2084. break;
  2085. case 0x0082:
  2086. //
  2087. // Walk straight to the specified position, at a high speed
  2088. //
  2089. if (!PAL_NPCWalkTo(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  2090. pScript->rgwOperand[2], 8))
  2091. {
  2092. wScriptEntry--;
  2093. }
  2094. break;
  2095. case 0x0083:
  2096. //
  2097. // Jump if event object is not in the specified zone of the current event object
  2098. //
  2099. if (pScript->rgwOperand[0] <= gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex ||
  2100. pScript->rgwOperand[0] > gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex)
  2101. {
  2102. //
  2103. // The event object is not in the current scene
  2104. //
  2105. wScriptEntry = pScript->rgwOperand[2] - 1;
  2106. g_fScriptSuccess = FALSE;
  2107. break;
  2108. }
  2109. x = pEvtObj->x - pCurrent->x;
  2110. y = pEvtObj->y - pCurrent->y;
  2111. if (abs(x) + abs(y * 2) >= pScript->rgwOperand[1] * 32 + 16)
  2112. {
  2113. wScriptEntry = pScript->rgwOperand[2] - 1;
  2114. g_fScriptSuccess = FALSE;
  2115. }
  2116. break;
  2117. case 0x0084:
  2118. //
  2119. // Place the item which player used as an event object to the scene
  2120. //
  2121. if (pScript->rgwOperand[0] <= gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex ||
  2122. pScript->rgwOperand[0] > gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex)
  2123. {
  2124. //
  2125. // The event object is not in the current scene
  2126. //
  2127. wScriptEntry = pScript->rgwOperand[2] - 1;
  2128. g_fScriptSuccess = FALSE;
  2129. break;
  2130. }
  2131. x = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset);
  2132. y = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset);
  2133. x +=
  2134. ((gpGlobals->wPartyDirection == kDirWest || gpGlobals->wPartyDirection == kDirSouth)
  2135. ? -16 : 16);
  2136. y +=
  2137. ((gpGlobals->wPartyDirection == kDirWest || gpGlobals->wPartyDirection == kDirNorth)
  2138. ? -8 : 8);
  2139. if (PAL_CheckObstacle(PAL_XY(x, y), FALSE, 0))
  2140. {
  2141. wScriptEntry = pScript->rgwOperand[2] - 1;
  2142. g_fScriptSuccess = FALSE;
  2143. }
  2144. else
  2145. {
  2146. pCurrent->x = x;
  2147. pCurrent->y = y;
  2148. pCurrent->sState = (SHORT)(pScript->rgwOperand[1]);
  2149. }
  2150. break;
  2151. case 0x0085:
  2152. //
  2153. // Delay for a period
  2154. //
  2155. UTIL_Delay(pScript->rgwOperand[0] * 80);
  2156. break;
  2157. case 0x0086:
  2158. //
  2159. // Jump if the specified item is not equipped
  2160. //
  2161. y = FALSE;
  2162. for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  2163. {
  2164. w = gpGlobals->rgParty[i].wPlayerRole;
  2165. for (x = 0; x < MAX_PLAYER_EQUIPMENTS; x++)
  2166. {
  2167. if (gpGlobals->g.PlayerRoles.rgwEquipment[x][w] == pScript->rgwOperand[0])
  2168. {
  2169. y = TRUE;
  2170. i = 999;
  2171. break;
  2172. }
  2173. }
  2174. }
  2175. if (!y)
  2176. {
  2177. wScriptEntry = pScript->rgwOperand[2] - 1;
  2178. }
  2179. break;
  2180. case 0x0087:
  2181. //
  2182. // Animate the event object
  2183. //
  2184. PAL_NPCWalkOneStep(wCurEventObjectID, 0);
  2185. break;
  2186. case 0x0088:
  2187. //
  2188. // Set the base damage of magic according to amount of money
  2189. //
  2190. i = ((gpGlobals->dwCash > 5000) ? 5000 : gpGlobals->dwCash);
  2191. gpGlobals->dwCash -= i;
  2192. j = gpGlobals->g.rgObject[pScript->rgwOperand[0]].magic.wMagicNumber;
  2193. gpGlobals->g.lprgMagic[j].wBaseDamage = i * 2 / 5;
  2194. break;
  2195. case 0x0089:
  2196. //
  2197. // Set the battle result
  2198. //
  2199. g_Battle.BattleResult = pScript->rgwOperand[0];
  2200. break;
  2201. case 0x008A:
  2202. //
  2203. // Enable Auto-Battle for next battle
  2204. //
  2205. gpGlobals->fAutoBattle = TRUE;
  2206. break;
  2207. case 0x008B:
  2208. //
  2209. // change the current palette
  2210. //
  2211. gpGlobals->wNumPalette = pScript->rgwOperand[0];
  2212. if (!gpGlobals->fNeedToFadeIn)
  2213. {
  2214. PAL_SetPalette(gpGlobals->wNumPalette, FALSE);
  2215. }
  2216. break;
  2217. case 0x008C:
  2218. //
  2219. // Fade from/to color
  2220. //
  2221. PAL_ColorFade(pScript->rgwOperand[1], (BYTE)(pScript->rgwOperand[0]),
  2222. pScript->rgwOperand[2]);
  2223. gpGlobals->fNeedToFadeIn = FALSE;
  2224. break;
  2225. case 0x008D:
  2226. //
  2227. // Increase player's level
  2228. //
  2229. PAL_PlayerLevelUp(wEventObjectID, pScript->rgwOperand[0]);
  2230. break;
  2231. case 0x008F:
  2232. //
  2233. // Halve the cash amount
  2234. //
  2235. gpGlobals->dwCash /= 2;
  2236. break;
  2237. case 0x0090:
  2238. //
  2239. // Set the object script
  2240. //
  2241. gpGlobals->g.rgObject[pScript->rgwOperand[0]].rgwData[2 + pScript->rgwOperand[2]] =
  2242. pScript->rgwOperand[1];
  2243. break;
  2244. case 0x0091:
  2245. //
  2246. // Jump if the enemy is not alone
  2247. //
  2248. if (gpGlobals->fInBattle)
  2249. {
  2250. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2251. {
  2252. if (i != wEventObjectID &&
  2253. g_Battle.rgEnemy[i].wObjectID == g_Battle.rgEnemy[wEventObjectID].wObjectID)
  2254. {
  2255. wScriptEntry = pScript->rgwOperand[0] - 1;
  2256. break;
  2257. }
  2258. }
  2259. }
  2260. break;
  2261. case 0x0092:
  2262. //
  2263. // Show a magic-casting animation for a player in battle
  2264. //
  2265. if (gpGlobals->fInBattle)
  2266. {
  2267. if (pScript->rgwOperand[0] != 0)
  2268. {
  2269. PAL_BattleShowPlayerPreMagicAnim(pScript->rgwOperand[0] - 1, FALSE);
  2270. g_Battle.rgPlayer[pScript->rgwOperand[0] - 1].wCurrentFrame = 6;
  2271. }
  2272. for (i = 0; i < 5; i++)
  2273. {
  2274. for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)
  2275. {
  2276. g_Battle.rgPlayer[j].iColorShift = i * 2;
  2277. }
  2278. PAL_BattleDelay(1, 0, TRUE);
  2279. }
  2280. PAL_BattleBackupScene();
  2281. PAL_BattleUpdateFighters();
  2282. PAL_BattleMakeScene();
  2283. PAL_BattleFadeScene();
  2284. }
  2285. break;
  2286. case 0x0093:
  2287. //
  2288. // Fade the screen. Update scene in the process.
  2289. //
  2290. PAL_SceneFade(gpGlobals->wNumPalette, gpGlobals->fNightPalette,
  2291. (SHORT)(pScript->rgwOperand[0]));
  2292. gpGlobals->fNeedToFadeIn = ((SHORT)(pScript->rgwOperand[0]) < 0);
  2293. break;
  2294. case 0x0094:
  2295. //
  2296. // Jump if the state of event object is the specified one
  2297. //
  2298. if (pCurrent->sState == (SHORT)(pScript->rgwOperand[1]))
  2299. {
  2300. wScriptEntry = pScript->rgwOperand[2] - 1;
  2301. }
  2302. break;
  2303. case 0x0095:
  2304. //
  2305. // Jump if the current scene is the specified one
  2306. //
  2307. if (gpGlobals->wNumScene == pScript->rgwOperand[0])
  2308. {
  2309. wScriptEntry = pScript->rgwOperand[1] - 1;
  2310. }
  2311. break;
  2312. case 0x0096:
  2313. //
  2314. // Show the ending animation
  2315. //
  2316. if (!gpGlobals->fIsWIN95)
  2317. PAL_EndingAnimation();
  2318. break;
  2319. case 0x0097:
  2320. //
  2321. // Ride the event object to the specified position, at a higher speed
  2322. //
  2323. PAL_PartyRideEventObject(wEventObjectID, pScript->rgwOperand[0], pScript->rgwOperand[1],
  2324. pScript->rgwOperand[2], 8);
  2325. break;
  2326. case 0x0098:
  2327. //
  2328. // Set follower of the party
  2329. //
  2330. if (pScript->rgwOperand[0] > 0)
  2331. {
  2332. gpGlobals->nFollower = 1;
  2333. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].wPlayerRole = pScript->rgwOperand[0];
  2334. PAL_SetLoadFlags(kLoadPlayerSprite);
  2335. PAL_LoadResources();
  2336. //
  2337. // Update the position and gesture for the follower
  2338. //
  2339. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].x =
  2340. gpGlobals->rgTrail[3].x - PAL_X(gpGlobals->viewport);
  2341. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].y =
  2342. gpGlobals->rgTrail[3].y - PAL_Y(gpGlobals->viewport);
  2343. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].wFrame =
  2344. gpGlobals->rgTrail[3].wDirection * 3;
  2345. }
  2346. else
  2347. {
  2348. gpGlobals->nFollower = 0;
  2349. }
  2350. break;
  2351. case 0x0099:
  2352. //
  2353. // Change the map for the specified scene
  2354. //
  2355. if (pScript->rgwOperand[0] == 0xFFFF)
  2356. {
  2357. gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wMapNum = pScript->rgwOperand[1];
  2358. PAL_SetLoadFlags(kLoadScene);
  2359. PAL_LoadResources();
  2360. }
  2361. else
  2362. {
  2363. gpGlobals->g.rgScene[pScript->rgwOperand[0] - 1].wMapNum = pScript->rgwOperand[1];
  2364. }
  2365. break;
  2366. case 0x009A:
  2367. //
  2368. // Set the state for multiple event objects
  2369. //
  2370. for (i = pScript->rgwOperand[0]; i <= pScript->rgwOperand[1]; i++)
  2371. {
  2372. gpGlobals->g.lprgEventObject[i - 1].sState = pScript->rgwOperand[2];
  2373. }
  2374. break;
  2375. case 0x009B:
  2376. //
  2377. // Fade to the current scene
  2378. // FIXME: This is obviously wrong
  2379. //
  2380. VIDEO_BackupScreen();
  2381. PAL_MakeScene();
  2382. VIDEO_FadeScreen(2);
  2383. break;
  2384. case 0x009C:
  2385. //
  2386. // Enemy duplicate itself
  2387. //
  2388. w = 0;
  2389. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2390. {
  2391. if (g_Battle.rgEnemy[i].wObjectID != 0)
  2392. {
  2393. w++;
  2394. }
  2395. }
  2396. if (w != 1)
  2397. {
  2398. //
  2399. // Duplication is only possible when only 1 enemy left
  2400. //
  2401. if (pScript->rgwOperand[1] != 0)
  2402. {
  2403. wScriptEntry = pScript->rgwOperand[1] - 1;
  2404. }
  2405. break;
  2406. }
  2407. w = pScript->rgwOperand[0];
  2408. if (w == 0)
  2409. {
  2410. w = 1;
  2411. }
  2412. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2413. {
  2414. if (w > 0 && g_Battle.rgEnemy[i].wObjectID == 0)
  2415. {
  2416. w--;
  2417. memset(&(g_Battle.rgEnemy[i]), 0, sizeof(BATTLEENEMY));
  2418. g_Battle.rgEnemy[i].wObjectID = g_Battle.rgEnemy[wEventObjectID].wObjectID;
  2419. g_Battle.rgEnemy[i].e = g_Battle.rgEnemy[wEventObjectID].e;
  2420. g_Battle.rgEnemy[i].wScriptOnTurnStart = g_Battle.rgEnemy[wEventObjectID].wScriptOnTurnStart;
  2421. g_Battle.rgEnemy[i].wScriptOnBattleEnd = g_Battle.rgEnemy[wEventObjectID].wScriptOnBattleEnd;
  2422. g_Battle.rgEnemy[i].wScriptOnReady = g_Battle.rgEnemy[wEventObjectID].wScriptOnReady;
  2423. g_Battle.rgEnemy[i].state = kFighterWait;
  2424. g_Battle.rgEnemy[i].flTimeMeter = 50;
  2425. g_Battle.rgEnemy[i].iColorShift = 0;
  2426. }
  2427. }
  2428. PAL_LoadBattleSprites();
  2429. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2430. {
  2431. if (g_Battle.rgEnemy[i].wObjectID == 0)
  2432. {
  2433. continue;
  2434. }
  2435. g_Battle.rgEnemy[i].pos = g_Battle.rgEnemy[wEventObjectID].pos;
  2436. }
  2437. for (i = 0; i < 10; i++)
  2438. {
  2439. for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)
  2440. {
  2441. x = (PAL_X(g_Battle.rgEnemy[j].pos) + PAL_X(g_Battle.rgEnemy[j].posOriginal)) / 2;
  2442. y = (PAL_Y(g_Battle.rgEnemy[j].pos) + PAL_Y(g_Battle.rgEnemy[j].posOriginal)) / 2;
  2443. g_Battle.rgEnemy[j].pos = PAL_XY(x, y);
  2444. }
  2445. PAL_BattleDelay(1, 0, TRUE);
  2446. }
  2447. PAL_BattleUpdateFighters();
  2448. PAL_BattleDelay(1, 0, TRUE);
  2449. break;
  2450. case 0x009E:
  2451. //
  2452. // Enemy summons another monster
  2453. //
  2454. x = 0;
  2455. w = pScript->rgwOperand[0];
  2456. y = (((SHORT)(pScript->rgwOperand[1]) <= 0) ? 1 : (SHORT)pScript->rgwOperand[1]);
  2457. if (w == 0 || w == 0xFFFF)
  2458. {
  2459. w = g_Battle.rgEnemy[wEventObjectID].wObjectID;
  2460. }
  2461. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2462. {
  2463. if (g_Battle.rgEnemy[i].wObjectID == 0)
  2464. {
  2465. x++;
  2466. }
  2467. }
  2468. if (x < y || g_Battle.iHidingTime > 0 ||
  2469. g_Battle.rgEnemy[wEventObjectID].rgwStatus[kStatusSleep] != 0 ||
  2470. g_Battle.rgEnemy[wEventObjectID].rgwStatus[kStatusParalyzed] != 0 ||
  2471. g_Battle.rgEnemy[wEventObjectID].rgwStatus[kStatusConfused] != 0)
  2472. {
  2473. if (pScript->rgwOperand[2] != 0)
  2474. {
  2475. wScriptEntry = pScript->rgwOperand[2] - 1;
  2476. }
  2477. }
  2478. else
  2479. {
  2480. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2481. {
  2482. if (g_Battle.rgEnemy[i].wObjectID == 0)
  2483. {
  2484. memset(&(g_Battle.rgEnemy[i]), 0, sizeof(BATTLEENEMY));
  2485. g_Battle.rgEnemy[i].wObjectID = w;
  2486. g_Battle.rgEnemy[i].e = gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[w].enemy.wEnemyID];
  2487. g_Battle.rgEnemy[i].state = kFighterWait;
  2488. g_Battle.rgEnemy[i].wScriptOnTurnStart = gpGlobals->g.rgObject[w].enemy.wScriptOnTurnStart;
  2489. g_Battle.rgEnemy[i].wScriptOnBattleEnd = gpGlobals->g.rgObject[w].enemy.wScriptOnBattleEnd;
  2490. g_Battle.rgEnemy[i].wScriptOnReady = gpGlobals->g.rgObject[w].enemy.wScriptOnReady;
  2491. g_Battle.rgEnemy[i].flTimeMeter = 50;
  2492. g_Battle.rgEnemy[i].iColorShift = 8;
  2493. y--;
  2494. if (y <= 0)
  2495. {
  2496. break;
  2497. }
  2498. }
  2499. }
  2500. PAL_BattleDelay(2, 0, TRUE);
  2501. PAL_BattleBackupScene();
  2502. PAL_LoadBattleSprites();
  2503. PAL_BattleMakeScene();
  2504. SOUND_Play(212);
  2505. PAL_BattleFadeScene();
  2506. for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
  2507. {
  2508. g_Battle.rgEnemy[i].iColorShift = 0;
  2509. }
  2510. PAL_BattleBackupScene();
  2511. PAL_BattleMakeScene();
  2512. PAL_BattleFadeScene();
  2513. }
  2514. break;
  2515. case 0x009F:
  2516. //
  2517. // Enemy transforms into something else
  2518. //
  2519. if (g_Battle.iHidingTime <= 0 &&
  2520. g_Battle.rgEnemy[wEventObjectID].rgwStatus[kStatusSleep] == 0 &&
  2521. g_Battle.rgEnemy[wEventObjectID].rgwStatus[kStatusParalyzed] == 0 &&
  2522. g_Battle.rgEnemy[wEventObjectID].rgwStatus[kStatusConfused] == 0)
  2523. {
  2524. w = g_Battle.rgEnemy[wEventObjectID].e.wHealth;
  2525. g_Battle.rgEnemy[wEventObjectID].wObjectID = pScript->rgwOperand[0];
  2526. g_Battle.rgEnemy[wEventObjectID].e =
  2527. gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[pScript->rgwOperand[0]].enemy.wEnemyID];
  2528. g_Battle.rgEnemy[wEventObjectID].e.wHealth = w;
  2529. g_Battle.rgEnemy[wEventObjectID].wCurrentFrame = 0;
  2530. for (i = 0; i < 6; i++)
  2531. {
  2532. g_Battle.rgEnemy[wEventObjectID].iColorShift = i;
  2533. PAL_BattleDelay(1, 0, FALSE);
  2534. }
  2535. g_Battle.rgEnemy[wEventObjectID].iColorShift = 0;
  2536. PAL_BattleBackupScene();
  2537. PAL_LoadBattleSprites();
  2538. PAL_BattleMakeScene();
  2539. PAL_BattleFadeScene();
  2540. }
  2541. break;
  2542. case 0x00A0:
  2543. //
  2544. // Quit game
  2545. //
  2546. if (gpGlobals->fIsWIN95)
  2547. PAL_EndingScreen();
  2548. PAL_AdditionalCredits();
  2549. PAL_Shutdown();
  2550. exit(0);
  2551. break;
  2552. case 0x00A1:
  2553. //
  2554. // Set the positions of all party members to the same as the first one
  2555. //
  2556. for (i = 0; i < MAX_PLAYABLE_PLAYER_ROLES; i++)
  2557. {
  2558. gpGlobals->rgTrail[i].wDirection = gpGlobals->wPartyDirection;
  2559. gpGlobals->rgTrail[i].x = gpGlobals->rgParty[0].x + PAL_X(gpGlobals->viewport);
  2560. gpGlobals->rgTrail[i].y = gpGlobals->rgParty[0].y + PAL_Y(gpGlobals->viewport);
  2561. }
  2562. for (i = 1; i <= gpGlobals->wMaxPartyMemberIndex; i++)
  2563. {
  2564. gpGlobals->rgParty[i].x = gpGlobals->rgParty[0].x;
  2565. gpGlobals->rgParty[i].y = gpGlobals->rgParty[0].y - 1;
  2566. }
  2567. PAL_UpdatePartyGestures(FALSE);
  2568. break;
  2569. case 0x00A2:
  2570. //
  2571. // Jump to one of the following instructions randomly
  2572. //
  2573. wScriptEntry += RandomLong(0, pScript->rgwOperand[0] - 1);
  2574. break;
  2575. case 0x00A3:
  2576. //
  2577. // Play CD music. Use the RIX music for fallback.
  2578. //
  2579. if (!SOUND_PlayCDA(pScript->rgwOperand[0]))
  2580. {
  2581. SOUND_PlayMUS(pScript->rgwOperand[1], TRUE, 0);
  2582. }
  2583. break;
  2584. case 0x00A4:
  2585. //
  2586. // Scroll FBP to the screen
  2587. //
  2588. if (!gpGlobals->fIsWIN95)
  2589. {
  2590. if (pScript->rgwOperand[0] == 68)
  2591. {
  2592. //
  2593. // HACKHACK: to make the ending picture show correctly
  2594. //
  2595. PAL_ShowFBP(69, 0);
  2596. PAL_ScrollFBP(pScript->rgwOperand[0], pScript->rgwOperand[2], TRUE);
  2597. }
  2598. else
  2599. {
  2600. PAL_ScrollFBP(pScript->rgwOperand[0], pScript->rgwOperand[2], pScript->rgwOperand[1]);
  2601. }
  2602. }
  2603. break;
  2604. case 0x00A5:
  2605. //
  2606. // Show FBP picture with sprite effects
  2607. //
  2608. if (!gpGlobals->fIsWIN95)
  2609. {
  2610. if (pScript->rgwOperand[1] != 0xFFFF)
  2611. {
  2612. PAL_EndingSetEffectSprite(pScript->rgwOperand[1]);
  2613. }
  2614. PAL_ShowFBP(pScript->rgwOperand[0], pScript->rgwOperand[2]);
  2615. }
  2616. break;
  2617. case 0x00A6:
  2618. //
  2619. // backup screen
  2620. //
  2621. VIDEO_BackupScreen();
  2622. break;
  2623. default:
  2624. TerminateOnError("SCRIPT: Invalid Instruction at %4x: (%4x - %4x, %4x, %4x)",
  2625. wScriptEntry, pScript->wOperation, pScript->rgwOperand[0],
  2626. pScript->rgwOperand[1], pScript->rgwOperand[2]);
  2627. break;
  2628. }
  2629. return wScriptEntry + 1;
  2630. }
  2631. WORD
  2632. PAL_RunTriggerScript(
  2633. WORD wScriptEntry,
  2634. WORD wEventObjectID
  2635. )
  2636. /*++
  2637. Purpose:
  2638. Runs a trigger script.
  2639. Parameters:
  2640. [IN] wScriptEntry - The script entry to execute.
  2641. [IN] wEventObjectID - The event object ID which invoked the script.
  2642. Return value:
  2643. The entry point of the script.
  2644. --*/
  2645. {
  2646. static WORD wLastEventObject = 0;
  2647. WORD wNextScriptEntry;
  2648. BOOL fEnded;
  2649. LPSCRIPTENTRY pScript;
  2650. LPEVENTOBJECT pEvtObj = NULL;
  2651. int i;
  2652. extern BOOL g_fUpdatedInBattle; // HACKHACK
  2653. wNextScriptEntry = wScriptEntry;
  2654. fEnded = FALSE;
  2655. g_fUpdatedInBattle = FALSE;
  2656. if (wEventObjectID == 0xFFFF)
  2657. {
  2658. wEventObjectID = wLastEventObject;
  2659. }
  2660. wLastEventObject = wEventObjectID;
  2661. if (wEventObjectID != 0)
  2662. {
  2663. pEvtObj = &(gpGlobals->g.lprgEventObject[wEventObjectID - 1]);
  2664. }
  2665. g_fScriptSuccess = TRUE;
  2666. //
  2667. // Set the default dialog speed.
  2668. //
  2669. PAL_DialogSetDelayTime(3);
  2670. while (wScriptEntry != 0 && !fEnded)
  2671. {
  2672. pScript = &(gpGlobals->g.lprgScriptEntry[wScriptEntry]);
  2673. UTIL_WriteLog(LOG_DEBUG, "[SCRIPT] %.4x: %.4x %.4x %.4x %.4x\n", wScriptEntry,
  2674. pScript->wOperation, pScript->rgwOperand[0], pScript->rgwOperand[1],
  2675. pScript->rgwOperand[2], pScript->rgwOperand[3]);
  2676. switch (pScript->wOperation)
  2677. {
  2678. case 0x0000:
  2679. //
  2680. // Stop running
  2681. //
  2682. fEnded = TRUE;
  2683. break;
  2684. case 0x0001:
  2685. //
  2686. // Stop running and replace the entry with the next line
  2687. //
  2688. fEnded = TRUE;
  2689. wNextScriptEntry = wScriptEntry + 1;
  2690. break;
  2691. case 0x0002:
  2692. //
  2693. // Stop running and replace the entry with the specified one
  2694. //
  2695. if (pScript->rgwOperand[1] == 0 ||
  2696. ++(pEvtObj->nScriptIdleFrame) < pScript->rgwOperand[1])
  2697. {
  2698. fEnded = TRUE;
  2699. wNextScriptEntry = pScript->rgwOperand[0];
  2700. }
  2701. else
  2702. {
  2703. //
  2704. // failed
  2705. //
  2706. pEvtObj->nScriptIdleFrame = 0;
  2707. wScriptEntry++;
  2708. }
  2709. break;
  2710. case 0x0003:
  2711. //
  2712. // unconditional jump
  2713. //
  2714. if (pScript->rgwOperand[1] == 0 ||
  2715. ++(pEvtObj->nScriptIdleFrame) < pScript->rgwOperand[1])
  2716. {
  2717. wScriptEntry = pScript->rgwOperand[0];
  2718. }
  2719. else
  2720. {
  2721. //
  2722. // failed
  2723. //
  2724. pEvtObj->nScriptIdleFrame = 0;
  2725. wScriptEntry++;
  2726. }
  2727. break;
  2728. case 0x0004:
  2729. //
  2730. // Call script
  2731. //
  2732. PAL_RunTriggerScript(pScript->rgwOperand[0],
  2733. ((pScript->rgwOperand[1] == 0) ? wEventObjectID : pScript->rgwOperand[1]));
  2734. wScriptEntry++;
  2735. break;
  2736. case 0x0005:
  2737. //
  2738. // Redraw screen
  2739. //
  2740. PAL_ClearDialog(TRUE);
  2741. if (PAL_DialogIsPlayingRNG())
  2742. {
  2743. VIDEO_RestoreScreen();
  2744. }
  2745. else if (gpGlobals->fInBattle)
  2746. {
  2747. PAL_BattleMakeScene();
  2748. SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);
  2749. VIDEO_UpdateScreen(NULL);
  2750. }
  2751. else
  2752. {
  2753. if (pScript->rgwOperand[2])
  2754. {
  2755. PAL_UpdatePartyGestures(FALSE);
  2756. }
  2757. PAL_MakeScene();
  2758. VIDEO_UpdateScreen(NULL);
  2759. UTIL_Delay((pScript->rgwOperand[1] == 0) ? 60 : (pScript->rgwOperand[1] * 60));
  2760. }
  2761. wScriptEntry++;
  2762. break;
  2763. case 0x0006:
  2764. //
  2765. // Jump to the specified address by the specified rate
  2766. //
  2767. if (RandomLong(1, 100) >= pScript->rgwOperand[0])
  2768. {
  2769. wScriptEntry = pScript->rgwOperand[1];
  2770. continue;
  2771. }
  2772. else
  2773. {
  2774. wScriptEntry++;
  2775. }
  2776. break;
  2777. case 0x0007:
  2778. //
  2779. // Start battle
  2780. //
  2781. i = PAL_StartBattle(pScript->rgwOperand[0], !pScript->rgwOperand[2]);
  2782. if (i == kBattleResultLost && pScript->rgwOperand[1] != 0)
  2783. {
  2784. wScriptEntry = pScript->rgwOperand[1];
  2785. }
  2786. else if (i == kBattleResultFleed && pScript->rgwOperand[2] != 0)
  2787. {
  2788. wScriptEntry = pScript->rgwOperand[2];
  2789. }
  2790. else
  2791. {
  2792. wScriptEntry++;
  2793. }
  2794. gpGlobals->fAutoBattle = FALSE;
  2795. break;
  2796. case 0x0008:
  2797. //
  2798. // Replace the entry with the next instruction
  2799. //
  2800. wScriptEntry++;
  2801. wNextScriptEntry = wScriptEntry;
  2802. break;
  2803. case 0x0009:
  2804. //
  2805. // wait for the specified number of frames
  2806. //
  2807. {
  2808. DWORD time;
  2809. PAL_ClearDialog(TRUE);
  2810. time = SDL_GetTicks() + FRAME_TIME;
  2811. for (i = 0; i < (pScript->rgwOperand[0] ? pScript->rgwOperand[0] : 1); i++)
  2812. {
  2813. PAL_ProcessEvent();
  2814. while (SDL_GetTicks() < time)
  2815. {
  2816. PAL_ProcessEvent();
  2817. SDL_Delay(1);
  2818. }
  2819. time = SDL_GetTicks() + FRAME_TIME;
  2820. if (pScript->rgwOperand[2])
  2821. {
  2822. PAL_UpdatePartyGestures(FALSE);
  2823. }
  2824. PAL_GameUpdate(pScript->rgwOperand[1] ? TRUE : FALSE);
  2825. PAL_MakeScene();
  2826. VIDEO_UpdateScreen(NULL);
  2827. }
  2828. }
  2829. wScriptEntry++;
  2830. break;
  2831. case 0x000A:
  2832. //
  2833. // Goto the specified address if player selected no
  2834. //
  2835. PAL_ClearDialog(FALSE);
  2836. if (!PAL_ConfirmMenu())
  2837. {
  2838. wScriptEntry = pScript->rgwOperand[0];
  2839. }
  2840. else
  2841. {
  2842. wScriptEntry++;
  2843. }
  2844. break;
  2845. case 0x003B:
  2846. //
  2847. // Show dialog in the middle part of the screen
  2848. //
  2849. PAL_ClearDialog(TRUE);
  2850. PAL_StartDialog(kDialogCenter, (BYTE)pScript->rgwOperand[0], 0,
  2851. pScript->rgwOperand[2] ? TRUE : FALSE);
  2852. wScriptEntry++;
  2853. break;
  2854. case 0x003C:
  2855. //
  2856. // Show dialog in the upper part of the screen
  2857. //
  2858. PAL_ClearDialog(TRUE);
  2859. PAL_StartDialog(kDialogUpper, (BYTE)pScript->rgwOperand[1],
  2860. pScript->rgwOperand[0], pScript->rgwOperand[2] ? TRUE : FALSE);
  2861. wScriptEntry++;
  2862. break;
  2863. case 0x003D:
  2864. //
  2865. // Show dialog in the lower part of the screen
  2866. //
  2867. PAL_ClearDialog(TRUE);
  2868. PAL_StartDialog(kDialogLower, (BYTE)pScript->rgwOperand[1],
  2869. pScript->rgwOperand[0], pScript->rgwOperand[2] ? TRUE : FALSE);
  2870. wScriptEntry++;
  2871. break;
  2872. case 0x003E:
  2873. //
  2874. // Show text in a window at the center of the screen
  2875. //
  2876. PAL_ClearDialog(TRUE);
  2877. PAL_StartDialog(kDialogCenterWindow, (BYTE)pScript->rgwOperand[0], 0, FALSE);
  2878. wScriptEntry++;
  2879. break;
  2880. case 0x008E:
  2881. //
  2882. // Restore the screen
  2883. //
  2884. PAL_ClearDialog(TRUE);
  2885. VIDEO_RestoreScreen();
  2886. VIDEO_UpdateScreen(NULL);
  2887. wScriptEntry++;
  2888. break;
  2889. case 0xFFFF:
  2890. //
  2891. // Print dialog text
  2892. //
  2893. // Support for Japanese
  2894. // If the second parameter is zero, then follow the standard behavior
  2895. // Otherwise, use the extended behavior
  2896. if (pScript->rgwOperand[1] == 0)
  2897. {
  2898. PAL_ShowDialogText(PAL_GetMsg(pScript->rgwOperand[0]));
  2899. wScriptEntry++;
  2900. }
  2901. else
  2902. {
  2903. // If the second parameter is set to 2, first display the text
  2904. if (pScript->rgwOperand[1] == 2)
  2905. {
  2906. PAL_ShowDialogText(PAL_GetMsg(pScript->rgwOperand[0]));
  2907. }
  2908. // Then, jump to script given by the third parameter.
  2909. wScriptEntry = pScript->rgwOperand[2];
  2910. }
  2911. break;
  2912. default:
  2913. PAL_ClearDialog(TRUE);
  2914. wScriptEntry = PAL_InterpretInstruction(wScriptEntry, wEventObjectID);
  2915. break;
  2916. }
  2917. }
  2918. PAL_EndDialog();
  2919. g_iCurEquipPart = -1;
  2920. return wNextScriptEntry;
  2921. }
  2922. WORD
  2923. PAL_RunAutoScript(
  2924. WORD wScriptEntry,
  2925. WORD wEventObjectID
  2926. )
  2927. /*++
  2928. Purpose:
  2929. Runs the autoscript of the specified event object.
  2930. Parameters:
  2931. [IN] wScriptEntry - The script entry to execute.
  2932. [IN] wEventObjectID - The event object ID which invoked the script.
  2933. Return value:
  2934. The address of the next script instruction to execute.
  2935. --*/
  2936. {
  2937. LPSCRIPTENTRY pScript;
  2938. LPEVENTOBJECT pEvtObj;
  2939. int iDescLine = 0;
  2940. begin:
  2941. pScript = &(gpGlobals->g.lprgScriptEntry[wScriptEntry]);
  2942. pEvtObj = &(gpGlobals->g.lprgEventObject[wEventObjectID - 1]);
  2943. //
  2944. // For autoscript, we should interpret one instruction per frame (except
  2945. // jumping) and save the address of next instruction.
  2946. //
  2947. switch (pScript->wOperation)
  2948. {
  2949. case 0x0000:
  2950. //
  2951. // Stop running
  2952. //
  2953. break;
  2954. case 0x0001:
  2955. //
  2956. // Stop running and replace the entry with the next line
  2957. //
  2958. wScriptEntry++;
  2959. break;
  2960. case 0x0002:
  2961. //
  2962. // Stop running and replace the entry with the specified one
  2963. //
  2964. if (pScript->rgwOperand[1] == 0 ||
  2965. ++(pEvtObj->wScriptIdleFrameCountAuto) < pScript->rgwOperand[1])
  2966. {
  2967. wScriptEntry = pScript->rgwOperand[0];
  2968. }
  2969. else
  2970. {
  2971. pEvtObj->wScriptIdleFrameCountAuto = 0;
  2972. wScriptEntry++;
  2973. }
  2974. break;
  2975. case 0x0003:
  2976. //
  2977. // unconditional jump
  2978. //
  2979. if (pScript->rgwOperand[1] == 0 ||
  2980. ++(pEvtObj->wScriptIdleFrameCountAuto) < pScript->rgwOperand[1])
  2981. {
  2982. wScriptEntry = pScript->rgwOperand[0];
  2983. goto begin;
  2984. }
  2985. else
  2986. {
  2987. pEvtObj->wScriptIdleFrameCountAuto = 0;
  2988. wScriptEntry++;
  2989. }
  2990. break;
  2991. case 0x0004:
  2992. //
  2993. // Call subroutine
  2994. //
  2995. PAL_RunTriggerScript(pScript->rgwOperand[0],
  2996. pScript->rgwOperand[1] ? pScript->rgwOperand[1] : wEventObjectID);
  2997. wScriptEntry++;
  2998. break;
  2999. case 0x0006:
  3000. //
  3001. // jump to the specified address by the specified rate
  3002. //
  3003. if (RandomLong(1, 100) >= pScript->rgwOperand[0] && pScript->rgwOperand[1] != 0)
  3004. {
  3005. wScriptEntry = pScript->rgwOperand[1];
  3006. goto begin;
  3007. }
  3008. else
  3009. {
  3010. wScriptEntry++;
  3011. }
  3012. break;
  3013. case 0x0009:
  3014. //
  3015. // Wait for a certain number of frames
  3016. //
  3017. if (++(pEvtObj->wScriptIdleFrameCountAuto) >= pScript->rgwOperand[0])
  3018. {
  3019. //
  3020. // waiting ended; go further
  3021. //
  3022. pEvtObj->wScriptIdleFrameCountAuto = 0;
  3023. wScriptEntry++;
  3024. }
  3025. break;
  3026. case 0xFFFF:
  3027. if (gpGlobals->fIsWIN95)
  3028. {
  3029. // Support for Japanese
  3030. // If the second parameter is zero, then follow the standard behavior
  3031. // Otherwise, use the extended behavior
  3032. // Either zero or two displays text
  3033. if (pScript->rgwOperand[1] == 0 || pScript->rgwOperand[1] == 2)
  3034. {
  3035. iDescLine = (wEventObjectID & ~PAL_ITEM_DESC_BOTTOM);
  3036. if (wEventObjectID & PAL_ITEM_DESC_BOTTOM)
  3037. {
  3038. int YOffset = gpGlobals->dwExtraItemDescLines * 16;
  3039. PAL_DrawText(PAL_GetMsg(pScript->rgwOperand[0]), PAL_XY(75, iDescLine * 16 + 150 - YOffset), DESCTEXT_COLOR, TRUE, FALSE);
  3040. }
  3041. else
  3042. {
  3043. PAL_DrawText(PAL_GetMsg(pScript->rgwOperand[0]), PAL_XY(100, iDescLine * 16 + 3), DESCTEXT_COLOR, TRUE, FALSE);
  3044. }
  3045. iDescLine++;
  3046. }
  3047. if (pScript->rgwOperand[1] != 0)
  3048. {
  3049. // Then, jump to script given by the third parameter.
  3050. wScriptEntry = pScript->rgwOperand[2];
  3051. }
  3052. else
  3053. {
  3054. wScriptEntry++;
  3055. }
  3056. }
  3057. else
  3058. {
  3059. wScriptEntry++;
  3060. }
  3061. break;
  3062. case 0x00A7:
  3063. wScriptEntry++;
  3064. break;
  3065. default:
  3066. //
  3067. // Other operations
  3068. //
  3069. wScriptEntry = PAL_InterpretInstruction(wScriptEntry, wEventObjectID);
  3070. break;
  3071. }
  3072. return wScriptEntry;
  3073. }