You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

game.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. #include "bomber.h"
  2. #include "game.h"
  3. #include "gfx.h"
  4. #include "network.h"
  5. #include "draw.h"
  6. #include "utils.h"
  7. #include "sound.h"
  8. #include "menu.h"
  9. #include "list.h"
  10. static int gameframe;
  11. static listhead activebombs;
  12. static listhead activedecays;
  13. static listhead activebonus;
  14. static listhead activegeneric;
  15. static listhead detonatebombs;
  16. static listhead activeflames;
  17. static listhead activeplayers;
  18. static listhead allplayers;
  19. figure walking[MAXSETS][NUMWALKFRAMES];
  20. solid background, backgroundoriginal;
  21. /* The playfield array, contains FIELD_* equates */
  22. unsigned char field[32][32];
  23. void *info[32][32];
  24. volatile char exitflag = 0;
  25. static int framecount = 0;
  26. char playername[16];
  27. static int mycount;
  28. static int bonustotal;
  29. static const int bonuschances[]= {
  30. TILE_BOMB,20,
  31. TILE_FLAME,20,
  32. TILE_TRIGGER,2,
  33. TILE_GOLDFLAME,2,
  34. TILE_SKATES,20,
  35. TILE_TURTLE,5,
  36. TILE_NONE,160
  37. };
  38. static GameOptions gameoptions;
  39. static const unsigned char playerpositions[MAXNETNODES*3] = { /* color, x, y */
  40. 2,0,0,
  41. 3,14,10,
  42. 4,14,0,
  43. 5,0,10,
  44. 1,6,0,
  45. 6,8,10,
  46. 7,0,6,
  47. 8,14,4,
  48. };
  49. static void resetplayer(player *pl, int color, int x, int y) {
  50. pl->speed=SPEEDSTART;
  51. pl->flags=0;
  52. pl->flamelength=gameoptions.flames+1;
  53. pl->bombsavailable=gameoptions.bombs+1;
  54. pl->color=color;
  55. pl->xpos=arraytoscreenx(x);
  56. pl->ypos=arraytoscreeny(y);
  57. field[y][x]=FIELD_EMPTY;
  58. if(x) field[y][x-1]=FIELD_EMPTY;
  59. if(y) field[y-1][x]=FIELD_EMPTY;
  60. if(x<arraynumx-1) field[y][x+1]=FIELD_EMPTY;
  61. if(y<arraynumy-1) field[y+1][x]=FIELD_EMPTY;
  62. addtail(&activeplayers, pl);
  63. }
  64. static void initplayer(int color,int x,int y,int controller) {
  65. player *pl;
  66. pl = allocentry(player);
  67. if(!pl)
  68. nomem("Couldn't get player structure (allocentry())");
  69. list_add_tail(&allplayers, &pl->list_all_players);
  70. pl->controller=controller;
  71. pl->fixx=-4;
  72. pl->fixy=-40;
  73. pl->kills = pl->deaths = 0;
  74. resetplayer(pl, color, x, y);
  75. }
  76. static void initplayers(void) {
  77. int i;
  78. const unsigned char *p;
  79. int c,x,y;
  80. if(NETWORK_NONE == network) {
  81. initplayer(2,0,0,-1);
  82. return;
  83. }
  84. p=playerpositions;
  85. for(i=0;i<MAXNETNODES;++i) {
  86. if(!netnodes[i].used) continue;
  87. c=*p++;
  88. x=*p++;
  89. y=*p++;
  90. initplayer(c,x,y,i);
  91. }
  92. }
  93. static void resetplayers(void) {
  94. const unsigned char *p;
  95. int c,x,y;
  96. player *pl;
  97. p=playerpositions;
  98. list_for_each_entry(pl, &allplayers, list_all_players) {
  99. c=*p++;
  100. x=*p++;
  101. y=*p++;
  102. resetplayer(pl, c, x, y);
  103. }
  104. }
  105. static void firstzero(void) {
  106. alloc_things();
  107. list_init_head(&activebombs);
  108. list_init_head(&detonatebombs);
  109. list_init_head(&activeflames);
  110. list_init_head(&activedecays);
  111. list_init_head(&activebonus);
  112. list_init_head(&activeplayers);
  113. list_init_head(&activegeneric);
  114. list_init_head(&allplayers);
  115. mycount = mydatacount = 0;
  116. memset(latestactions,0,sizeof(latestactions));
  117. memset(latestcounts,0,sizeof(latestcounts));
  118. memset(actionblock,0,sizeof(actionblock));
  119. actioncount = 0;
  120. }
  121. static void initgame() {
  122. int i,j;
  123. int x,y;
  124. int bl;
  125. const int *p;
  126. int comp;
  127. if (network != NETWORK_SLAVE)
  128. set_game_options(&configopts);
  129. gameframe=0;
  130. things_list_clear(&activebombs);
  131. things_list_clear(&detonatebombs);
  132. things_list_clear(&activeflames);
  133. things_list_clear(&activedecays);
  134. things_list_clear(&activebonus);
  135. list_init_head(&activeplayers);
  136. things_list_clear(&activegeneric);
  137. p=bonuschances;
  138. bonustotal=0;
  139. for(;;) {
  140. i=*p++;
  141. if(i==TILE_NONE) break;
  142. bonustotal+=*p++;
  143. }
  144. bonustotal += 64*(3-gameoptions.generosity);
  145. memset(field,0,sizeof(field));
  146. comp=gameoptions.density;
  147. for(j=0;j<arraynumy;++j)
  148. for(i=0;i<arraynumx;++i) {
  149. /* if((i&j)&1) {
  150. field[j][i]=FIELD_BORDER;
  151. } else*/
  152. field[j][i]=
  153. (myrand()&3)>=comp ? FIELD_BRICK : FIELD_EMPTY;
  154. }
  155. solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE);
  156. resetplayers();
  157. for(j=0;j<arraynumy;++j) {
  158. y=arraystarty+j*arrayspacey;
  159. for(i=0;i<arraynumx;++i) {
  160. x=arraystartx+i*arrayspacex;
  161. bl=field[j][i];
  162. if(bl==FIELD_BORDER) bl=2;
  163. else if(bl==FIELD_BRICK) bl=1;
  164. else continue;
  165. drawfigureany(x,y,blocks+bl,&background);
  166. }
  167. }
  168. solidcopy(&background,0,0,IXSIZE,IYSIZE);
  169. copyup();
  170. }
  171. static void addflame(player *owner,int px,int py) {
  172. flame *fl,*fl2;
  173. fl = allocentry(flame);
  174. if(!fl) return;
  175. addtail(&activeflames,fl);
  176. field[py][px]=FIELD_FLAME;
  177. info[py][px]=fl;
  178. fl->px=px;
  179. fl->py=py;
  180. fl->xpos=arraytoscreenx(px);
  181. fl->ypos=arraytoscreeny(py);
  182. fl->owner=owner;
  183. if(px && field[py][px-1]==FIELD_FLAME) {
  184. fl2=info[py][px-1];
  185. fl->lurd|=FL_LEFT;
  186. fl2->lurd|=FL_RIGHT;
  187. }
  188. if(py && field[py-1][px]==FIELD_FLAME) {
  189. fl2=info[py-1][px];
  190. fl->lurd|=FL_UP;
  191. fl2->lurd|=FL_DOWN;
  192. }
  193. if(px<arraynumx-1 && field[py][px+1]==FIELD_FLAME) {
  194. fl2=info[py][px+1];
  195. fl->lurd|=FL_RIGHT;
  196. fl2->lurd|=FL_LEFT;
  197. }
  198. if(py<arraynumy-1 && field[py+1][px]==FIELD_FLAME) {
  199. fl2=info[py+1][px];
  200. fl->lurd|=FL_DOWN;
  201. fl2->lurd|=FL_UP;
  202. }
  203. }
  204. static void dropbomb(player *pl,int px,int py,int type){
  205. bomb *bmb;
  206. if(field[py][px]!=FIELD_EMPTY) return;
  207. bmb = allocentry(bomb);
  208. if(!bmb) return;
  209. playsound(3);
  210. addtail(&activebombs,bmb);
  211. --(pl->bombsavailable);
  212. field[py][px]=FIELD_BOMB;
  213. info[py][px]=bmb;
  214. bmb->type=type;
  215. bmb->px=px;
  216. bmb->py=py;
  217. bmb->xpos=arraytoscreenx(px);
  218. bmb->ypos=arraytoscreeny(py);
  219. bmb->power=pl->flamelength;
  220. bmb->owner=pl;
  221. }
  222. static void adddecay(int px,int py) {
  223. brickdecay *bd;
  224. int xpos,ypos;
  225. bd = allocentry(brickdecay);
  226. if(!bd) return;
  227. field[py][px]=FIELD_EXPLODING;
  228. bd->xpos=arraytoscreenx(px);
  229. bd->ypos=arraytoscreeny(py);
  230. bd->px=px;
  231. bd->py=py;
  232. addtail(&activedecays,bd);
  233. xpos=tovideox(bd->xpos);
  234. ypos=tovideoy(bd->ypos);
  235. solidcopyany(&backgroundoriginal,&background,xpos,ypos,
  236. arrayspacex,arrayspacey);
  237. solidcopy(&background,xpos,ypos,arrayspacex,arrayspacey);
  238. }
  239. static void addbonus(int px,int py,int type) {
  240. bonustile *bonus;
  241. bonus = allocentry(bonustile);
  242. if(!bonus) return;
  243. addtail(&activebonus,bonus);
  244. bonus->px=px;
  245. bonus->py=py;
  246. bonus->xpos=arraytoscreenx(px);
  247. bonus->ypos=arraytoscreeny(py);
  248. bonus->type=type;
  249. field[py][px]=FIELD_BONUS;
  250. info[py][px]=bonus;
  251. }
  252. static void trybonus(int px,int py) {
  253. int i=0, r;
  254. const int *p;
  255. if(field[py][px]!=FIELD_EMPTY) return;
  256. p=bonuschances;
  257. r=myrand()%bonustotal;
  258. while(r>=0) {
  259. i=*p++;
  260. r-=*p++;
  261. }
  262. if(i==TILE_NONE) return;
  263. addbonus(px,py,i);
  264. }
  265. static void deletebonus(bonustile *bonus) {
  266. int px,py;
  267. px=bonus->px;
  268. py=bonus->py;
  269. field[py][px]=0;
  270. info[py][px]=0;
  271. list_del(&bonus->list);
  272. freeentry(bonus);
  273. }
  274. static void adddetonate(bomb *bmb) {
  275. if (bmb->type==BOMB_OFF) return;
  276. bmb->type = BOMB_OFF;
  277. field[bmb->py][bmb->px] = FIELD_EXPLODING;
  278. info[bmb->py][bmb->px] = 0;
  279. removeitem(bmb);
  280. addtail(&detonatebombs, bmb);
  281. }
  282. static void processbombs() {
  283. bomb *bmb, *next;
  284. list_for_each_entry_safe(bmb, next, &activebombs, list) {
  285. ++(bmb->figcount);
  286. ++bmb->timer;
  287. switch(bmb->type) {
  288. case BOMB_NORMAL:
  289. if (bmb->timer == BOMBLIFE)
  290. adddetonate(bmb);
  291. break;
  292. case BOMB_CONTROLLED:
  293. if (bmb->timer == BOMB_CONTROLLED_LIFE) {
  294. bmb->timer = 0;
  295. bmb->type = BOMB_NORMAL;
  296. }
  297. break;
  298. }
  299. }
  300. }
  301. static void flameshaft(player *owner,int px,int py,int dx,int dy,int power) {
  302. int there;
  303. bomb *bmb;
  304. while(power--) {
  305. px+=dx;
  306. py+=dy;
  307. if(px<0 || py<0 || px>=arraynumx || py>=arraynumy) break;
  308. there=field[py][px];
  309. switch(there) {
  310. case FIELD_BOMB:
  311. bmb=info[py][px];
  312. adddetonate(bmb);
  313. break;
  314. case FIELD_EMPTY:
  315. addflame(owner,px,py);
  316. break;
  317. case FIELD_BRICK:
  318. adddecay(px,py);
  319. power=0;
  320. break;
  321. case FIELD_BONUS:
  322. deletebonus(info[py][px]);
  323. power=0;
  324. break;
  325. case FIELD_BORDER:
  326. case FIELD_EXPLODING:
  327. default:
  328. power=0;
  329. case FIELD_FLAME:
  330. break;
  331. }
  332. }
  333. }
  334. static void detonatebomb(bomb *bmb) {
  335. int px,py;
  336. int power;
  337. player *owner;
  338. ++(bmb->owner->bombsavailable);
  339. px=bmb->px;
  340. py=bmb->py;
  341. power=bmb->power;
  342. owner=bmb->owner;
  343. list_del(&bmb->list);
  344. freeentry(bmb);
  345. addflame(owner,px,py);
  346. flameshaft(owner,px,py,-1,0,power);
  347. flameshaft(owner,px,py,0,-1,power);
  348. flameshaft(owner,px,py,1,0,power);
  349. flameshaft(owner,px,py,0,1,power);
  350. }
  351. static void dodetonations(void) {
  352. int i = 0;
  353. bomb *bmb;
  354. while (!list_empty(&detonatebombs)) {
  355. bmb = (bomb*) detonatebombs.next;
  356. ++i;
  357. detonatebomb(bmb);
  358. }
  359. if(i) playsound((myrand()&1) ? 0 : 4);
  360. }
  361. static void processflames(void) {
  362. flame *fl, *next;
  363. list_for_each_entry_safe(fl, next, &activeflames, list) {
  364. ++(fl->timer);
  365. if(fl->timer==FLAMELIFE) {
  366. field[fl->py][fl->px]=FIELD_EMPTY;
  367. info[fl->py][fl->px]=0;
  368. list_del(&fl->list);
  369. freeentry(fl);
  370. }
  371. }
  372. }
  373. static void processdecays() {
  374. brickdecay *bd, *next;
  375. list_for_each_entry_safe(bd, next, &activedecays, list) {
  376. ++(bd->timer);
  377. if(bd->timer == DECAYLIFE) {
  378. field[bd->py][bd->px] = FIELD_EMPTY;
  379. trybonus(bd->px, bd->py);
  380. list_del(&bd->list);
  381. freeentry(bd);
  382. }
  383. }
  384. }
  385. static void drawbombs(void) {
  386. int j;
  387. bomb *bmb;
  388. struct figure *figtab;
  389. int color;
  390. int xpos,ypos;
  391. list_for_each_entry(bmb, &activebombs, list) {
  392. color=bmb->owner->color;
  393. figtab=(bmb->type==BOMB_NORMAL) ? bombs1[color] : bombs2[color];
  394. j=bmb->figcount % (NUMBOMBFRAMES<<1);
  395. if(j>=NUMBOMBFRAMES) j=(NUMBOMBFRAMES<<1)-j-1;
  396. xpos=tovideox(bmb->xpos);
  397. ypos=tovideoy(bmb->ypos)-3;
  398. addsprite(xpos,ypos,figtab+j);
  399. }
  400. }
  401. static void drawflames(void) {
  402. flame *fl;
  403. int xpos,ypos;
  404. int color;
  405. int fig;
  406. list_for_each_entry(fl, &activeflames, list) {
  407. color=fl->owner->color;
  408. xpos=tovideox(fl->xpos);
  409. ypos=tovideoy(fl->ypos);
  410. fig=(fl->timer*10)/FLAMELIFE;
  411. if(fig>=5) fig=9-fig;
  412. fig+=5*fl->lurd;
  413. addsprite(xpos,ypos,flamefigs[0/* color */]+fig);
  414. }
  415. }
  416. static void drawdecays() {
  417. brickdecay *bd;
  418. list_for_each_entry(bd, &activedecays, list) {
  419. addsprite(tovideox(bd->xpos),tovideoy(bd->ypos),
  420. blocksx+(bd->timer*9)/DECAYLIFE);
  421. }
  422. }
  423. static void drawbonus() {
  424. bonustile *bonus;
  425. list_for_each_entry(bonus, &activebonus, list) {
  426. addsprite(tovideox(bonus->xpos),tovideoy(bonus->ypos),
  427. tiles+bonus->type);
  428. }
  429. }
  430. static void drawplayers() {
  431. player *pl;
  432. int xpos,ypos;
  433. list_for_each_entry(pl, &activeplayers, list) {
  434. if(!(pl->flags & FLG_DEAD)) {
  435. if(!pl->figure)
  436. pl->figure=walking[pl->color]+30;
  437. xpos=tovideox(pl->xpos)+pl->fixx;
  438. ypos=tovideoy(pl->ypos)+pl->fixy;
  439. addsprite(xpos,ypos,pl->figure);
  440. }
  441. }
  442. }
  443. static void detonatecontrolled(player *pl) {
  444. bomb *bmb, *next;
  445. list_for_each_entry_safe(bmb, next, &activebombs, list) {
  446. if(bmb->owner==pl && bmb->type==BOMB_CONTROLLED)
  447. adddetonate(bmb);
  448. }
  449. }
  450. static void playonce(generic *gen) {
  451. if (gen->timer == gen->data1) {
  452. list_del(&gen->list);
  453. freeentry(gen);
  454. }
  455. }
  456. static void drawgeneric(generic *gen) {
  457. addsprite(gen->xpos,gen->ypos,((figure *)(gen->ptr1))+gen->timer);
  458. }
  459. static void queuesequence(int xpos,int ypos,figure *fig,int count) {
  460. generic *gen;
  461. gen = allocentry(generic);
  462. if(!gen) return;
  463. gen->xpos=xpos;
  464. gen->ypos=ypos;
  465. gen->data1=count;
  466. gen->process=playonce;
  467. gen->draw=drawgeneric;
  468. gen->ptr1=fig;
  469. addtail(&activegeneric,gen);
  470. }
  471. static void adddeath(player *pl) {
  472. int xpos,ypos;
  473. xpos=tovideox(pl->xpos)+pl->fixx-10;
  474. ypos=tovideoy(pl->ypos)+pl->fixy;
  475. queuesequence(xpos,ypos,death,NUMDEATHFRAMES);
  476. }
  477. static void killplayer(player *pl) {
  478. pl->deaths++;
  479. pl->flags|=FLG_DEAD;
  480. playsound(2);
  481. adddeath(pl);
  482. detonatecontrolled(pl);
  483. }
  484. static void processgenerics(void) {
  485. generic *gen, *next;
  486. list_for_each_entry_safe(gen, next, &activegeneric, list) {
  487. ++(gen->timer);
  488. gen->process(gen);
  489. }
  490. }
  491. static void drawgenerics(void) {
  492. generic *gen;
  493. list_for_each_entry(gen, &activegeneric, list) {
  494. gen->draw(gen);
  495. }
  496. }
  497. static void drawstats(void) {
  498. player *pl;
  499. int p = 0;
  500. const char *n;
  501. char buf[16];
  502. solidcopy(&background, 0, 0, IXSIZE, arraystarty);
  503. list_for_each_entry(pl, &allplayers, list_all_players) {
  504. if (pl->controller >= 0) {
  505. n = netnodes[pl->controller].name;
  506. } else {
  507. n = playername;
  508. }
  509. snprintf(buf, sizeof(buf), "%-8.8s %2i/%2i", n, pl->kills % 100, pl->deaths % 100);
  510. drawstring(11 + (p/2) * (15 * fontxsize + 7), 11 + (p%2) * (fontysize+2), buf);
  511. p++;
  512. }
  513. }
  514. static int centerxchange(player *pl) {
  515. int speed;
  516. int val;
  517. int line;
  518. int max;
  519. max=arrayspacex<<FRACTION;
  520. speed=pl->speed;
  521. val=pl->xpos+(max<<2);
  522. val%=max;
  523. line=max>>1;
  524. if(val<line) {
  525. if(val-speed<0)
  526. return -val;
  527. else
  528. return -speed;
  529. } else if(val>=line) {
  530. if(val+speed>max)
  531. return max-val;
  532. else
  533. return speed;
  534. }
  535. return 0;
  536. }
  537. static void centerx(player *pl) {
  538. pl->xpos+=centerxchange(pl);
  539. }
  540. static int centerychange(player *pl) {
  541. int speed;
  542. int val;
  543. int line;
  544. int max;
  545. max=arrayspacey<<FRACTION;
  546. speed=pl->speed;
  547. val=pl->ypos+(max<<2);
  548. val%=max;
  549. line=max>>1;
  550. if(val<line)
  551. {
  552. if(val-speed<0)
  553. return -val;
  554. else
  555. return -speed;
  556. } else if(val>=line)
  557. {
  558. if(val+speed>max)
  559. return max-val;
  560. else
  561. return speed;
  562. }
  563. return 0;
  564. }
  565. static void centery(player *pl) {
  566. pl->ypos+=centerychange(pl);
  567. }
  568. #define SGN(x) ((x)==0 ? 0 : ((x)<0 ? -1 : 1))
  569. static void trymove(player *pl,int dx,int dy) {
  570. int wx,wy;
  571. int sx,sy;
  572. int there;
  573. int px,py;
  574. static int depth=0;
  575. int tx,ty;
  576. ++depth;
  577. sx=(dx*(arrayspacex+1)) << (FRACTION-1);
  578. sy=(dy*(arrayspacey+1)) << (FRACTION-1);
  579. wx=screentoarrayx(pl->xpos+sx);
  580. wy=screentoarrayy(pl->ypos+sy);
  581. px=screentoarrayx(pl->xpos);
  582. py=screentoarrayy(pl->ypos);
  583. if(wx<0 || wx>=arraynumx || wy<0 || wy>=arraynumy) {
  584. --depth;
  585. return;
  586. }
  587. there=field[wy][wx];
  588. if((px!=wx || py!=wy) &&
  589. (there==FIELD_BRICK||there==FIELD_BOMB||there==FIELD_BORDER))
  590. {
  591. if(dx && !dy) {
  592. ty=centerychange(pl);
  593. if(ty && depth==1)
  594. trymove(pl,0,-SGN(ty));
  595. } else if(dy && !dx) {
  596. tx=centerxchange(pl);
  597. if(tx && depth==1)
  598. trymove(pl,-SGN(tx),0);
  599. }
  600. } else {
  601. pl->xpos+=dx*pl->speed;
  602. pl->ypos+=dy*pl->speed;
  603. if(dx && !dy) centery(pl);
  604. if(dy && !dx) centerx(pl);
  605. }
  606. --depth;
  607. }
  608. static void applybonus(player *pl,bonustile *bonus) {
  609. int type;
  610. int maxflame;
  611. maxflame=arraynumx>arraynumy ? arraynumx : arraynumy;
  612. type=bonus->type;
  613. deletebonus(bonus);
  614. switch(type) {
  615. case TILE_BOMB:
  616. if (pl->bombsavailable < 9)
  617. ++(pl->bombsavailable);
  618. break;
  619. case TILE_FLAME:
  620. if(pl->flamelength<maxflame)
  621. ++(pl->flamelength);
  622. break;
  623. case TILE_GOLDFLAME:
  624. pl->flamelength=maxflame;
  625. break;
  626. case TILE_TRIGGER:
  627. pl->flags|=FLG_CONTROL;
  628. break;
  629. case TILE_SKATES:
  630. if (pl->speed < SPEEDSTART) {
  631. pl->speed = SPEEDSTART;
  632. } else {
  633. pl->speed+=SPEEDDELTA;
  634. }
  635. if(pl->speed>SPEEDMAX) pl->speed=SPEEDMAX;
  636. break;
  637. case TILE_TURTLE:
  638. pl->speed=SPEEDTURTLE;
  639. pl->speedturtle_timeout=SPEEDTURTLE_TIMEOUT;
  640. break;
  641. }
  642. }
  643. static void doplayer(player *pl) {
  644. int last;
  645. int color;
  646. int speed;
  647. int px,py;
  648. int there;
  649. int flags;
  650. int what;
  651. if(pl->controller==-1)
  652. what=myaction;
  653. else
  654. what=actions[pl->controller];
  655. flags=pl->flags;
  656. if(flags&FLG_DEAD) return;
  657. color=pl->color;
  658. last=pl->doing;
  659. pl->doing=what;
  660. speed=pl->speed;
  661. px=screentoarrayx(pl->xpos);
  662. py=screentoarrayy(pl->ypos);
  663. there=field[py][px];
  664. if(what==ACT_QUIT) {
  665. killplayer(pl);
  666. list_del(&pl->list_all_players);
  667. return;
  668. }
  669. if(there==FIELD_BONUS) {
  670. playsound((myrand()&1) ? 1 : 5);
  671. applybonus(pl,info[py][px]);
  672. } else if(there==FIELD_FLAME) {
  673. flame *fl = info[py][px];
  674. if (fl->owner == pl) {
  675. pl->kills--;
  676. } else {
  677. fl->owner->kills++;
  678. }
  679. killplayer(pl);
  680. return;
  681. }
  682. // if(what&ACT_TURBO) speed<<=2;
  683. if(what&ACT_PRIMARY) {
  684. if(there==FIELD_EMPTY && pl->bombsavailable)
  685. dropbomb(pl,px,py,
  686. (flags&FLG_CONTROL) ? BOMB_CONTROLLED :BOMB_NORMAL);
  687. }
  688. if(what&ACT_SECONDARY && (flags&FLG_CONTROL))
  689. detonatecontrolled(pl);
  690. switch(what&ACT_MASK) {
  691. case ACT_UP:
  692. trymove(pl,0,-1);
  693. pl->figcount=(pl->figcount+1)%15;
  694. pl->figure=walking[color]+pl->figcount+15;
  695. break;
  696. case ACT_DOWN:
  697. trymove(pl,0,1);
  698. pl->figcount=(pl->figcount+1)%15;
  699. pl->figure=walking[color]+pl->figcount+30;
  700. break;
  701. case ACT_LEFT:
  702. trymove(pl,-1,0);
  703. pl->figcount=(pl->figcount+1)%15;
  704. pl->figure=walking[color]+pl->figcount+45;
  705. break;
  706. case ACT_RIGHT:
  707. trymove(pl,1,0);
  708. pl->figcount=(pl->figcount+1)%15;
  709. pl->figure=walking[color]+pl->figcount;
  710. break;
  711. case ACT_NONE:
  712. break;
  713. }
  714. if (pl->speedturtle_timeout > 0) {
  715. pl->speedturtle_timeout--;
  716. if (0 == pl->speedturtle_timeout) {
  717. if (pl->speed < SPEEDSTART) pl->speed = SPEEDSTART;
  718. }
  719. }
  720. }
  721. static void processplayers(void) {
  722. player *pl, *next;
  723. list_for_each_entry_safe(pl, next, &activeplayers, list) {
  724. doplayer(pl);
  725. }
  726. }
  727. static void processquits(void) {
  728. int i;
  729. if (network != NETWORK_SLAVE) return;
  730. for (i = 0; i < MAXNETNODES; ++i) {
  731. if (netnodes[i].used && actions[i]==ACT_QUIT)
  732. netnodes[i].used=0;
  733. }
  734. }
  735. static int getaction(void) {
  736. int what;
  737. what=ACT_NONE;
  738. if(checkpressed(MYLEFT)) what=ACT_LEFT;
  739. else if(checkpressed(MYRIGHT)) what=ACT_RIGHT;
  740. else if(checkpressed(MYDOWN)) what=ACT_DOWN;
  741. else if(checkpressed(MYUP)) what=ACT_UP;
  742. else if(checkdown(13)) what=ACT_ENTER;
  743. else if(checkdown(0x1b)) what=ACT_QUIT;
  744. if(checkdown(' '))
  745. what|=ACT_PRIMARY;
  746. if(checkdown('b'))
  747. what|=ACT_SECONDARY;
  748. return what;
  749. }
  750. static int iterate(void) {
  751. int i;
  752. int gountil; /* destination tick */
  753. static int deathcount = 0;
  754. mypause();
  755. scaninput();
  756. erasesprites();
  757. clearspritelist();
  758. gfxunlock();
  759. myaction = getaction();
  760. if (NETWORK_NONE == network && myaction==ACT_QUIT) return CODE_QUIT;
  761. if (NETWORK_NONE == network) {
  762. gountil = mycount + 1; /* single step in singly player mode */
  763. } else {
  764. gountil = networktraffic(); /* as master single step, as slave as many as we can do */
  765. }
  766. while (mycount < gountil) { /* simulate ticks up to gountil */
  767. ++mycount;
  768. if (NETWORK_NONE != network) {
  769. i = gountil - mycount;
  770. if(i >= ACTIONHIST) // too far behind
  771. goto leave_game;
  772. memcpy(actions, actionblock+i*MAXNETNODES, MAXNETNODES);
  773. if (actions[myslot] == ACT_QUIT) return CODE_QUIT;
  774. }
  775. processbombs();
  776. dodetonations();
  777. processdecays();
  778. processflames();
  779. processgenerics();
  780. processquits();
  781. processplayers();
  782. }
  783. /*
  784. if(!(rand()&127))
  785. {
  786. i=gtime();
  787. while(gtime()-i<100);
  788. }
  789. */
  790. drawbombs();
  791. drawbonus();
  792. drawgenerics();
  793. drawdecays();
  794. drawflames();
  795. drawplayers();
  796. drawstats();
  797. plotsprites();
  798. copyup();
  799. if (list_empty(&activegeneric)) {
  800. player *pl;
  801. int deadplayers = 0;
  802. i = 0;
  803. list_for_each_entry(pl, &activeplayers, list) {
  804. if(!(pl->flags & FLG_DEAD))
  805. ++i;
  806. else
  807. deadplayers++;
  808. }
  809. if (deadplayers > 0 && (!i || (NETWORK_NONE != network && i==1))) {
  810. ++deathcount;
  811. if(deathcount==25)
  812. return CODE_ALLDEAD;
  813. } else
  814. deathcount=0;
  815. }
  816. return CODE_CONT;
  817. leave_game: /* client disconnect/timeout: send ACT_QUIT to master */
  818. myaction = ACT_QUIT;
  819. networktraffic();
  820. return CODE_QUIT;
  821. }
  822. void set_game_options(GameOptions *options) {
  823. gameoptions = *options;
  824. }
  825. void run_single_player(void) {
  826. int code;
  827. network = NETWORK_NONE;
  828. firstzero();
  829. initplayers();
  830. do {
  831. initgame();
  832. while(!(code=iterate()) && !exitflag) ++framecount;
  833. } while (code != CODE_QUIT && !exitflag);
  834. }
  835. void run_network_game(void) {
  836. int code;
  837. firstzero();
  838. initplayers();
  839. do {
  840. initgame();
  841. while (!(code=iterate()) && !exitflag) ++framecount;
  842. } while (code != CODE_QUIT && !exitflag);
  843. }