25 unsigned char responsible
; /* responsible for the next fault (if any) */
33 Ball ball
= { GAME_X_MID
, GAME_Y_MID
, BALL_DEFAULT_SPEED
, 0.2, 7.5 };
34 Ball ground
= { 0, 0, 0, 0, 0 };
35 Player player1
= { GAME_X_MIN
-4, GAME_Y_MID
, 0, 0, 1 };
36 Player player2
= { GAME_X_MAX
, GAME_Y_MID
, 0, 0, 0 };
49 show_bmp( "data/court.bmp", 0, 0, 255);
50 show_bmp( "data/shadow.png", ball
.x
, ball
.y
, 255);
52 show_sprite( RACKET_BMP
, (!player1
.state
), 4, player1
.x
, player1
.y
, 255);
53 show_sprite( RACKET_BMP
, (!player2
.state
)+2, 4, player2
.x
, player2
.y
, 255);
55 phase
= 2*1.6*ball
.jump
*get_phase( ball
.x
, GAME_X_MIN
, GAME_X_MAX
, ball
.move_x
);
59 /* after the ball hit the ground, responsibilities change */
60 player1
.responsible
= !(player2
.responsible
= !player2
.responsible
);
68 if( ground
.jump
&& !(i
%5)) ground
.jump
--;
72 show_sprite( "data/ground.png", ground
.jump
-1, 3, ground
.x
, ground
.y
, 128);
75 if( ball
.move_x
> 0) {
76 show_sprite( "data/ball.png", (i
/5)%4, 4, ball
.x
, ball
.y
-phase
, 255);
78 show_sprite( "data/ball.png", 3-(i
/5)%4, 4, ball
.x
, ball
.y
-phase
, 255);
81 show_digit( player1
.score
/10%10, 140*2, 14, 100);
82 show_digit( player1
.score
%10, 148*2, 14, 100);
83 show_digit( 10, 156*2, 14, 100);
84 show_digit( player2
.score
/10%10, 164*2, 14, 100);
85 show_digit( player2
.score
%10, 172*2, 14, 100);
89 if( IS_OUT_X(ball
.x
) || IS_OUT_Y(ball
.y
)) {
90 if( (IS_OUT_Y(ball
.y
) && player1
.responsible
) || (!(player1
.state
&& IS_NEAR_Y(player1
.y
, ball
.y
+phase
)) && ball
.x
< GAME_X_MIN
)) {
93 player2
.responsible
= !(player1
.responsible
= 1);
96 ball
.move_x
= fabsf( ball
.move_x
);
97 limit_value( &ball
.move_x
, ball
.move_x
, BALL_DEFAULT_SPEED
);
100 sound_applause_stop();
103 if( (IS_OUT_Y(ball
.y
) && player2
.responsible
) || (!(player2
.state
&& IS_NEAR_Y(player2
.y
, ball
.y
+phase
)) && ball
.x
> GAME_X_MAX
)) {
106 player1
.responsible
= !(player2
.responsible
= 1);
109 ball
.move_x
= -fabsf( ball
.move_x
);
110 limit_value( &ball
.move_x
, -BALL_DEFAULT_SPEED
, ball
.move_x
);
113 sound_applause_stop();
116 if( IS_OUT_X(ball
.x
)) {
117 if( ball
.move_x
< 0) {
119 if( player1
.state
== PLAYER_STATE_MAX
) {
120 ball
.move_x
= PLAYER_POWERSHOT
;
122 ball
.move_x
= 2.5 + 2.0*player1
.state
/PLAYER_STATE_MAX
;
124 ball
.move_y
= get_move_y( player1
.y
, ball
.y
-phase
, PLAYER_AREA
, ball
.move_x
, phase
);
125 ball
.jump
+= 1.0-2.0*(player1
.state
<5);
126 sound_racket( player1
.state
== PLAYER_STATE_MAX
);
129 if( player2
.state
== PLAYER_STATE_MAX
) {
130 ball
.move_x
= -PLAYER_POWERSHOT
;
132 ball
.move_x
= -(2.5 + 2.0*player2
.state
/PLAYER_STATE_MAX
);
134 ball
.move_y
= get_move_y( player2
.y
, ball
.y
-phase
, PLAYER_AREA
, ball
.move_x
, phase
);
135 ball
.jump
+= 1.0-2.0*(player2
.state
<5);
136 sound_racket( player2
.state
== PLAYER_STATE_MAX
);
141 ball
.x
+= ball
.move_x
*2;
142 ball
.y
+= ball
.move_y
*2;
144 if( player1
.state
) player1
.state
--;
145 if( player2
.state
) player2
.state
--;
148 keys
= SDL_GetKeyState( NULL
);
150 if( keys
['2']) player1
.y
-=8;
151 if( keys
['w']) player1
.y
-=6;
152 if( keys
['s']) player1
.y
+=6;
153 if( keys
['x']) player1
.y
+=8;
154 if( keys
['d'] && !player1
.state
) player1
.state
= PLAYER_STATE_MAX
;
156 if( keys
['9']) player2
.y
-=8;
157 if( keys
['o']) player2
.y
-=6;
158 if( keys
['l']) player2
.y
+=6;
159 if( keys
['.']) player2
.y
+=8;
160 if( keys
['k'] && !player2
.state
) player2
.state
= PLAYER_STATE_MAX
;
162 if( keys
['f']) SDL_WM_ToggleFullScreen( screen
);
164 if( keys
[SDLK_ESCAPE
] || keys
['q']) break;
166 limit_value( &player1
.y
, PLAYER_Y_MIN
, PLAYER_Y_MAX
);
167 limit_value( &player2
.y
, PLAYER_Y_MIN
, PLAYER_Y_MAX
);
168 limit_value( &ball
.jump
, BALL_JUMP_MIN
, BALL_JUMP_MAX
);
177 void limit_value( float* value
, float min
, float max
) {
180 } else if( *value
> max
) {
185 float get_phase( float x
, float min
, float max
, float direction
) {
188 pos
= (direction
>0)?(1-GROUND_PHASE
):(GROUND_PHASE
);
190 fract
= (x
-min
)/(max
-min
);
194 return fabsf( cosf(PI
*fract
/2));
196 fract
= (pos
-fract
)/(1-pos
);
197 return fabsf( sinf(PI
*fract
/2));
201 float get_move_y( float py
, float by
, float pa
, float move_x
, float phase
) {
202 float pct
, dest
, x_len
, y_len
;
204 /* 0.0 .. 1.0 for racket hit position */
205 pct
= ((py
+pa
)-by
)/(2*pa
);
206 limit_value( &pct
, 0.0, 1.0);
208 /* Y destination for ball */
209 dest
= GAME_Y_MIN
+ pct
*(GAME_Y_MAX
-GAME_Y_MIN
);
211 /* lengths for the ball's journey */
212 x_len
= GAME_X_MAX
- GAME_X_MIN
;
213 y_len
= dest
- py
+ phase
;
215 /* return the should-be value for move_y */
216 return (y_len
*move_x
)/(x_len
);