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 "bonus.h"
20 #include "keyb.h"
21 #include "screen.h"
22 #include "menu.h"
23 #include "decl.h"
24 #include "points.h"
25 #include "level.h"
26 #include "sound.h"
27 
28 #include <stdlib.h>
29 
30 #define fishcnt         16
31 #define gametime        500
32 #define scrollerspeed   2
33 
34 /* position, status and movement direction
35  * of all the fishes
36  */
37 static struct {
38    Sint32 x;
39    Sint32 y;
40    Sint32 state;
41    Sint32 ydir;
42 } fish[fishcnt];
43 
44 /* position of the submarine and the torpedo,
45  * the state is taken from time
46  */
47 static Sint32 torpedox, torpedoy, subposx, subposy;
48 
49 /* current game time
50  */
51 static Sint32 time;
52 
53 /* current xposition, this is ongoing from tower to
54  * tower so that you continue where you've left of in
55  * the last bonus game
56  */
57 static Uint32 xpos = 0;
58 
59 /* this function displays everything of the bonus game */
show()60 static void show() {
61 
62   /* lets first calc the position of the tower on the screen */
63   Sint32 towerpos;
64 
65   if (time < gametime/2)
66     towerpos = -(4*time);
67   else
68     towerpos = gametime * scrollerspeed - 4*time + SCREENWID + (SPR_SLICEWID*2);
69 
70   /* draw the background layers */
71   scr_draw_bonus1(xpos, towerpos);
72 
73   /* if the torpedo is visible, draw it */
74   if (torpedox != -1)
75     scr_draw_torpedo(torpedoy, torpedox);
76 
77   /* output the submarine */
78   scr_draw_submarine(subposy - 20, subposx, time % 9);
79 
80   /* and the fishes */
81   for (int b = 0; b < fishcnt; b++)
82     if (fish[b].x >= -SPR_FISHWID)
83       scr_draw_fish(fish[b].y, fish[b].x, fish[b].state);
84 
85   /* and finally the forground layers of the scroller */
86   scr_draw_bonus2(xpos, towerpos);
87 }
88 
89 /* callback proc for menu drawing the current state and dim that picture */
bonus_background_proc(void)90 static void bonus_background_proc(void) {
91   show();
92   scr_darkenscreen();
93 }
94 
escape(void)95 static bool escape(void) {
96 
97   set_men_bgproc(bonus_background_proc);
98   return men_game();
99 }
100 
pause(void)101 static void pause(void) {
102 
103   set_men_bgproc(bonus_background_proc);
104   men_info(_("Pause"), -1, 1);
105 }
106 
bns_restart(void)107 void bns_restart(void) { xpos = 0; }
108 
bns_game(void)109 bool bns_game(void) {
110 
111   /* game local x position, moved since the start of
112    * this bonus game
113    */
114   Uint32 xpos_ofs = 0;
115 
116   /* when will the next fish appear */
117   Uint32 nextfish = 30;
118 
119   /* when automatic is switched on the submarine will move
120    * automatically to the tower base
121    */
122   bool automatic = false;
123 
124   /* the newtowercol is true, the towercolor has already been switched
125    * to the color of the tower we're going to arrive at
126    */
127   bool newtowercol = false;
128 
129   Uint8 b;
130 
131   subposx = SUBM_TARGET_X;
132   subposy = SUBM_TARGET_Y;
133 
134   /* no fished and no torpedo visible at game start */
135   for (b = 0; b < fishcnt; b++)
136     fish[b].x = -(SPR_FISHWID+1);
137   torpedox = -1;
138 
139   /* restart timer */
140   time = 0;
141 
142   key_readkey();
143 
144   do {
145 
146     /* move torpedo */
147     if (torpedox >= 0) {
148       torpedox += 8;
149       if (torpedox > (SCREENWID+SPR_TORPWID))
150         torpedox = -1;
151       for (b = 0; b < fishcnt; b++) {
152         if (fish[b].x > 0 && fish[b].state >= 32) {
153           if ((torpedox + SPR_TORPWID > fish[b].x) && (torpedox < fish[b].x + SPR_FISHWID) &&
154               (torpedoy + SPR_TORPHEI > fish[b].y) && (torpedoy < fish[b].y + SPR_FISHHEI)) {
155             torpedox = -1;
156             fish[b].state -= 32;
157             ttsounds::instance()->stopsound(SND_TORPEDO);
158           }
159         }
160       }
161     }
162 
163     /* move submarine */
164     if (!automatic) {
165       if (key_keypressed(fire_key)) {
166         if (torpedox == -1) {
167           torpedox = subposx + TORPEDO_OFS_X;
168           torpedoy = subposy + TORPEDO_OFS_Y;
169           ttsounds::instance()->startsound(SND_TORPEDO);
170         }
171       }
172 
173       if ((key_keystat() & down_key) != 0) {
174         if (subposy < SUBM_MAX_Y)
175           subposy += 4;
176       } else {
177         if ((key_keystat() & up_key) != 0) {
178           if (subposy > SUBM_MIN_Y)
179             subposy -= 4;
180         }
181       }
182 
183       if ((key_keystat() & left_key) != 0) {
184         if (subposx > SUBM_MIN_X)
185           subposx -= 8;
186       } else {
187         if ((key_keystat() & right_key) != 0) {
188           if (subposx < SUBM_MAX_X)
189             subposx += 4;
190         }
191       }
192     } else {
193       if (subposx > SUBM_TARGET_X)
194         subposx -= 8;
195       else if (subposx < SUBM_TARGET_X)
196         subposx += 4;
197 
198       if (subposy > SUBM_TARGET_Y)
199         subposy -= 4;
200     }
201 
202     /* escape or pausekey pressed */
203     if (key_keypressed(break_key))
204       if (escape()) {
205         return false;
206       }
207 
208     if (key_keypressed(pause_key))
209       pause();
210 
211     key_readkey();
212 
213     /* move the fish */
214     for (b = 0; b < fishcnt; b++) {
215       if (fish[b].x >= -SPR_FISHWID) {
216         fish[b].x -= 8;
217         fish[b].y += fish[b].ydir;
218         if (fish[b].y > 300 || fish[b].y < 80)
219           fish[b].ydir = -fish[b].ydir;
220 
221         if (fish[b].state >= 32)
222           fish[b].state = ((fish[b].state + 1) & 31) + 32;
223         else
224           fish[b].state = (fish[b].state + 1) & 31;
225 
226         if ((fish[b].state < 32) &&
227             (fish[b].x > subposx - 40) &&
228             (fish[b].x < subposx + 120) &&
229             (fish[b].y > subposy - 40) &&
230             (fish[b].y < subposy + 40)) {
231           pts_add(50);
232           ttsounds::instance()->startsound(SND_HIT);
233           fish[b].x = - (SPR_FISHWID + 1);
234         }
235       }
236     }
237 
238     /* nexfish handling */
239     if (nextfish > 0)
240       nextfish--;
241     else {
242       for (b = 0; b < fishcnt; b++) {
243         if (fish[b].x < -SPR_FISHWID) {
244           fish[b].x = SCREENWID;
245           fish[b].y = rand() / (RAND_MAX / 140) + 120;
246           fish[b].state = 32;
247           do {
248             fish[b].ydir = rand() / (RAND_MAX / 10) - 5;
249           } while (fish[b].ydir == 0);
250           nextfish = rand() / (RAND_MAX / 20) + 5;
251           break;
252         }
253       }
254     }
255 
256     /* change towercolor in the middle of the game */
257     if ((time > gametime/2) && !newtowercol) {
258       scr_settowercolor(lev_towercol_red(), lev_towercol_green(), lev_towercol_blue());
259       newtowercol = true;
260     }
261 
262     /* end of game, switch to automatic, stop scrolling */
263     if (time == gametime) {
264       automatic = true;
265       if ((subposx == SUBM_TARGET_X) && (subposy == SUBM_TARGET_Y)) break;
266     } else {
267       xpos +=4;
268       xpos_ofs += 4;
269       time++;
270     }
271 
272     if (!((time + 20) & 0x3f)) ttsounds::instance()->startsound(SND_SONAR);
273 
274     /* display screen and wait */
275     show();
276     scr_swap();
277     ttsounds::instance()->play();
278     dcl_wait();
279 
280   } while (true);
281 
282   return true;
283 }
284