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