1 /* Tower Toppler - Nebulus
2 * Copyright (C) 2000-2012 Andreas R�ver
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "game.h"
20
21 #include "stars.h"
22 #include "points.h"
23 #include "decl.h"
24 #include "screen.h"
25 #include "keyb.h"
26 #include "menu.h"
27 #include "level.h"
28 #include "elevators.h"
29 #include "robots.h"
30 #include "toppler.h"
31 #include "snowball.h"
32 #include "sound.h"
33
34 #include <string.h>
35 #include <stdlib.h>
36
37 typedef enum {
38 STATE_PLAYING,
39 STATE_ABORTED,
40 STATE_DIED,
41 STATE_TIMEOUT,
42 STATE_FINISHED
43 } gam_states;
44
gam_init(void)45 void gam_init(void) {
46 scr_init();
47 key_init();
48 }
49
gam_done(void)50 void gam_done(void) {
51 key_done();
52 scr_done();
53 }
54
gam_newgame(void)55 void gam_newgame(void) {
56 pts_reset();
57 }
58
gam_loadtower(Uint8 tow)59 void gam_loadtower(Uint8 tow) {
60 lev_selecttower(tow);
61 }
62
gam_arrival(void)63 void gam_arrival(void) {
64 int b, toppler, delay = 0;
65
66 rob_initialize();
67 snb_init();
68 char *passwd = lev_get_passwd();
69
70 bool svisible = true;
71 int substart = 0;
72 int subshape = 0;
73
74 b = 5;
75 toppler = 1;
76
77 top_hide();
78
79 key_readkey();
80
81 do {
82 scr_drawall(8, 0, lev_towertime(), svisible, subshape, substart, SF_NONE);
83 scr_darkenscreen();
84 scr_writetext_center((SCREENHEI / 6), _("You are entering the"));
85
86 if (strlen(lev_towername()))
87 scr_writetext_broken_center((SCREENHEI*2 / 6), _(lev_towername()));
88 else
89 scr_writetext_broken_center((SCREENHEI*2 / 6), _("Nameless Tower"));
90
91 if (passwd && lev_show_passwd(lev_towernr())) {
92 char buf[50];
93 snprintf(buf, 50, _("Password: %s"), passwd);
94 scr_writetext_center(SCREENHEI * 5 / 6, buf);
95 }
96 scr_swap();
97 ttsounds::instance()->play();
98
99 switch (b) {
100
101 case 5:
102 b = 6;
103 delay = 0;
104 break;
105
106 case 6:
107 delay++;
108 if (delay == 10) {
109 b = 0;
110 }
111 break;
112
113 case 0:
114 substart += 2;
115 if (substart == 70) {
116 b = 1;
117 top_show(0, toppler, 4);
118 delay = 0;
119 }
120 break;
121
122 case 1:
123 delay++;
124 subshape = 9 + delay;
125 if (delay == 21)
126 b = 2;
127 break;
128
129 case 2:
130 toppler++;
131 top_show(0, toppler, 4);
132 if (toppler == 8)
133 b = 3;
134 break;
135
136 case 3:
137 subshape--;
138 if (subshape == 9) {
139 b = 4;
140 }
141 break;
142
143 case 4:
144 substart -= 2;
145 if (substart == 0) {
146 b = 5;
147 svisible = false;
148 }
149 break;
150 }
151 dcl_wait();
152 } while (!((b == 5) || key_keypressed(fire_key)));
153
154 /* wait until the key has been released otherwise the space key
155 might already result in a snowball being thrown */
156 key_wait_for_none(NULL);
157 svisible = false;
158 }
159
gam_pick_up(Uint8 anglepos,Uint16 time)160 void gam_pick_up(Uint8 anglepos, Uint16 time) {
161 /* the shapes of the toppler when it turns after leaving a door*/
162 static unsigned char door4[4] = { 0xa, 0x9, 0x8, 0x0 };
163
164 int toppler, b, u, delay = 0;
165
166 b = u = 0;
167 toppler = 8;
168
169 top_show(door4[0], toppler, anglepos);
170
171 bool svisible = false;
172 int subshape = 0;
173 int substart = 0;
174
175 key_readkey();
176
177 do {
178 scr_drawall(8, (4 - anglepos) & 0x7f, time, svisible, subshape, substart, SF_NONE);
179 scr_swap();
180
181 switch (b) {
182
183 case 0:
184 u++;
185 top_show(door4[u / 2], toppler, anglepos);
186 if (u == 6) {
187 b = 1;
188 svisible = true;
189 }
190 break;
191
192 case 1:
193 substart += 2;
194 if (substart == 70) {
195 delay = 0;
196 b = 2;
197 }
198 break;
199
200 case 2:
201 delay++;
202 subshape = 9 + delay;
203 if (delay == 21)
204 b = 3;
205 break;
206
207 case 3:
208 toppler--;
209 top_show(door4[u / 2], toppler, anglepos);
210 if (toppler == 1)
211 b = 4;
212 break;
213
214 case 4:
215 subshape--;
216 if (subshape == 9) {
217 b = 5;
218 top_hide();
219 }
220 break;
221
222 case 5:
223 substart -= 2;
224 if (substart == 0) {
225 b = 6;
226 svisible = false;
227 }
228 break;
229 }
230 dcl_wait();
231 } while (!((b == 6) | key_keypressed(fire_key)));
232
233 top_hide();
234 svisible = false;
235 }
236
237 /* checks the new height reached and adds points */
new_height(int verticalpos,int & reached_height)238 static void new_height(int verticalpos, int &reached_height) {
239
240 if (verticalpos <= reached_height)
241 return;
242
243 while (reached_height < verticalpos) {
244 pts_add(10);
245 reached_height++;
246 }
247 }
248
249 /* updates the position of the tower on screen
250 with respect to the position of the animal
251
252 there is a slight lowpass in the vertical movement
253 of the tower */
towerpos(int verticalpos,int & tower_position,int anglepos,int & tower_angle)254 static unsigned short towerpos(int verticalpos, int &tower_position, int anglepos, int &tower_angle) {
255 int i, j;
256
257 j = anglepos - tower_angle;
258 if (j > 100) j -= 0x80;
259 if (j < -100) j += 0x80;
260 tower_angle = anglepos;
261
262
263 i = verticalpos - tower_position;
264
265 if (i > 0)
266 i = (i + 3) / 4;
267 else
268 i = -((3 - i) / 4);
269
270 sts_move(j, i);
271 tower_position += i;
272
273 ttsounds::instance()->setsoundvol(SND_WATER, verticalpos > 100 ? 30 : 128 - verticalpos);
274
275 return tower_position;
276 }
277
278 static int bg_tower_pos = 0;
279 static int bg_tower_angle = 0;
280 static int bg_time = 0;
281
282 /* men_yn() background drawing callback proc */
game_background_proc(void)283 static void game_background_proc(void) {
284 scr_drawall(towerpos(top_verticalpos(), bg_tower_pos,
285 top_anglepos(), bg_tower_angle), (4 - top_anglepos()) & 0x7f, bg_time, false, 0, 0, SF_NONE);
286
287 scr_darkenscreen();
288 }
289
timeout(int & tower_position,int & tower_anglepos)290 static void timeout(int &tower_position, int &tower_anglepos) {
291
292 bg_tower_pos = tower_position;
293 bg_tower_angle = tower_anglepos;
294 bg_time = 0;
295
296 set_men_bgproc(game_background_proc);
297
298 men_info(_("Time over"), 150);
299 }
300
writebonus(int & tower_position,int tower_anglepos,int zeit,int tec,int extra,int time,int lif,bool lifes)301 static void writebonus(int &tower_position, int tower_anglepos, int zeit, int tec, int extra, int time, int lif, bool lifes) {
302 char s[30];
303
304 scr_drawall(towerpos(top_verticalpos(), tower_position,
305 top_anglepos(), tower_anglepos), (4 - top_anglepos()) & 0x7f, time, false, 0, 0, SF_NONE);
306
307 scr_darkenscreen();
308
309 if (lifes) {
310 snprintf(s, 30, _("Time: ~t35010 X %3d"), zeit);
311 scr_writeformattext(90, (SCREENHEI / 2) - FONTHEI * 3, s);
312 snprintf(s, 30, _("Technique: ~t35010 X %3d"), tec);
313 scr_writeformattext(90, (SCREENHEI / 2) - FONTHEI, s);
314 snprintf(s, 30, _("Extra: ~t35010 X %3d"), extra);
315 scr_writeformattext(90, (SCREENHEI / 2) + FONTHEI, s);
316 snprintf(s, 30, _("Lifes: ~t3505000 X %3d"), lif);
317 scr_writeformattext(90, (SCREENHEI / 2) + FONTHEI * 3, s);
318 } else {
319 snprintf(s, 30, _("Time: ~t35010 X %3d"), zeit);
320 scr_writeformattext(90, (SCREENHEI / 2) - FONTHEI * 3, s);
321 snprintf(s, 30, _("Technique: ~t35010 X %3d"), tec);
322 scr_writeformattext(90, (SCREENHEI / 2), s);
323 snprintf(s, 30, _("Extra: ~t35010 X %3d"), extra);
324 scr_writeformattext(90, (SCREENHEI / 2) + FONTHEI * 3, s);
325 }
326
327 scr_swap();
328 }
329
countdown(int & s,int factor)330 static void countdown(int &s, int factor) {
331 if (s >= 100) {
332 s -= 100;
333 pts_add(100*factor);
334 return;
335 }
336 if (s >= 10) {
337 s -= 10;
338 pts_add(10*factor);
339 return;
340 }
341 if (s >= 1) {
342 (s)--;
343 pts_add(factor);
344 return;
345 }
346 }
347
bonus(int & tower_position,int & tower_angle,int time,bool lifes)348 static void bonus(int &tower_position, int &tower_angle, int time, bool lifes) {
349
350 int zeit, tec, extra, delay = 0;
351 int lif = pts_lifes();
352
353 zeit = time / 10;
354 extra = 100;
355 tec = top_technic();
356
357 do {
358 writebonus(tower_position, tower_angle, zeit, tec, extra, time, lif, lifes);
359 dcl_wait();
360 } while ((delay++ < 80) && !key_keypressed(fire_key));
361
362 while (zeit > 0) {
363 dcl_wait();
364 countdown(zeit, 10);
365 ttsounds::instance()->startsound(SND_SCORE);
366 ttsounds::instance()->play();
367 writebonus(tower_position, tower_angle, zeit, tec, extra, time, lif, lifes);
368 }
369
370 while (tec > 0) {
371 dcl_wait();
372 countdown(tec, 10);
373 ttsounds::instance()->startsound(SND_SCORE);
374 ttsounds::instance()->play();
375 writebonus(tower_position, tower_angle, zeit, tec, extra, time, lif, lifes);
376 }
377
378 while (extra > 0) {
379 dcl_wait();
380 countdown(extra, 10);
381 ttsounds::instance()->startsound(SND_SCORE);
382 ttsounds::instance()->play();
383 writebonus(tower_position, tower_angle, zeit, tec, extra, time, lif, lifes);
384 }
385
386 if (lifes) {
387 while (lif > 0) {
388 dcl_wait();
389 countdown(lif, 5000);
390 ttsounds::instance()->startsound(SND_SCORE);
391 ttsounds::instance()->play();
392 writebonus(tower_position, tower_angle, zeit, tec, extra, time, lif, lifes);
393 }
394 }
395
396 delay = 0;
397
398 do {
399 writebonus(tower_position, tower_angle, zeit, tec, extra, time, lif, lifes);
400 dcl_wait();
401 } while ((delay++ < 30) && (!key_keypressed(fire_key)));
402 }
403
404 /* update the time */
akt_time(int & time,int & timecount,gam_states & state)405 static void akt_time(int &time, int &timecount, gam_states &state) {
406 if (timecount >= 0) {
407 timecount++;
408 if (timecount == 5) {
409 timecount = 0;
410 time--;
411 if ((time >= 0) && (time <= 20 || (time <= 40 && (time % 2))))
412 ttsounds::instance()->startsound(SND_ALARM);
413 if (time == 0)
414 state = STATE_TIMEOUT;
415 }
416 }
417 }
418
get_keys(Sint8 & left_right,Sint8 & up_down,bool & space,Uint16 kstat)419 static void get_keys(Sint8 &left_right, Sint8 &up_down, bool &space, Uint16 kstat) {
420 #ifdef GAME_DEBUG_KEYS
421 if ((kstat & left_key) && (kstat & right_key) &&
422 (kstat & up_key) && (kstat & down_key)) {
423 run_debug_menu();
424 }
425 #endif /* GAME_DEBUG_KEYS */
426 if (kstat & left_key)
427 left_right = -1;
428 else {
429 if (kstat & right_key)
430 left_right = 1;
431 else
432 left_right = 0;
433 }
434
435 if (kstat & up_key)
436 up_down = 1;
437 else {
438 if (kstat & down_key)
439 up_down = -1;
440 else
441 up_down = 0;
442 }
443
444 if (kstat & fire_key)
445 space = true;
446 else
447 space = false;
448 }
449
escape(gam_states & state,int & tower_position,int & tower_anglepos,int time)450 static void escape(gam_states &state, int &tower_position, int &tower_anglepos, int time) {
451
452 ttsounds::instance()->stopsound(SND_WATER);
453
454 bg_tower_pos = tower_position;
455 bg_tower_angle = tower_anglepos;
456 bg_time = time;
457
458 set_men_bgproc(game_background_proc);
459 if (men_game())
460 state = STATE_ABORTED;
461
462 ttsounds::instance()->startsound(SND_WATER);
463 towerpos(top_verticalpos(), tower_position,
464 top_anglepos(), tower_anglepos);
465 }
466
pause(int & tower_position,int tower_anglepos,int time)467 static void pause(int &tower_position, int tower_anglepos, int time) {
468
469 ttsounds::instance()->stopsound(SND_WATER);
470
471 bg_tower_pos = tower_position;
472 bg_tower_angle = tower_anglepos;
473 bg_time = time;
474
475 set_men_bgproc(game_background_proc);
476 men_info(_("Pause"), -1, 1);
477
478 ttsounds::instance()->startsound(SND_WATER);
479 towerpos(top_verticalpos(), tower_position,
480 top_anglepos(), tower_anglepos);
481 }
482
gam_towergame(Uint8 & anglepos,Uint16 & resttime,int & demo,void * demobuf)483 gam_result gam_towergame(Uint8 &anglepos, Uint16 &resttime, int &demo, void *demobuf) {
484
485 static Uint8 door3[6] = {
486 0x17, 0x18, 0x18, 0x19, 0x19, 0xb
487 };
488
489 Sint8 left_right, up_down;
490 bool space;
491
492 gam_states state = STATE_PLAYING;
493
494 int demolen = 0, demo_alloc = 0;
495 Uint16 demokeys = 0;
496 Uint16 *dbuf = *(Uint16 **)demobuf;
497
498 screenflag drawflags = SF_NONE;
499
500 /* the maximal reached height for this tower */
501 int reached_height;
502
503 /* the tower position, the angle is the same as the toppler pos */
504 int tower_position;
505 int tower_angle;
506
507 /* subcounter for timer */
508 int timecount = 0;
509
510 /* time left for the player to reach the tower */
511 int time = lev_towertime();
512
513 if (demo == -1) drawflags = SF_REC;
514 else if (demo > 0) drawflags = SF_DEMO;
515
516 assert_msg(!(((demo == -1) || (demo > 0)) && !demobuf), "Trying to play or record a null demo.");
517
518 top_init();
519
520 reached_height = tower_position = top_verticalpos();
521 tower_angle = top_anglepos();
522
523 ele_init();
524 key_readkey();
525
526 do {
527
528 bg_tower_pos = tower_position;
529 bg_tower_angle = tower_angle;
530 bg_time = time;
531
532 if ((demo > 0) && (demolen < demo) && dbuf) {
533 demokeys = dbuf[demolen++];
534 get_keys(left_right, up_down, space, demokeys);
535 if ((demolen >= demo) || key_keystat()) state = STATE_ABORTED;
536 } else {
537 demokeys = key_keystat();
538 get_keys(left_right, up_down, space, demokeys);
539 }
540
541 if (demo == -1) {
542 if ((demolen >= demo_alloc) || (dbuf == NULL)) {
543 demo_alloc += 200;
544 Uint16 *tmp = new Uint16[demo_alloc];
545 if (demolen && (dbuf)) {
546 (void)memcpy(tmp, dbuf, demolen*sizeof(Uint16));
547 delete [] dbuf;
548 }
549 dbuf = tmp;
550 *(Uint16 **)demobuf = tmp;
551 }
552 dbuf[demolen++] = demokeys;
553 }
554
555 if ((demo >= 0) && (demolen > demo)) {
556 state = STATE_ABORTED;
557 break;
558 }
559
560 if (key_keypressed(break_key)) {
561 if (demo) state = STATE_ABORTED;
562 else
563 escape(state, tower_position, tower_angle, time);
564 }
565
566 if (key_keypressed(pause_key)) {
567 if (demo) state = STATE_ABORTED;
568 else
569 pause(tower_position, tower_angle, time);
570 }
571
572 if (!demo) key_readkey();
573
574 ele_update();
575 snb_movesnowball();
576 top_updatetoppler(left_right, up_down, space);
577
578 if (!top_dying())
579 rob_new(top_verticalpos());
580
581 rob_update();
582 top_testcollision();
583
584 akt_time(time, timecount, state);
585 new_height(top_verticalpos(), reached_height);
586 scr_drawall(towerpos(top_verticalpos(), tower_position,
587 top_anglepos(), tower_angle), (4 - top_anglepos()) & 0x7f, time, false, 0, 0, drawflags);
588 scr_swap();
589 ttsounds::instance()->play();
590 dcl_wait();
591 } while (!top_ended() && (state == STATE_PLAYING));
592
593 if (top_targetreached() && !demo) {
594 bonus(tower_position, tower_angle, time, lev_lasttower());
595 rob_disappearall();
596
597 for (int i = 0; i < 6; i++) {
598 top_show(door3[i], top_verticalpos(), top_anglepos());
599
600 rob_update();
601 scr_drawall(towerpos(top_verticalpos(), tower_position,
602 top_anglepos(), tower_angle), (4 - top_anglepos()) & 0x7f, time, false, 0, 0, drawflags);
603 scr_swap();
604 dcl_wait();
605 }
606
607 /* first remove all the layera above the target door */
608 while (lev_towerrows() > tower_position / 4 + 4) {
609
610 lev_removelayer(lev_towerrows()-1);
611 ttsounds::instance()->startsound(SND_CRUMBLE);
612 rob_update();
613 scr_drawall(towerpos(top_verticalpos(), tower_position,
614 top_anglepos(), tower_angle), (4 - top_anglepos()) & 0x7f, time, false, 0, 0, drawflags);
615 scr_swap();
616 ttsounds::instance()->play();
617
618 dcl_wait();
619
620 }
621
622 /* now remvoe all layers below the target door */
623 while (tower_position > 8) {
624
625 if (top_verticalpos() > 8) {
626 lev_removelayer(top_verticalpos() / 4 - 2);
627 ttsounds::instance()->startsound(SND_CRUMBLE);
628 top_drop1layer();
629 }
630
631 rob_update();
632 scr_drawall(towerpos(top_verticalpos(), tower_position,
633 top_anglepos(), tower_angle), (4 - top_anglepos()) & 0x7f, time, false, 0, 0, drawflags);
634 scr_swap();
635 ttsounds::instance()->play();
636
637 dcl_wait();
638 }
639
640 state = STATE_FINISHED;
641 } else if (top_died()) state = STATE_DIED;
642
643 anglepos = top_anglepos();
644 resttime = time;
645 key_readkey();
646
647 if (demo == -1) {
648 demo = demolen;
649 }
650 if (demo) state = STATE_ABORTED;
651
652 switch (state) {
653
654 case STATE_TIMEOUT:
655 timeout(tower_position, tower_angle);
656 pts_died();
657 return GAME_DIED;
658
659 case STATE_ABORTED:
660 return GAME_ABORTED;
661
662 case STATE_FINISHED:
663 return GAME_FINISHED;
664
665 case STATE_DIED:
666 pts_died();
667 return GAME_DIED;
668
669 default:
670 return GAME_FINISHED;
671 }
672 }
673
674