sprite.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. * Copyright (C) 2002 Gilead Kutnick - exophase@adelphia.net
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. // sprite.cpp, by Exophase
  23. // Global declarations:
  24. #include <stdlib.h>
  25. #include "data.h"
  26. #include "sprite.h"
  27. #include "graphics.h"
  28. #include "idput.h"
  29. #include "error.h"
  30. #include "game.h"
  31. #include "world.h"
  32. // FIXME - Collision rectangles against char backgrounds (ccheck1/2)
  33. // need to be clipped against the edges of the boards...
  34. void plot_sprite(World *mzx_world, Sprite *cur_sprite, int color, int x, int y)
  35. {
  36. if(((cur_sprite->width) && (cur_sprite->height)))
  37. {
  38. cur_sprite->x = x;
  39. cur_sprite->y = y;
  40. if(color == 288)
  41. {
  42. cur_sprite->flags |= SPRITE_SRC_COLORS;
  43. }
  44. else
  45. {
  46. cur_sprite->flags &= ~SPRITE_SRC_COLORS;
  47. cur_sprite->color = color;
  48. }
  49. if(!(cur_sprite->flags & SPRITE_INITIALIZED))
  50. {
  51. cur_sprite->flags |= SPRITE_INITIALIZED;
  52. mzx_world->active_sprites++;
  53. }
  54. }
  55. }
  56. // For the qsort.
  57. int compare_spr(const void *dest, const void *src);
  58. int compare_spr(const void *dest, const void *src)
  59. {
  60. Sprite *spr_dest = *((Sprite **)dest);
  61. Sprite *spr_src = *((Sprite **)src);
  62. return ((spr_dest->y + spr_dest->col_y) -
  63. (spr_src->y + spr_src->col_y));
  64. }
  65. void draw_sprites(World *mzx_world)
  66. {
  67. Board *src_board = mzx_world->current_board;
  68. int num_sprites = mzx_world->num_sprites;
  69. int i, i2, i3, i4, i5, i6, st_x, st_y, of_x, of_y, d;
  70. int skip, skip2, skip3;
  71. int dr_w, dr_h, ref_x, ref_y, scr_x, scr_y;
  72. int bwidth, bheight, use_chars = 1;
  73. int uvlayer = 0;
  74. Sprite **sprite_list = mzx_world->sprite_list;
  75. Sprite *dr_order[MAX_SPRITES];
  76. Sprite *cur_sprite;
  77. unsigned char ch, color, dcolor;
  78. int viewport_x = src_board->viewport_x;
  79. int viewport_y = src_board->viewport_y;
  80. int viewport_width = src_board->viewport_width;
  81. int viewport_height = src_board->viewport_height;
  82. int board_width = src_board->board_width;
  83. int overlay_mode = src_board->overlay_mode;
  84. char *overlay = src_board->overlay;
  85. char *overlay_color = src_board->overlay_color;
  86. char *src_chars;
  87. char *src_colors;
  88. // see if y sort should be done
  89. if(mzx_world->sprite_y_order)
  90. {
  91. // Switched to stdlib qsort. Hooray!
  92. // Fill it with the active sprites in the beginning
  93. // and the inactive sprites in the end.
  94. for(i = 0, i2 = 0, i3 = MAX_SPRITES - 1; i < MAX_SPRITES; i++)
  95. {
  96. if((sprite_list[i])->flags & SPRITE_INITIALIZED)
  97. {
  98. dr_order[i2] = sprite_list[i];
  99. i2++;
  100. }
  101. else
  102. {
  103. dr_order[i3] = sprite_list[i];
  104. i3--;
  105. }
  106. }
  107. // Now sort it, using qsort.
  108. qsort(dr_order, i2, sizeof(Sprite *), compare_spr);
  109. }
  110. // draw this on top of the SCREEN window.
  111. for(i = 0; i < MAX_SPRITES; i++)
  112. {
  113. if(mzx_world->sprite_y_order)
  114. {
  115. cur_sprite = dr_order[i];
  116. }
  117. else
  118. {
  119. cur_sprite = sprite_list[i];
  120. }
  121. if(cur_sprite->flags & SPRITE_INITIALIZED)
  122. {
  123. calculate_xytop(mzx_world, &scr_x, &scr_y);
  124. ref_x = cur_sprite->ref_x;
  125. ref_y = cur_sprite->ref_y;
  126. of_x = 0;
  127. of_y = 0;
  128. st_x = (cur_sprite->x + viewport_x);
  129. st_y = (cur_sprite->y + viewport_y);
  130. if(!(cur_sprite->flags & SPRITE_STATIC))
  131. {
  132. st_x -= scr_x;
  133. st_y -= scr_y;
  134. }
  135. dr_w = cur_sprite->width;
  136. dr_h = cur_sprite->height;
  137. // clip draw position against viewport
  138. if(st_x < viewport_x)
  139. {
  140. of_x = viewport_x - st_x;
  141. dr_w -= of_x;
  142. if(dr_w < 1) continue;
  143. st_x = viewport_x;
  144. }
  145. if(st_y < viewport_y)
  146. {
  147. of_y = viewport_y - st_y;
  148. dr_h -= of_y;
  149. if(dr_h < 1) continue;
  150. st_y = viewport_y;
  151. }
  152. if((st_x > (viewport_x + viewport_width)) ||
  153. (st_y > (viewport_y + viewport_height))) continue;
  154. if((st_x + dr_w) > (viewport_x + viewport_width))
  155. {
  156. dr_w = viewport_x + viewport_width - st_x;
  157. }
  158. if((st_y + dr_h) > (viewport_y + viewport_height))
  159. {
  160. dr_h = viewport_y + viewport_height - st_y;
  161. }
  162. if(cur_sprite->flags & SPRITE_VLAYER)
  163. {
  164. use_chars = 1;
  165. bwidth = mzx_world->vlayer_width;
  166. bheight = mzx_world->vlayer_height;
  167. src_chars = mzx_world->vlayer_chars;
  168. src_colors = mzx_world->vlayer_colors;
  169. }
  170. else
  171. {
  172. use_chars = 0;
  173. bwidth = board_width;
  174. bheight = src_board->board_width;
  175. src_chars = src_board->level_param;
  176. src_colors = src_board->level_color;
  177. }
  178. if((ref_x + dr_w) > bwidth)
  179. dr_w = bwidth - ref_x;
  180. if((ref_y + dr_h) > bheight)
  181. dr_h = bheight - ref_y;
  182. i4 = ((ref_y + of_y) * bwidth) + ref_x + of_x;
  183. i5 = (st_y * 80) + st_x;
  184. if(overlay_mode == 2)
  185. {
  186. i6 = ((cur_sprite->y - scr_y) * board_width) + (cur_sprite->x - scr_x);
  187. }
  188. else
  189. {
  190. i6 = (cur_sprite->y * board_width) + cur_sprite->x;
  191. }
  192. skip = bwidth - dr_w;
  193. skip2 = 80 - dr_w;
  194. skip3 = board_width - dr_w;
  195. switch((cur_sprite->flags & 0x0C) >> 2)
  196. {
  197. // natural colors, over overlay
  198. case 3: // 11
  199. {
  200. for(i2 = 0; i2 < dr_h; i2++)
  201. {
  202. for(i3 = 0; i3 < dr_w; i3++)
  203. {
  204. color = src_colors[i4];
  205. if(use_chars)
  206. {
  207. ch = src_chars[i4];
  208. }
  209. else
  210. {
  211. ch = get_id_char(src_board, i4);
  212. }
  213. if(!(color & 0xF0))
  214. {
  215. color = (color & 0x0F) | (get_color_linear(i5) & 0xF0);
  216. }
  217. if(ch != 32)
  218. {
  219. if(!(cur_sprite->flags & SPRITE_CHAR_CHECK2) || !is_blank(ch))
  220. {
  221. draw_char_linear(color, ch, i5);
  222. }
  223. }
  224. i4++;
  225. i5++;
  226. }
  227. i4 += skip;
  228. i5 += skip2;
  229. }
  230. break;
  231. }
  232. // natural colors, under overlay
  233. case 2: // 10
  234. {
  235. for(i2 = 0; i2 < dr_h; i2++)
  236. {
  237. for(i3 = 0; i3 < dr_w; i3++)
  238. {
  239. color = src_colors[i4];
  240. if(use_chars)
  241. {
  242. ch = src_chars[i4];
  243. }
  244. else
  245. {
  246. ch = get_id_char(src_board, i4);
  247. }
  248. if(!(color & 0xF0))
  249. {
  250. color = (color & 0x0F) | (get_color_linear(i5) & 0xF0);
  251. }
  252. if((!overlay_mode || (overlay[i6] == 32)) && ch != 32)
  253. {
  254. if(!(cur_sprite->flags & SPRITE_CHAR_CHECK2) || !is_blank(ch))
  255. {
  256. draw_char_linear(color, ch, i5);
  257. }
  258. }
  259. i4++;
  260. i5++;
  261. i6++;
  262. }
  263. i4 += skip;
  264. i5 += skip2;
  265. i6 += skip3;
  266. }
  267. break;
  268. }
  269. // given colors, over overlay
  270. case 1: // 01
  271. {
  272. color = cur_sprite->color;
  273. for(i2 = 0; i2 < dr_h; i2++)
  274. {
  275. for(i3 = 0; i3 < dr_w; i3++)
  276. {
  277. if(use_chars)
  278. {
  279. ch = src_chars[i4];
  280. }
  281. else
  282. {
  283. ch = get_id_char(src_board, i4);
  284. }
  285. dcolor = color;
  286. if(!(color & 0xF0))
  287. {
  288. dcolor = (color & 0x0F) | (get_color_linear(i5) & 0xF0);
  289. }
  290. if(ch != 32)
  291. {
  292. if(!(cur_sprite->flags & SPRITE_CHAR_CHECK2) || !is_blank(ch))
  293. {
  294. draw_char_linear(dcolor, ch, i5);
  295. }
  296. }
  297. i4++;
  298. i5++;
  299. }
  300. i4 += skip;
  301. i5 += skip2;
  302. }
  303. break;
  304. }
  305. // given colors, under overlay
  306. case 0: // 00
  307. {
  308. color = cur_sprite->color;
  309. for(i2 = 0; i2 < dr_h; i2++)
  310. {
  311. for(i3 = 0; i3 < dr_w; i3++)
  312. {
  313. if(use_chars)
  314. {
  315. ch = src_chars[i4];
  316. }
  317. else
  318. {
  319. ch = get_id_char(src_board, i4);
  320. }
  321. dcolor = color;
  322. if(!(color & 0xF0))
  323. {
  324. dcolor = (color & 0x0F) | (get_color_linear(i5) & 0xF0);
  325. }
  326. if((!overlay_mode || (overlay[i6] == 32)) && ch != 32)
  327. {
  328. if(!(cur_sprite->flags & SPRITE_CHAR_CHECK2) || !is_blank(ch))
  329. {
  330. draw_char_linear(dcolor, ch, i5);
  331. }
  332. }
  333. i4++;
  334. i5++;
  335. i6++;
  336. }
  337. i4 += skip;
  338. i5 += skip2;
  339. i6 += skip3;
  340. }
  341. break;
  342. }
  343. }
  344. }
  345. }
  346. }
  347. int sprite_at_xy(Sprite *cur_sprite, int x, int y)
  348. {
  349. if((x >= cur_sprite->x) && (x < cur_sprite->x + cur_sprite->width) &&
  350. (y >= cur_sprite->y) && (y < cur_sprite->y + cur_sprite->height)
  351. && (cur_sprite->flags & SPRITE_INITIALIZED))
  352. {
  353. return 1;
  354. }
  355. else
  356. {
  357. return 0;
  358. }
  359. }
  360. int sprite_colliding_xy(World *mzx_world, Sprite *check_sprite, int x, int y)
  361. {
  362. Board *src_board = mzx_world->current_board;
  363. int board_width = src_board->board_width;
  364. Sprite **sprite_list = mzx_world->sprite_list;
  365. Sprite *cur_sprite;
  366. int colliding = 0;
  367. int skip, skip2, i, i2, i3, i4, i5;
  368. int bwidth;
  369. int x1, x2, y1, y2;
  370. int mw, mh;
  371. int use_chars = 1, use_chars2 = 1;
  372. unsigned int x_lmask, x_gmask, y_lmask, y_gmask, xl, xg, yl, yg, wl, hl, wg, hg;
  373. char *vlayer_chars = mzx_world->vlayer_chars;
  374. char *level_id = src_board->level_id;
  375. int *collision_list = mzx_world->collision_list;
  376. int vlayer_width = mzx_world->vlayer_width;
  377. int board_collide = 0;
  378. if(!(check_sprite->flags & SPRITE_INITIALIZED)) return -1;
  379. // Check against the background, will only collide against customblock for now
  380. // (id 5)
  381. if(check_sprite->flags & SPRITE_VLAYER)
  382. {
  383. use_chars = 0;
  384. bwidth = vlayer_width;
  385. }
  386. else
  387. {
  388. bwidth = board_width;
  389. }
  390. // Scan board area
  391. skip = board_width - check_sprite->col_width;;
  392. skip2 = bwidth - check_sprite->col_width;
  393. i3 = ((y + check_sprite->col_y) * board_width) + x + check_sprite->col_x;
  394. i4 = ((check_sprite->ref_y + check_sprite->col_y) * bwidth) +
  395. check_sprite->ref_x + check_sprite->col_x;
  396. for(i = 0; i < check_sprite->col_height; i++)
  397. {
  398. for(i2 = 0; i2 < check_sprite->col_width; i2++)
  399. {
  400. // First, if ccheck is on, it won't care if the source is 32
  401. int c;
  402. if(!use_chars)
  403. {
  404. c = vlayer_chars[i4];
  405. }
  406. else
  407. {
  408. c = get_id_char(src_board, i4);
  409. }
  410. if(!(check_sprite->flags & SPRITE_CHAR_CHECK) ||
  411. (c != 32))
  412. {
  413. // if ccheck2 is on and the char is blank, don't trigger.
  414. if(!(check_sprite->flags & SPRITE_CHAR_CHECK2) ||
  415. (!is_blank(c)))
  416. {
  417. if(level_id[i3] == 5)
  418. {
  419. // Colliding against background
  420. if(board_collide) break;
  421. collision_list[colliding] = -1;
  422. colliding++;
  423. board_collide = 1;
  424. }
  425. }
  426. }
  427. i3++;
  428. i4++;
  429. }
  430. i3 += skip;
  431. i4 += skip2;
  432. }
  433. for(i = 0; i < MAX_SPRITES; i++)
  434. {
  435. cur_sprite = sprite_list[i];
  436. if((cur_sprite == check_sprite) || !(cur_sprite->flags & SPRITE_INITIALIZED))
  437. continue;
  438. if(!(cur_sprite->col_width) || !(cur_sprite->col_height))
  439. continue;
  440. x1 = cur_sprite->x + cur_sprite->col_x;
  441. x2 = x + check_sprite->col_x;
  442. y1 = cur_sprite->y + cur_sprite->col_y;
  443. y2 = y + check_sprite->col_y;
  444. x_lmask = (signed int)(x1 - x2) >> 31;
  445. x_gmask = ~x_lmask;
  446. y_lmask = (signed int)(y1 - y2) >> 31;
  447. y_gmask = ~y_lmask;
  448. xl = (x1 & x_lmask) | (x2 & x_gmask);
  449. xg = (x1 & x_gmask) | (x2 & x_lmask);
  450. yl = (y1 & y_lmask) | (y2 & y_gmask);
  451. yg = (y1 & y_gmask) | (y2 & y_lmask);
  452. wl = (cur_sprite->col_width & x_lmask) |
  453. (check_sprite->col_width & x_gmask);
  454. hl = (cur_sprite->col_height & y_lmask) |
  455. (check_sprite->col_height & y_gmask);
  456. if((((xg - xl) - wl) & ((yg - yl) - hl)) >> 31)
  457. {
  458. // Does it require char/char verification?
  459. if(check_sprite->flags & SPRITE_CHAR_CHECK)
  460. {
  461. // The sub rectangle is going to be somewhere within both sprites;
  462. // It's going to start at the beginning of the component further
  463. // along (xg/yg) which is an absolute board position; find the
  464. // i5 both sprites are from this... and you will iterate in a
  465. // rectangle there that is (xl + wl) - xg... the difference between
  466. // where the first one ends and the second one begins
  467. mw = (xl + wl) - xg;
  468. mh = (yl + hl) - yg;
  469. // Reuse these.. i5s. For both you must look at PHYSICAL data, that
  470. // is, where the chars of the sprite itself is.
  471. x1 = cur_sprite->ref_x + (xg - x1) + cur_sprite->col_x;
  472. y1 = cur_sprite->ref_y + (yg - y1) + cur_sprite->col_y;
  473. x2 = check_sprite->ref_x + (xg - x2) + check_sprite->col_x;
  474. y2 = check_sprite->ref_y + (yg - y2) + check_sprite->col_y;
  475. // Check to make sure draw area doesn't go over.
  476. wg = (cur_sprite->col_width & x_gmask) |
  477. (check_sprite->col_width & x_lmask);
  478. hg = (cur_sprite->col_height & y_gmask) |
  479. (check_sprite->col_height & y_lmask);
  480. if(mw > wg)
  481. {
  482. mw = wg;
  483. }
  484. if(mh > hg)
  485. {
  486. mh = hg;
  487. }
  488. // Now iterate through the rect; if both are NOT 32 then a collision is
  489. // flagged.
  490. if(cur_sprite->flags & SPRITE_VLAYER)
  491. {
  492. use_chars2 = 0;
  493. i4 = (y1 * vlayer_width) + x1;
  494. skip = vlayer_width - mw;
  495. }
  496. else
  497. {
  498. i4 = (y1 * board_width) + x1;
  499. skip = board_width - mw;
  500. }
  501. i5 = (y2 * bwidth) + x2;
  502. skip2 = bwidth - mw;
  503. // If ccheck mode 2 is on it should do a further strength check.
  504. if(check_sprite->flags & SPRITE_CHAR_CHECK2)
  505. {
  506. for(i2 = 0; i2 < mh; i2++)
  507. {
  508. for(i3 = 0; i3 < mw; i3++)
  509. {
  510. unsigned char c1, c2;
  511. if(use_chars2)
  512. {
  513. c1 = get_id_char(src_board, i4);
  514. }
  515. else
  516. {
  517. c1 = vlayer_chars[i4];
  518. }
  519. if(use_chars)
  520. {
  521. c2 = get_id_char(src_board, i5);
  522. }
  523. else
  524. {
  525. c2 = vlayer_chars[i5];
  526. }
  527. if((c1 != 32) && (c2 != 32))
  528. {
  529. // Collision.. maybe.
  530. // We still have to see if both of the chars aren't
  531. // blank.
  532. if(!(is_blank(c1) || is_blank(c2)))
  533. {
  534. collision_list[colliding] = i;
  535. colliding++;
  536. goto next;
  537. }
  538. }
  539. i4++;
  540. i5++;
  541. }
  542. i4 += skip;
  543. i5 += skip2;
  544. }
  545. }
  546. else
  547. {
  548. for(i2 = 0; i2 < mh; i2++)
  549. {
  550. for(i3 = 0; i3 < mw; i3++)
  551. {
  552. unsigned char c1, c2;
  553. if(use_chars2)
  554. {
  555. c1 = get_id_char(src_board, i4);
  556. }
  557. else
  558. {
  559. c1 = vlayer_chars[i4];
  560. }
  561. if(use_chars)
  562. {
  563. c2 = get_id_char(src_board, i5);
  564. }
  565. else
  566. {
  567. c2 = vlayer_chars[i5];
  568. }
  569. if((c1 != 32) && (c2 != 32))
  570. {
  571. // Collision!
  572. collision_list[colliding] = i;
  573. colliding++;
  574. goto next;
  575. }
  576. i4++;
  577. i5++;
  578. }
  579. i4 += skip;
  580. i5 += skip;
  581. }
  582. }
  583. }
  584. else
  585. {
  586. collision_list[colliding] = i;
  587. colliding++;
  588. }
  589. next:
  590. continue;
  591. }
  592. }
  593. mzx_world->collision_count = colliding;
  594. return colliding;
  595. }
  596. int is_blank(unsigned char c)
  597. {
  598. char cp[14];
  599. ec_read_char(c, cp);
  600. int blank = 0, i;
  601. for(i = 0; i < 14; i++)
  602. {
  603. blank |= cp[i];
  604. }
  605. return !blank;
  606. return 0;
  607. }