scene.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  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. // Portions based on PALx Project by palxex.
  7. // Copyright (c) 2006, 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. #include "main.h"
  25. #define MAX_SPRITE_TO_DRAW 2048
  26. typedef struct tagSPRITE_TO_DRAW
  27. {
  28. LPCBITMAPRLE lpSpriteFrame; // pointer to the frame bitmap
  29. PAL_POS pos; // position on the scene
  30. int iLayer; // logical layer
  31. } SPRITE_TO_DRAW;
  32. static SPRITE_TO_DRAW g_rgSpriteToDraw[MAX_SPRITE_TO_DRAW];
  33. static int g_nSpriteToDraw;
  34. static VOID
  35. PAL_AddSpriteToDraw(
  36. LPCBITMAPRLE lpSpriteFrame,
  37. int x,
  38. int y,
  39. int iLayer
  40. )
  41. /*++
  42. Purpose:
  43. Add a sprite to our list of drawing.
  44. Parameters:
  45. [IN] lpSpriteFrame - the bitmap of the sprite frame.
  46. [IN] x - the X coordinate on the screen.
  47. [IN] y - the Y coordinate on the screen.
  48. [IN] iLayer - the layer of the sprite.
  49. Return value:
  50. None.
  51. --*/
  52. {
  53. assert(g_nSpriteToDraw < MAX_SPRITE_TO_DRAW);
  54. g_rgSpriteToDraw[g_nSpriteToDraw].lpSpriteFrame = lpSpriteFrame;
  55. g_rgSpriteToDraw[g_nSpriteToDraw].pos = PAL_XY(x, y);
  56. g_rgSpriteToDraw[g_nSpriteToDraw].iLayer = iLayer;
  57. g_nSpriteToDraw++;
  58. }
  59. static VOID
  60. PAL_CalcCoverTiles(
  61. SPRITE_TO_DRAW *lpSpriteToDraw
  62. )
  63. /*++
  64. Purpose:
  65. Calculate all the tiles which may cover the specified sprite. Add the tiles
  66. into our list as well.
  67. Parameters:
  68. [IN] lpSpriteToDraw - pointer to SPRITE_TO_DRAW struct.
  69. Return value:
  70. None.
  71. --*/
  72. {
  73. int x, y, i, l, iTileHeight;
  74. LPCBITMAPRLE lpTile;
  75. const int sx = PAL_X(gpGlobals->viewport) + PAL_X(lpSpriteToDraw->pos);
  76. const int sy = PAL_Y(gpGlobals->viewport) + PAL_Y(lpSpriteToDraw->pos);
  77. const int sh = ((sx % 32) ? 1 : 0);
  78. const int width = PAL_RLEGetWidth(lpSpriteToDraw->lpSpriteFrame);
  79. const int height = PAL_RLEGetHeight(lpSpriteToDraw->lpSpriteFrame);
  80. int dx = 0;
  81. int dy = 0;
  82. int dh = 0;
  83. //
  84. // Loop through all the tiles in the area of the sprite.
  85. //
  86. for (y = (sy - height - 15) / 16; y <= sy / 16; y++)
  87. {
  88. for (x = (sx - width / 2) / 32; x <= (sx + width / 2) / 32; x++)
  89. {
  90. for (i = ((x == (sx - width / 2) / 32) ? 0 : 3); i < 5; i++)
  91. {
  92. //
  93. // Scan tiles in the following form (* = to scan):
  94. //
  95. // . . . * * * . . .
  96. // . . . * * . . . .
  97. //
  98. switch (i)
  99. {
  100. case 0:
  101. dx = x;
  102. dy = y;
  103. dh = sh;
  104. break;
  105. case 1:
  106. dx = x - 1;
  107. break;
  108. case 2:
  109. dx = (sh ? x : (x - 1));
  110. dy = (sh ? (y + 1) : y);
  111. dh = 1 - sh;
  112. break;
  113. case 3:
  114. dx = x + 1;
  115. dy = y;
  116. dh = sh;
  117. break;
  118. case 4:
  119. dx = (sh ? (x + 1) : x);
  120. dy = (sh ? (y + 1) : y);
  121. dh = 1 - sh;
  122. break;
  123. }
  124. for (l = 0; l < 2; l++)
  125. {
  126. lpTile = PAL_MapGetTileBitmap(dx, dy, dh, l, PAL_GetCurrentMap());
  127. iTileHeight = (signed char)PAL_MapGetTileHeight(dx, dy, dh, l, PAL_GetCurrentMap());
  128. //
  129. // Check if this tile may cover the sprites
  130. //
  131. if (lpTile != NULL && iTileHeight > 0 && (dy + iTileHeight) * 16 + dh * 8 >= sy)
  132. {
  133. //
  134. // This tile may cover the sprite
  135. //
  136. PAL_AddSpriteToDraw(lpTile,
  137. dx * 32 + dh * 16 - 16 - PAL_X(gpGlobals->viewport),
  138. dy * 16 + dh * 8 + 7 + l + iTileHeight * 8 - PAL_Y(gpGlobals->viewport),
  139. iTileHeight * 8 + l);
  140. }
  141. }
  142. }
  143. }
  144. }
  145. }
  146. static VOID
  147. PAL_SceneDrawSprites(
  148. VOID
  149. )
  150. /*++
  151. Purpose:
  152. Draw all the sprites to scene.
  153. Parameters:
  154. None.
  155. Return value:
  156. None.
  157. --*/
  158. {
  159. int i, x, y, vy;
  160. g_nSpriteToDraw = 0;
  161. //
  162. // Put all the sprites to be drawn into our array.
  163. //
  164. //
  165. // Players
  166. //
  167. for (i = 0; i <= (short)gpGlobals->wMaxPartyMemberIndex + gpGlobals->nFollower; i++)
  168. {
  169. LPCBITMAPRLE lpBitmap =
  170. PAL_SpriteGetFrame(PAL_GetPlayerSprite((BYTE)i), gpGlobals->rgParty[i].wFrame);
  171. if (lpBitmap == NULL)
  172. {
  173. continue;
  174. }
  175. //
  176. // Add it to our array
  177. //
  178. PAL_AddSpriteToDraw(lpBitmap,
  179. gpGlobals->rgParty[i].x - PAL_RLEGetWidth(lpBitmap) / 2,
  180. gpGlobals->rgParty[i].y + gpGlobals->wLayer + 10,
  181. gpGlobals->wLayer + 6);
  182. //
  183. // Calculate covering tiles on the map
  184. //
  185. PAL_CalcCoverTiles(&g_rgSpriteToDraw[g_nSpriteToDraw - 1]);
  186. }
  187. //
  188. // Event Objects (Monsters/NPCs/others)
  189. //
  190. for (i = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex;
  191. i < gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; i++)
  192. {
  193. LPCBITMAPRLE lpFrame;
  194. LPCSPRITE lpSprite;
  195. LPEVENTOBJECT lpEvtObj = &(gpGlobals->g.lprgEventObject[i]);
  196. int iFrame;
  197. if (lpEvtObj->sState == kObjStateHidden || lpEvtObj->sVanishTime > 0 ||
  198. lpEvtObj->sState < 0)
  199. {
  200. continue;
  201. }
  202. //
  203. // Get the sprite
  204. //
  205. lpSprite = PAL_GetEventObjectSprite((WORD)i + 1);
  206. if (lpSprite == NULL)
  207. {
  208. continue;
  209. }
  210. iFrame = lpEvtObj->wCurrentFrameNum;
  211. if (lpEvtObj->nSpriteFrames == 3)
  212. {
  213. //
  214. // walking character
  215. //
  216. if (iFrame == 2)
  217. {
  218. iFrame = 0;
  219. }
  220. if (iFrame == 3)
  221. {
  222. iFrame = 2;
  223. }
  224. }
  225. lpFrame = PAL_SpriteGetFrame(lpSprite,
  226. lpEvtObj->wDirection * lpEvtObj->nSpriteFrames + iFrame);
  227. if (lpFrame == NULL)
  228. {
  229. continue;
  230. }
  231. //
  232. // Calculate the coordinate and check if outside the screen
  233. //
  234. x = (SHORT)lpEvtObj->x - PAL_X(gpGlobals->viewport);
  235. x -= PAL_RLEGetWidth(lpFrame) / 2;
  236. if (x >= 320 || x < -(int)PAL_RLEGetWidth(lpFrame))
  237. {
  238. //
  239. // outside the screen; skip it
  240. //
  241. continue;
  242. }
  243. y = (SHORT)lpEvtObj->y - PAL_Y(gpGlobals->viewport);
  244. y += lpEvtObj->sLayer * 8 + 9;
  245. vy = y - PAL_RLEGetHeight(lpFrame) - lpEvtObj->sLayer * 8 + 2;
  246. if (vy >= 200 || vy < -(int)PAL_RLEGetHeight(lpFrame))
  247. {
  248. //
  249. // outside the screen; skip it
  250. //
  251. continue;
  252. }
  253. //
  254. // Add it into the array
  255. //
  256. PAL_AddSpriteToDraw(lpFrame, x, y, lpEvtObj->sLayer * 8 + 2);
  257. //
  258. // Calculate covering map tiles
  259. //
  260. PAL_CalcCoverTiles(&g_rgSpriteToDraw[g_nSpriteToDraw - 1]);
  261. }
  262. //
  263. // All sprites are now in our array; sort them by their vertical positions.
  264. //
  265. for (x = 0; x < g_nSpriteToDraw - 1; x++)
  266. {
  267. SPRITE_TO_DRAW tmp;
  268. BOOL fSwap = FALSE;
  269. for (y = 0; y < g_nSpriteToDraw - 1 - x; y++)
  270. {
  271. if (PAL_Y(g_rgSpriteToDraw[y].pos) > PAL_Y(g_rgSpriteToDraw[y + 1].pos))
  272. {
  273. fSwap = TRUE;
  274. tmp = g_rgSpriteToDraw[y];
  275. g_rgSpriteToDraw[y] = g_rgSpriteToDraw[y + 1];
  276. g_rgSpriteToDraw[y + 1] = tmp;
  277. }
  278. }
  279. if (!fSwap)
  280. {
  281. break;
  282. }
  283. }
  284. //
  285. // Draw all the sprites to the screen.
  286. //
  287. for (i = 0; i < g_nSpriteToDraw; i++)
  288. {
  289. SPRITE_TO_DRAW *p = &g_rgSpriteToDraw[i];
  290. x = PAL_X(p->pos);
  291. y = PAL_Y(p->pos) - PAL_RLEGetHeight(p->lpSpriteFrame) - p->iLayer;
  292. PAL_RLEBlitToSurface(p->lpSpriteFrame, gpScreen, PAL_XY(x, y));
  293. }
  294. }
  295. VOID
  296. PAL_ApplyWave(
  297. SDL_Surface *lpSurface
  298. )
  299. /*++
  300. Purpose:
  301. Apply screen waving effect when needed.
  302. Parameters:
  303. [OUT] lpSurface - the surface to be proceed.
  304. Return value:
  305. None.
  306. --*/
  307. {
  308. int wave[32];
  309. int i, a, b;
  310. static int index = 0;
  311. LPBYTE p;
  312. BYTE buf[320];
  313. gpGlobals->wScreenWave += gpGlobals->sWaveProgression;
  314. if (gpGlobals->wScreenWave == 0 || gpGlobals->wScreenWave >= 256)
  315. {
  316. //
  317. // No need to wave the screen
  318. //
  319. gpGlobals->wScreenWave = 0;
  320. gpGlobals->sWaveProgression = 0;
  321. return;
  322. }
  323. //
  324. // Calculate the waving offsets.
  325. //
  326. a = 0;
  327. b = 60 + 8;
  328. for (i = 0; i < 16; i++)
  329. {
  330. b -= 8;
  331. a += b;
  332. //
  333. // WARNING: assuming the screen width is 320
  334. //
  335. wave[i] = a * gpGlobals->wScreenWave / 256;
  336. wave[i + 16] = 320 - wave[i];
  337. }
  338. //
  339. // Apply the effect.
  340. // WARNING: only works with 320x200 8-bit surface.
  341. //
  342. a = index;
  343. p = (LPBYTE)(lpSurface->pixels);
  344. //
  345. // Loop through all lines in the screen buffer.
  346. //
  347. for (i = 0; i < 200; i++)
  348. {
  349. b = wave[a];
  350. if (b > 0)
  351. {
  352. //
  353. // Do a shift on the current line with the calculated offset.
  354. //
  355. memcpy(buf, p, b);
  356. //memmove(p, p + b, 320 - b);
  357. memmove(p, &p[b], 320 - b);
  358. //memcpy(p + 320 - b, buf, b);
  359. memcpy(&p[320 - b], buf, b);
  360. }
  361. a = (a + 1) % 32;
  362. p += lpSurface->pitch;
  363. }
  364. index = (index + 1) % 32;
  365. }
  366. VOID
  367. PAL_MakeScene(
  368. VOID
  369. )
  370. /*++
  371. Purpose:
  372. Draw the scene of the current frame to the screen. Both the map and
  373. the sprites are handled here.
  374. Parameters:
  375. None.
  376. Return value:
  377. None.
  378. --*/
  379. {
  380. static SDL_Rect rect = {0, 0, 320, 200};
  381. //
  382. // Step 1: Draw the complete map, for both of the layers.
  383. //
  384. rect.x = PAL_X(gpGlobals->viewport);
  385. rect.y = PAL_Y(gpGlobals->viewport);
  386. PAL_MapBlitToSurface(PAL_GetCurrentMap(), gpScreen, &rect, 0);
  387. PAL_MapBlitToSurface(PAL_GetCurrentMap(), gpScreen, &rect, 1);
  388. //
  389. // Step 2: Apply screen waving effects.
  390. //
  391. PAL_ApplyWave(gpScreen);
  392. //
  393. // Step 3: Draw all the sprites.
  394. //
  395. PAL_SceneDrawSprites();
  396. //
  397. // Check if we need to fade in.
  398. //
  399. if (gpGlobals->fNeedToFadeIn)
  400. {
  401. VIDEO_UpdateScreen(NULL);
  402. PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1);
  403. gpGlobals->fNeedToFadeIn = FALSE;
  404. }
  405. }
  406. BOOL
  407. PAL_CheckObstacle(
  408. PAL_POS pos,
  409. BOOL fCheckEventObjects,
  410. WORD wSelfObject
  411. )
  412. /*++
  413. Purpose:
  414. Check if the specified location has obstacle or not.
  415. Parameters:
  416. [IN] pos - the position to check.
  417. [IN] fCheckEventObjects - TRUE if check for event objects, FALSE if only
  418. check for the map.
  419. [IN] wSelfObject - the event object which will be skipped.
  420. Return value:
  421. TRUE if the location is obstacle, FALSE if not.
  422. --*/
  423. {
  424. int x, y, h, xr, yr;
  425. if (PAL_X(pos) < 0 || PAL_X(pos) >= 2048 || PAL_Y(pos) < 0 || PAL_Y(pos) >= 2048)
  426. {
  427. return TRUE;
  428. }
  429. //
  430. // Check if the map tile at the specified position is blocking
  431. //
  432. x = PAL_X(pos) / 32;
  433. y = PAL_Y(pos) / 16;
  434. h = 0;
  435. xr = PAL_X(pos) % 32;
  436. yr = PAL_Y(pos) % 16;
  437. if (xr + yr * 2 >= 16)
  438. {
  439. if (xr + yr * 2 >= 48)
  440. {
  441. x++;
  442. y++;
  443. }
  444. else if (32 - xr + yr * 2 < 16)
  445. {
  446. x++;
  447. }
  448. else if (32 - xr + yr * 2 < 48)
  449. {
  450. h = 1;
  451. }
  452. else
  453. {
  454. y++;
  455. }
  456. }
  457. if (PAL_MapTileIsBlocked(x, y, h, PAL_GetCurrentMap()))
  458. {
  459. return TRUE;
  460. }
  461. if (fCheckEventObjects)
  462. {
  463. //
  464. // Loop through all event objects in the current scene
  465. //
  466. int i;
  467. for (i = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex;
  468. i < gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; i++)
  469. {
  470. LPEVENTOBJECT p = &(gpGlobals->g.lprgEventObject[i]);
  471. if (i == wSelfObject - 1)
  472. {
  473. //
  474. // Skip myself
  475. //
  476. continue;
  477. }
  478. //
  479. // Is this object a blocking one?
  480. //
  481. if (p->sState >= kObjStateBlocker)
  482. {
  483. //
  484. // Check for collision
  485. //
  486. if (abs(p->x - PAL_X(pos)) + abs(p->y - PAL_Y(pos)) * 2 < 16)
  487. {
  488. return TRUE;
  489. }
  490. }
  491. }
  492. }
  493. return FALSE;
  494. }
  495. VOID
  496. PAL_UpdatePartyGestures(
  497. BOOL fWalking
  498. )
  499. /*++
  500. Purpose:
  501. Update the gestures of all the party members.
  502. Parameters:
  503. [IN] fWalking - whether the party is walking or not.
  504. Return value:
  505. None.
  506. --*/
  507. {
  508. static int s_iThisStepFrame = 0;
  509. int iStepFrameFollower = 0, iStepFrameLeader = 0;
  510. int i;
  511. if (fWalking)
  512. {
  513. //
  514. // Update the gesture for party leader
  515. //
  516. s_iThisStepFrame = (s_iThisStepFrame + 1) % 4;
  517. if (s_iThisStepFrame & 1)
  518. {
  519. iStepFrameLeader = (s_iThisStepFrame + 1) / 2;
  520. iStepFrameFollower = 3 - iStepFrameLeader;
  521. }
  522. else
  523. {
  524. iStepFrameLeader = 0;
  525. iStepFrameFollower = 0;
  526. }
  527. gpGlobals->rgParty[0].x = PAL_X(gpGlobals->partyoffset);
  528. gpGlobals->rgParty[0].y = PAL_Y(gpGlobals->partyoffset);
  529. if (gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[0].wPlayerRole] == 4)
  530. {
  531. gpGlobals->rgParty[0].wFrame = gpGlobals->wPartyDirection * 4 + s_iThisStepFrame;
  532. }
  533. else
  534. {
  535. gpGlobals->rgParty[0].wFrame = gpGlobals->wPartyDirection * 3 + iStepFrameLeader;
  536. }
  537. //
  538. // Update the gestures and positions for other party members
  539. //
  540. for (i = 1; i <= (short)gpGlobals->wMaxPartyMemberIndex; i++)
  541. {
  542. gpGlobals->rgParty[i].x = gpGlobals->rgTrail[1].x - PAL_X(gpGlobals->viewport);
  543. gpGlobals->rgParty[i].y = gpGlobals->rgTrail[1].y - PAL_Y(gpGlobals->viewport);
  544. if (i == 2)
  545. {
  546. gpGlobals->rgParty[i].x +=
  547. (gpGlobals->rgTrail[1].wDirection == kDirEast || gpGlobals->rgTrail[1].wDirection == kDirWest) ? -16 : 16;
  548. gpGlobals->rgParty[i].y += 8;
  549. }
  550. else
  551. {
  552. gpGlobals->rgParty[i].x +=
  553. ((gpGlobals->rgTrail[1].wDirection == kDirWest || gpGlobals->rgTrail[1].wDirection == kDirSouth) ? 16 : -16);
  554. gpGlobals->rgParty[i].y +=
  555. ((gpGlobals->rgTrail[1].wDirection == kDirWest || gpGlobals->rgTrail[1].wDirection == kDirNorth) ? 8 : -8);
  556. }
  557. //
  558. // Adjust the position if there is obstacle
  559. //
  560. if (PAL_CheckObstacle(PAL_XY(gpGlobals->rgParty[i].x + PAL_X(gpGlobals->viewport),
  561. gpGlobals->rgParty[i].y + PAL_Y(gpGlobals->viewport)), TRUE, 0))
  562. {
  563. gpGlobals->rgParty[i].x = gpGlobals->rgTrail[1].x - PAL_X(gpGlobals->viewport);
  564. gpGlobals->rgParty[i].y = gpGlobals->rgTrail[1].y - PAL_Y(gpGlobals->viewport);
  565. }
  566. //
  567. // Update gesture for this party member
  568. //
  569. if (gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[i].wPlayerRole] == 4)
  570. {
  571. gpGlobals->rgParty[i].wFrame = gpGlobals->rgTrail[2].wDirection * 4 + s_iThisStepFrame;
  572. }
  573. else
  574. {
  575. gpGlobals->rgParty[i].wFrame = gpGlobals->rgTrail[2].wDirection * 3 + iStepFrameLeader;
  576. }
  577. }
  578. if (gpGlobals->nFollower > 0)
  579. {
  580. //
  581. // Update the position and gesture for the follower
  582. //
  583. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].x =
  584. gpGlobals->rgTrail[3].x - PAL_X(gpGlobals->viewport);
  585. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].y =
  586. gpGlobals->rgTrail[3].y - PAL_Y(gpGlobals->viewport);
  587. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].wFrame =
  588. gpGlobals->rgTrail[3].wDirection * 3 + iStepFrameFollower;
  589. }
  590. }
  591. else
  592. {
  593. //
  594. // Player is not moved. Use the "standing" gesture instead of "walking" one.
  595. //
  596. i = gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[0].wPlayerRole];
  597. if (i == 0)
  598. {
  599. i = 3;
  600. }
  601. gpGlobals->rgParty[0].wFrame = gpGlobals->wPartyDirection * i;
  602. for (i = 1; i <= (short)gpGlobals->wMaxPartyMemberIndex; i++)
  603. {
  604. int f = gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[i].wPlayerRole];
  605. if (f == 0)
  606. {
  607. f = 3;
  608. }
  609. gpGlobals->rgParty[i].wFrame = gpGlobals->rgTrail[2].wDirection * f;
  610. }
  611. if (gpGlobals->nFollower > 0)
  612. {
  613. gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].wFrame =
  614. gpGlobals->rgTrail[3].wDirection * 3;
  615. }
  616. s_iThisStepFrame &= 2;
  617. s_iThisStepFrame ^= 2;
  618. }
  619. }
  620. VOID
  621. PAL_UpdateParty(
  622. VOID
  623. )
  624. /*++
  625. Purpose:
  626. Update the location and walking gesture of all the party members.
  627. Parameters:
  628. None.
  629. Return value:
  630. None.
  631. --*/
  632. {
  633. int xSource, ySource, xTarget, yTarget, xOffset, yOffset, i;
  634. //
  635. // Has user pressed one of the arrow keys?
  636. //
  637. if (g_InputState.dir != kDirUnknown)
  638. {
  639. xOffset = ((g_InputState.dir == kDirWest || g_InputState.dir == kDirSouth) ? -16 : 16);
  640. yOffset = ((g_InputState.dir == kDirWest || g_InputState.dir == kDirNorth) ? -8 : 8);
  641. xSource = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset);
  642. ySource = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset);
  643. xTarget = xSource + xOffset;
  644. yTarget = ySource + yOffset;
  645. gpGlobals->wPartyDirection = g_InputState.dir;
  646. //
  647. // Check for obstacles on the destination location
  648. //
  649. if (!PAL_CheckObstacle(PAL_XY(xTarget, yTarget), TRUE, 0))
  650. {
  651. //
  652. // Player will actually be moved. Store trail.
  653. //
  654. for (i = 3; i >= 0; i--)
  655. {
  656. gpGlobals->rgTrail[i + 1] = gpGlobals->rgTrail[i];
  657. }
  658. gpGlobals->rgTrail[0].wDirection = g_InputState.dir;
  659. gpGlobals->rgTrail[0].x = xSource;
  660. gpGlobals->rgTrail[0].y = ySource;
  661. //
  662. // Move the viewport
  663. //
  664. gpGlobals->viewport =
  665. PAL_XY(PAL_X(gpGlobals->viewport) + xOffset, PAL_Y(gpGlobals->viewport) + yOffset);
  666. //
  667. // Update gestures
  668. //
  669. PAL_UpdatePartyGestures(TRUE);
  670. return; // don't go further
  671. }
  672. }
  673. PAL_UpdatePartyGestures(FALSE);
  674. }
  675. VOID
  676. PAL_NPCWalkOneStep(
  677. WORD wEventObjectID,
  678. INT iSpeed
  679. )
  680. /*++
  681. Purpose:
  682. Move and animate the specified event object (NPC).
  683. Parameters:
  684. [IN] wEventObjectID - the event object to move.
  685. [IN] iSpeed - speed of the movement.
  686. Return value:
  687. None.
  688. --*/
  689. {
  690. LPEVENTOBJECT p;
  691. //
  692. // Check for invalid parameters
  693. //
  694. if (wEventObjectID == 0 || wEventObjectID > gpGlobals->g.nEventObject)
  695. {
  696. return;
  697. }
  698. p = &(gpGlobals->g.lprgEventObject[wEventObjectID - 1]);
  699. //
  700. // Move the event object by the specified direction
  701. //
  702. p->x += ((p->wDirection == kDirWest || p->wDirection == kDirSouth) ? -2 : 2) * iSpeed;
  703. p->y += ((p->wDirection == kDirWest || p->wDirection == kDirNorth) ? -1 : 1) * iSpeed;
  704. //
  705. // Update the gesture
  706. //
  707. if (p->nSpriteFrames > 0)
  708. {
  709. p->wCurrentFrameNum++;
  710. p->wCurrentFrameNum %= (p->nSpriteFrames == 3 ? 4 : p->nSpriteFrames);
  711. }
  712. else if (p->nSpriteFramesAuto > 0)
  713. {
  714. p->wCurrentFrameNum++;
  715. p->wCurrentFrameNum %= p->nSpriteFramesAuto;
  716. }
  717. }