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