Imported kball_final_src_16dec2004.tar.gz
[kball.git] / src / cball.cpp
blob7d7087b66adc4d9c2115d46b25488fdb89efdf24
1 // ------------------------------------------------------------------
2 // cball.cpp
3 // ------------------------------------------------------------------
4 // This class is the ball of the player
5 // By Kronoman - In loving memory of my father
6 // Copyright (c) 2003,2004, Kronoman
7 // ------------------------------------------------------------------
9 #include "cball.h"
10 #include "gerror.h"
11 #include "sphermap.h"
12 #include "sound.h"
14 // ------------------------------------------------------------------
15 // Constructor
16 // ------------------------------------------------------------------
17 CBall::CBall()
19 x = y = z = dx = dy = dz = 0.0;
20 spr = spr_shadow = spr_cache = NULL;
21 ctmap = NULL;
22 particle_manager = NULL;
24 lives = BALL_LIVES;
25 anglex = angley = 0.0;
26 score = 0;
28 // DEBUG - we use all available controllers by default
29 control.set_use_mouse(true);
30 control.set_use_joystick(true);
31 control.set_use_keyboard(true);
35 // ------------------------------------------------------------------
36 // Destructor
37 // ------------------------------------------------------------------
38 CBall::~CBall()
40 // release RAM
41 if (spr_cache != NULL)
43 destroy_bitmap(spr_cache);
44 spr_cache = NULL;
48 // ------------------------------------------------------------------
49 // Draw the ball, in bmp, displaced by sx,sy pixels
50 // This uses 3D Allegro polygon routines
51 // A *scene* must be initialized!!
52 // ------------------------------------------------------------------
53 void CBall::draw(BITMAP *bmp, int sx, int sy)
55 float s = 0; // scale (is added to the size, not multiplied!)
56 if (spr == NULL)
57 return ; // can't draw, set the sprite first (texture of sphere)
58 if (z < BALL_MIN_Z*0.95)
59 return ; // we are dead, the ball is gone, don't draw
61 // create sprite cache for rendering sphere texture (this is the size of texture, not the radius of the ball)
62 if (spr_cache == NULL)
63 spr_cache = create_bitmap(spr->w, spr->h);
65 if (spr_cache == NULL)
66 raise_error("ERROR: CBall:draw() -> can't create sprite texture render cache (spr_cache) (out of memory?)\n");
68 // if the ball is jumping or falling, we scale it acording to Z
69 if (z < -1.0)
71 s = - (z * BALL_RADIUS / BALL_MIN_Z);
74 if (z > 1.0)
76 s = (z * BALL_RADIUS * 2 / BALL_MAX_Z);
80 // render sphere
81 MATRIX m;
82 clear_to_color(spr_cache, makecol(255, 0, 255)); // magic pink fill
84 get_planet_rotation_matrix(&m, ftofix(anglex), ftofix(angley), 0); // rotate texture
85 mapped_sphere_ex(spr_cache, spr_cache->w / 2, spr_cache->h / 2, spr_cache->w / 2, spr, &m); // render texture
87 // add shadow enviroment map
88 set_trans_blender(200, 200, 200, 200); // transparent blender
89 draw_trans_sprite(spr_cache, spr_shadow, 0, 0); // blit the shiny shadow
92 // do a quad for render of the ball
93 V3D_f *v_xyz_p[4]; // this is needed to pass the array pointer to software renderer
94 V3D_f pc_v[4]; // the 4 vertex of the quad are precalculated and stored here
96 int poltype = POLYTYPE_ATEX_MASK; // type of polygon to render, usually POLYTYPE_ATEX_MASK
98 pc_v[0].x = x - sx - s;
99 pc_v[0].y = y - sy - s;
101 pc_v[1].x = x - sx + BALL_RADIUS * 2 + s;
102 pc_v[1].y = y - sy - s;
104 pc_v[2].x = x - sx + BALL_RADIUS * 2 + s;
105 pc_v[2].y = y - sy + BALL_RADIUS * 2 + s;
107 pc_v[3].x = x - sx - s;
108 pc_v[3].y = y - sy + BALL_RADIUS * 2 + s;
110 pc_v[0].z = pc_v[1].z = pc_v[2].z = pc_v[3].z = (z < 0) ? 2 : 0.25;
113 v_xyz_p[0] = &pc_v[0];
114 v_xyz_p[1] = &pc_v[1];
115 v_xyz_p[2] = &pc_v[2];
116 v_xyz_p[3] = &pc_v[3];
118 // texture map coordinates
119 pc_v[0].u = 0;
120 pc_v[0].v = 0;
121 pc_v[1].u = spr->w;
122 pc_v[1].v = 0;
123 pc_v[2].u = spr->w;
124 pc_v[2].v = spr->h;
125 pc_v[3].u = 0;
126 pc_v[3].v = spr->h;
128 scene_polygon3d_f(poltype, spr_cache, 4, v_xyz_p); // render polygon to scene
133 // ------------------------------------------------------------------
134 // Update ball logic, returns true if ball is 'dead'
135 // Also, does sounds, pick up prizes, etc... :)
136 // ------------------------------------------------------------------
138 int CBall::update_logic()
140 int ret ; // this ret is NOT used as return value of 'return' in this routine.
141 bool over_exit_floor = false; // we are over floor that is level's exit?
143 if (ctmap == NULL)
144 return CBALL_IS_FINE; // sorry, I don't know the map where I move
146 if (z < BALL_MIN_Z)
147 return CBALL_IS_DEAD; // we are dead (Z too low), we lose, we can't handle the ball, etc... :P // DEBUG : sound ?
149 // rotate the thing
150 if ((int)dx != 0 || (int)dy != 0 || (int)dz != 0)
152 // DEBUG - check this, the rotation is not 100% correct in certain cases
153 if ((angley >= 0 && angley <= 64) || (angley >= 192))
154 anglex -= dx;
155 else
156 anglex += dx;
158 angley -= dy;
160 if (anglex < 0)
161 anglex = 255;
162 if (anglex > 255)
163 anglex = 0;
164 if (angley < 0)
165 angley = 255;
166 if (angley > 255)
167 angley = 0;
171 // control input
172 ret = control.do_input_poll();
174 if (ret & KC_UP)
175 dy -= BALL_SPEED_Y;
176 if (ret & KC_DOWN)
177 dy += BALL_SPEED_Y;
178 if (ret & KC_LEFT)
179 dx -= BALL_SPEED_X;
180 if (ret & KC_RIGHT)
181 dx += BALL_SPEED_X;
183 // apply current tile floor transformations (current floor on center of the ball)
184 ret = ctmap->get_tile_type(((int)x + (BALL_RADIUS)) / TMAPS_W, ((int)y + (BALL_RADIUS)) / TMAPS_H, 0);
185 if (0 < z && z < 1.0) // only if 0 < Z < 1.0 we are in the floor
187 if (ret > 0) // is over a valid tile
190 if (ctmap->tile_set[ret].sound && (!ctmap->tile_set[ret].exit_level || (ctmap->tile_set[ret].exit_level && (ctmap->prize_map_indispensable<1) ) ) )
191 soundw.play_sample(ctmap->tile_set[ret].sound, rand() % 50 + 180, 128, 1000 + rand() % 250 - 125, 0); // SOUND of the tile, DEBUG
193 dx += ctmap->tile_set[ret].adx;
194 dy += ctmap->tile_set[ret].ady;
195 dz += ctmap->tile_set[ret].adz;
197 dx *= ctmap->tile_set[ret].mdx;
198 dy *= ctmap->tile_set[ret].mdy;
199 dz *= ctmap->tile_set[ret].mdz;
201 // if we are over a floor, we are safe
202 if (dz < 0)
203 dz = 0.0; // we aren't falling anymore =D
204 if (z < 1)
205 z = 1.0; // we are over floor =D
207 // this floor is exit?
208 over_exit_floor = ctmap->tile_set[ret].exit_level;
210 else
212 // if we are outside map or in a empty floor, we must fall to death... :^O
213 dz -= BALL_SPEED_Z; // negative dz, means fall!
216 else
218 z -= N_BALL_SPEED_Z; // apply gravity
221 // comprobations of max values
223 if (dy < -BALL_MSPEED)
224 dy = -BALL_MSPEED;
226 if (dy > BALL_MSPEED)
227 dy = BALL_MSPEED;
229 if (dx < -BALL_MSPEED)
230 dx = -BALL_MSPEED;
232 if (dx > BALL_MSPEED)
233 dx = BALL_MSPEED;
235 if (dz < -BALL_MSPEED)
236 dz = -BALL_MSPEED;
238 if (dz > BALL_MSPEED)
239 dz = BALL_MSPEED;
241 // friction
242 if (dy > 0)
243 dy -= N_BALL_SPEED_Y;
245 if (dy < 0)
246 dy += N_BALL_SPEED_Y;
248 if (dx > 0)
249 dx -= N_BALL_SPEED_X;
251 if (dx < 0)
252 dx += N_BALL_SPEED_X;
254 // 'dead zone' of the ball
255 if (dy < N_BALL_SPEED_Y*1.1 && dy > 0)
256 dy = 0.0;
258 if (dy > -N_BALL_SPEED_Y*1.1 && dy < 0)
259 dy = 0.0;
261 if (dx < N_BALL_SPEED_X*1.1 && dx > 0)
262 dx = 0.0;
264 if (dx > -N_BALL_SPEED_X*1.1 && dx < 0)
265 dx = 0.0;
267 // gravity (if dz > 1.0, the ball is jumping)
268 if (dz > 0)
269 dz -= N_BALL_SPEED_Z;
271 // Collision with walls -- DEBUG - DEBUG -- THIS NEEDS HEAVY CHECK!!!
272 // predict where the ball goes (for check collisions)
273 float xp, yp;
274 xp = x + dx;
275 yp = y + dy;
278 Atento:
279 formula para sacar el rebote
281 r = u - 2*n*(n dot u)
283 donde
284 r = vector que quiero
285 u = vector direccion bola
286 n = normal de la superficie (pared)
288 dot = producto escalar
292 if (z > 0) // only if z > 0 we are over the floor; we only collide with walls if we are over the floor. duh!
294 float n_dot_u = 0, yn = 0, xn = 0; // n dot u , n(x,y)
295 float part_x = 0, part_y = 0; // particle spark position
297 for (int i = 0; i < 8; i ++) // check 8 points of ball's sprite
299 // NOTE: the size of the bounding box is smaller than the ball radius
301 // BGAP: size to shrink the bounding box
302 #define BGAP 6
303 switch (i)
305 case 0: // up middle
306 part_x = xp + BALL_RADIUS;
307 part_y = yp + BGAP;
309 xn = 0;
310 yn = 1;
311 break;
313 case 1: // down middle
314 part_x = xp + BALL_RADIUS;
315 part_y = yp + BALL_RADIUS * 2 - BGAP;
316 xn = 0;
317 yn = -1;
318 break;
320 case 2: // left middle
321 part_x = xp + BGAP;
322 part_y = yp + BALL_RADIUS;
323 xn = 1;
324 yn = 0;
325 break;
327 case 3: // right middle
328 part_x = xp + BALL_RADIUS * 2 - BGAP;
329 part_y = yp + BALL_RADIUS;
330 xn = -1;
331 yn = 0;
332 break;
334 #define normalized_v 0.707106781
335 // this are the four cornes
336 // the weird numbers on normal vectors are because they are normalized!
337 case 4: // up left
338 part_x = xp + BGAP;
339 part_y = yp + BGAP;
340 xn = normalized_v;
341 yn = normalized_v;
342 break;
344 case 5: // down left
345 part_x = xp + BGAP;
346 part_y = yp + BALL_RADIUS * 2 - BGAP;
347 xn = normalized_v;
348 yn = -normalized_v;
349 break;
351 case 6: // up right
352 part_x = xp + BALL_RADIUS * 2 - BGAP;
353 part_y = yp + BGAP;
354 xn = -normalized_v;
355 yn = normalized_v;
356 break;
358 case 7: // down right
359 part_x = xp + BALL_RADIUS * 2 - BGAP;
360 part_y = yp + BALL_RADIUS * 2 - BGAP;
361 xn = -normalized_v;
362 yn = -normalized_v;
363 break;
364 #undef normalized_v
367 #undef BGAP
368 ret = ctmap->get_tile_type((int)part_x / TMAPS_W, (int)part_y / TMAPS_H, 0); // up
370 if (ret > 0)
372 if (ctmap->tile_set[ret].solid)
374 // DEBUG -- hack way to solve bug of corners!!
375 if (i < 4) // hack with corners - it WORKS, and that is what counts :P
377 // bounce!
378 n_dot_u = dx * xn + dy * yn;
379 // this is the real bounce, proper done with vectors (although most of the time it don't work :P)
380 dx = dx - 2 * xn * n_dot_u;
381 dy = dy - 2 * yn * n_dot_u;
383 else
385 dx *= -1; // hacky bounce for conners... I know, is wrong... I dont care...
386 dy *= -1;
387 } // end of hack
389 // bounce factor of wall
390 dx *= ctmap->tile_set[ret].bounce_factor;
391 dy *= ctmap->tile_set[ret].bounce_factor;
394 // DEBUG: the particle spark NEEDS to be accurate
395 for (int i = 0; i < rand() % 10 + 5; i++) // particle spark
396 particle_manager->add_particle(new CBaseParticle(part_x + (rand() % 6) - 3, part_y + (rand() % 6) - 3, (float)(rand() % 300) / 100.0*(dx < 0 ? -1 : 1), (float)(rand() % 300) / 100.0*(dy < 0 ? -1 : 1), makecol(255, rand() % 55 + 200, 0), rand() % 15 + 5));
398 // bounce sound
399 if (ctmap->tile_set[ret].sound)
400 soundw.play_sample(ctmap->tile_set[ret].sound, rand() % 56 + 200, 128 + rand() % 64 - 32, 1000 + rand() % 300 - 150, 0);
402 break; // end for (if not, the code will fail, will bounce many times, most of the time just rendering void the bounce)
408 // move the ball
411 x += dx;
412 y += dy;
413 z += dz;
415 if (x < 0)
416 x = 0;
418 if (y < 0)
419 y = 0;
421 if (x > TMAP_SIZE * TMAPS_W)
422 x = TMAP_SIZE * TMAPS_W;
424 if (y > TMAP_SIZE * TMAPS_H)
425 y = TMAP_SIZE * TMAPS_H;
427 if (z > BALL_MAX_Z) // top jump, hit the 'roof'
429 z = BALL_MAX_Z;
431 if (dz > 0)
432 dz = dz * 0.8; // decrease jump by 20 % also
435 // finally, check the 'prize' layer (only if we are over the floor)
437 ret = ctmap->get_tile_type(((int)x + (BALL_RADIUS)) / TMAPS_W, ((int)y + (BALL_RADIUS)) / TMAPS_H, 1);
439 if ((ctmap->tile_set[ret].indispensable || ctmap->tile_set[ret].is_a_prize) && z >= 0 && ret > 0)
442 score += ctmap->tile_set[ret].score;
444 if (ctmap->tile_set[ret].indispensable)
445 ctmap->prize_map_indispensable--;
447 ctmap->set_tile_type(((int)x + (BALL_RADIUS)) / TMAPS_W, ((int)y + (BALL_RADIUS)) / TMAPS_H, 1, 0); // clean the tile
449 // SOUND
450 if (ctmap->tile_set[ret].sound)
451 soundw.play_sample(ctmap->tile_set[ret].sound, rand() % 26 + 230, 128 + rand() % 64 - 32, 1000 + rand() % 100 - 50, 0);
453 // add score message
454 if (particle_manager != NULL)
456 char score_txt[256];
457 usprintf(score_txt, "%c%d", (ctmap->tile_set[ret].score > 0 ? '+' : '-'), ctmap->tile_set[ret].score);
459 particle_manager->add_particle(new CExplosiveTextParticle(x + BALL_RADIUS, y, 0.0, (float)(rand() % 100 + 25) / -100.0, makecol(255, rand() % 128 + 128, 0), rand() % 30 + 30, string(score_txt) ) );
461 for (int i = 0; i < rand() % 30 + 30; i++)
462 particle_manager->add_particle(new CSparkParticle(x + BALL_RADIUS, y + BALL_RADIUS, (float)((rand() % 800) - 400) / 100.0, (float)((rand() % 800) - 400) / 100.0, makecol(rand() % 128 + 128, 255, 0), rand() % 15 + 15, 3));
467 // if I'm not dead, and I'm over level exit and I'm still, exit level
468 if (over_exit_floor)
469 return CBALL_EXIT_LEVEL;
471 return CBALL_IS_FINE; // not dead yet ;)