1 // ------------------------------------------------------------------
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 // ------------------------------------------------------------------
14 // ------------------------------------------------------------------
16 // ------------------------------------------------------------------
19 x
= y
= z
= dx
= dy
= dz
= 0.0;
20 spr
= spr_shadow
= spr_cache
= NULL
;
22 particle_manager
= NULL
;
25 anglex
= angley
= 0.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 // ------------------------------------------------------------------
37 // ------------------------------------------------------------------
41 if (spr_cache
!= NULL
)
43 destroy_bitmap(spr_cache
);
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!)
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
71 s
= - (z
* BALL_RADIUS
/ BALL_MIN_Z
);
76 s
= (z
* BALL_RADIUS
* 2 / BALL_MAX_Z
);
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
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?
144 return CBALL_IS_FINE
; // sorry, I don't know the map where I move
147 return CBALL_IS_DEAD
; // we are dead (Z too low), we lose, we can't handle the ball, etc... :P // DEBUG : sound ?
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))
172 ret
= control
.do_input_poll();
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
203 dz
= 0.0; // we aren't falling anymore =D
205 z
= 1.0; // we are over floor =D
207 // this floor is exit?
208 over_exit_floor
= ctmap
->tile_set
[ret
].exit_level
;
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!
218 z
-= N_BALL_SPEED_Z
; // apply gravity
221 // comprobations of max values
223 if (dy
< -BALL_MSPEED
)
226 if (dy
> BALL_MSPEED
)
229 if (dx
< -BALL_MSPEED
)
232 if (dx
> BALL_MSPEED
)
235 if (dz
< -BALL_MSPEED
)
238 if (dz
> BALL_MSPEED
)
243 dy
-= N_BALL_SPEED_Y
;
246 dy
+= N_BALL_SPEED_Y
;
249 dx
-= N_BALL_SPEED_X
;
252 dx
+= N_BALL_SPEED_X
;
254 // 'dead zone' of the ball
255 if (dy
< N_BALL_SPEED_Y
*1.1 && dy
> 0)
258 if (dy
> -N_BALL_SPEED_Y
*1.1 && dy
< 0)
261 if (dx
< N_BALL_SPEED_X
*1.1 && dx
> 0)
264 if (dx
> -N_BALL_SPEED_X
*1.1 && dx
< 0)
267 // gravity (if dz > 1.0, the ball is jumping)
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)
279 formula para sacar el rebote
281 r = u - 2*n*(n dot u)
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
306 part_x
= xp
+ BALL_RADIUS
;
313 case 1: // down middle
314 part_x
= xp
+ BALL_RADIUS
;
315 part_y
= yp
+ BALL_RADIUS
* 2 - BGAP
;
320 case 2: // left middle
322 part_y
= yp
+ BALL_RADIUS
;
327 case 3: // right middle
328 part_x
= xp
+ BALL_RADIUS
* 2 - BGAP
;
329 part_y
= yp
+ BALL_RADIUS
;
334 #define normalized_v 0.707106781
335 // this are the four cornes
336 // the weird numbers on normal vectors are because they are normalized!
346 part_y
= yp
+ BALL_RADIUS
* 2 - BGAP
;
352 part_x
= xp
+ BALL_RADIUS
* 2 - BGAP
;
358 case 7: // down right
359 part_x
= xp
+ BALL_RADIUS
* 2 - BGAP
;
360 part_y
= yp
+ BALL_RADIUS
* 2 - BGAP
;
368 ret
= ctmap
->get_tile_type((int)part_x
/ TMAPS_W
, (int)part_y
/ TMAPS_H
, 0); // up
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
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
;
385 dx
*= -1; // hacky bounce for conners... I know, is wrong... I dont care...
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));
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)
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'
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
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);
454 if (particle_manager
!= NULL
)
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
469 return CBALL_EXIT_LEVEL
;
471 return CBALL_IS_FINE
; // not dead yet ;)