- moved lots of code around, made gameloop even more into a class
[supertux.git] / src / world.cpp
1 //
2 // C Implementation: world
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include "globals.h"
16 #include "scene.h"
17 #include "screen.h"
18 #include "defines.h"
19 #include "world.h"
20 #include "tile.h"
21
22 texture_type img_distro[4];
23
24 void bouncy_distro_init(bouncy_distro_type* pbouncy_distro, float x, float y)
25 {
26   pbouncy_distro->base.x = x;
27   pbouncy_distro->base.y = y;
28   pbouncy_distro->base.ym = -2;
29 }
30
31 void bouncy_distro_action(bouncy_distro_type* pbouncy_distro)
32 {
33   pbouncy_distro->base.y = pbouncy_distro->base.y + pbouncy_distro->base.ym * frame_ratio;
34
35   pbouncy_distro->base.ym += 0.1 * frame_ratio;
36
37   if (pbouncy_distro->base.ym >= 0)
38     bouncy_distros.erase(static_cast<std::vector<bouncy_distro_type>::iterator>(pbouncy_distro));
39 }
40
41 void bouncy_distro_draw(bouncy_distro_type* pbouncy_distro)
42 {
43   texture_draw(&img_distro[0],
44                pbouncy_distro->base.x - scroll_x,
45                pbouncy_distro->base.y);
46 }
47
48 void broken_brick_init(broken_brick_type* pbroken_brick, float x, float y, float xm, float ym)
49 {
50   pbroken_brick->base.x = x;
51   pbroken_brick->base.y = y;
52   pbroken_brick->base.xm = xm;
53   pbroken_brick->base.ym = ym;
54   timer_init(&pbroken_brick->timer, true);
55   timer_start(&pbroken_brick->timer,200);
56 }
57
58 void broken_brick_action(broken_brick_type* pbroken_brick)
59 {
60   pbroken_brick->base.x = pbroken_brick->base.x + pbroken_brick->base.xm * frame_ratio;
61   pbroken_brick->base.y = pbroken_brick->base.y + pbroken_brick->base.ym * frame_ratio;
62
63   if (!timer_check(&pbroken_brick->timer))
64     broken_bricks.erase(static_cast<std::vector<broken_brick_type>::iterator>(pbroken_brick));
65 }
66
67 void broken_brick_draw(broken_brick_type* pbroken_brick)
68 {
69   SDL_Rect src, dest;
70   src.x = rand() % 16;
71   src.y = rand() % 16;
72   src.w = 16;
73   src.h = 16;
74
75   dest.x = (int)(pbroken_brick->base.x - scroll_x);
76   dest.y = (int)pbroken_brick->base.y;
77   dest.w = 16;
78   dest.h = 16;
79
80   texture_draw_part(&img_brick[0],src.x,src.y,dest.x,dest.y,dest.w,dest.h);
81 }
82
83 void bouncy_brick_init(bouncy_brick_type* pbouncy_brick, float x, float y)
84 {
85   pbouncy_brick->base.x   = x;
86   pbouncy_brick->base.y   = y;
87   pbouncy_brick->offset   = 0;
88   pbouncy_brick->offset_m = -BOUNCY_BRICK_SPEED;
89   pbouncy_brick->shape    = GameSession::current()->get_level()->gettileid(x, y);
90 }
91
92 void bouncy_brick_action(bouncy_brick_type* pbouncy_brick)
93 {
94
95   pbouncy_brick->offset = (pbouncy_brick->offset +
96                            pbouncy_brick->offset_m * frame_ratio);
97
98   /* Go back down? */
99
100   if (pbouncy_brick->offset < -BOUNCY_BRICK_MAX_OFFSET)
101     pbouncy_brick->offset_m = BOUNCY_BRICK_SPEED;
102
103
104   /* Stop bouncing? */
105
106   if (pbouncy_brick->offset >= 0)
107     bouncy_bricks.erase(static_cast<std::vector<bouncy_brick_type>::iterator>(pbouncy_brick));
108 }
109
110 void bouncy_brick_draw(bouncy_brick_type* pbouncy_brick)
111 {
112   int s;
113   SDL_Rect dest;
114   
115   if (pbouncy_brick->base.x >= scroll_x - 32 &&
116       pbouncy_brick->base.x <= scroll_x + screen->w)
117     {
118       dest.x = (int)(pbouncy_brick->base.x - scroll_x);
119       dest.y = (int)pbouncy_brick->base.y;
120       dest.w = 32;
121       dest.h = 32;
122
123       Level* plevel = GameSession::current()->get_level();
124
125       // FIXME: overdrawing hack to clean the tile from the screen to
126       // paint it later at on offseted position
127       if(plevel->bkgd_image[0] == '\0')
128         {
129           fillrect(pbouncy_brick->base.x - scroll_x, pbouncy_brick->base.y,
130                    32,32, 
131                    plevel->bkgd_red, plevel->bkgd_green, plevel->bkgd_blue, 0);
132         }
133       else
134         {
135           s = (int)scroll_x / 30;
136           texture_draw_part(&img_bkgd,dest.x + s,dest.y,dest.x,dest.y,dest.w,dest.h);
137         }
138
139       drawshape(pbouncy_brick->base.x - scroll_x,
140                 pbouncy_brick->base.y + pbouncy_brick->offset,
141                 pbouncy_brick->shape);
142     }
143 }
144
145 void floating_score_init(floating_score_type* pfloating_score, float x, float y, int s)
146 {
147   pfloating_score->base.x = x;
148   pfloating_score->base.y = y - 16;
149   timer_init(&pfloating_score->timer,true);
150   timer_start(&pfloating_score->timer,1000);
151   pfloating_score->value = s;
152 }
153
154 void floating_score_action(floating_score_type* pfloating_score)
155 {
156   pfloating_score->base.y = pfloating_score->base.y - 2 * frame_ratio;
157
158   if(!timer_check(&pfloating_score->timer))
159     floating_scores.erase(static_cast<std::vector<floating_score_type>::iterator>(pfloating_score));
160 }
161
162 void floating_score_draw(floating_score_type* pfloating_score)
163 {
164   char str[10];
165   sprintf(str, "%d", pfloating_score->value);
166   text_draw(&gold_text, str, (int)pfloating_score->base.x + 16 - strlen(str) * 8, (int)pfloating_score->base.y, 1);
167 }
168
169 /* Break a brick: */
170 void trybreakbrick(float x, float y, bool small)
171 {
172   Level* plevel = GameSession::current()->get_level();
173   
174   Tile* tile = gettile(x, y);
175   if (tile->brick)
176     {
177       if (tile->data > 0)
178         {
179           /* Get a distro from it: */
180           add_bouncy_distro(((int)(x + 1) / 32) * 32,
181                             (int)(y / 32) * 32);
182
183           if (!counting_distros)
184             {
185               counting_distros = true;
186               distro_counter = 50;
187             }
188
189           if (distro_counter <= 0)
190             plevel->change(x, y, TM_IA, tile->next_tile);
191
192           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
193           score = score + SCORE_DISTRO;
194           distros++;
195         }
196       else if (!small)
197         {
198           /* Get rid of it: */
199           plevel->change(x, y, TM_IA, tile->next_tile);
200           
201           /* Replace it with broken bits: */
202           add_broken_brick(((int)(x + 1) / 32) * 32,
203                            (int)(y / 32) * 32);
204           
205           /* Get some score: */
206           play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
207           score = score + SCORE_BRICK;
208         }
209     }
210 }
211
212 /* Empty a box: */
213 void tryemptybox(float x, float y, int col_side)
214 {
215   Level* plevel = GameSession::current()->get_level();
216
217   Tile* tile = gettile(x,y);
218   if (!tile->fullbox)
219     return;
220
221   // according to the collision side, set the upgrade direction
222   if(col_side == LEFT)
223     col_side = RIGHT;
224   else
225     col_side = LEFT;
226
227   switch(tile->data)
228     {
229     case 1: //'A':      /* Box with a distro! */
230       add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
231       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
232       score = score + SCORE_DISTRO;
233       distros++;
234       break;
235
236     case 2: // 'B':      /* Add an upgrade! */
237       if (tux.size == SMALL)     /* Tux is small, add mints! */
238         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
239       else     /* Tux is big, add coffee: */
240         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
241       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
242       break;
243
244     case 3:// '!':     /* Add a golden herring */
245       add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
246       break;
247     default:
248       break;
249     }
250
251   /* Empty the box: */
252   plevel->change(x, y, TM_IA, tile->next_tile);
253 }
254
255 /* Try to grab a distro: */
256 void trygrabdistro(float x, float y, int bounciness)
257 {
258   Level* plevel = GameSession::current()->get_level();
259   Tile* tile = gettile(x, y);
260   if (tile && tile->distro)
261     {
262       plevel->change(x, y, TM_IA, tile->next_tile);
263       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
264
265       if (bounciness == BOUNCE)
266         {
267           add_bouncy_distro(((int)(x + 1) / 32) * 32,
268                             (int)(y / 32) * 32);
269         }
270
271       score = score + SCORE_DISTRO;
272       distros++;
273     }
274 }
275
276 /* Try to bump a bad guy from below: */
277 void trybumpbadguy(float x, float y)
278 {
279   /* Bad guys: */
280   for (unsigned int i = 0; i < bad_guys.size(); i++)
281     {
282       if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
283           bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
284         {
285           bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
286         }
287     }
288
289
290   /* Upgrades: */
291   for (unsigned int i = 0; i < upgrades.size(); i++)
292     {
293       if (upgrades[i].base.height == 32 &&
294           upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
295           upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
296         {
297           upgrades[i].base.xm = -upgrades[i].base.xm;
298           upgrades[i].base.ym = -8;
299           play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
300         }
301     }
302 }
303
304 /* EOF */
305