Make Tennix easier by reducing bouncing
[tennix.git] / game.c
blob68632335b1a4067129e034bb1495ec0d7eb82b43
1 #include <stdio.h>
2 #include <math.h>
4 #include <SDL/SDL.h>
6 #include "tennix.h"
7 #include "game.h"
8 #include "graphics.h"
9 #include "input.h"
10 #include "sound.h"
12 typedef struct {
13 float x;
14 float y;
15 float move_x;
16 float move_y;
17 float jump;
18 } Ball;
20 typedef struct {
21 float x;
22 float y;
23 unsigned char state;
24 unsigned int score;
25 unsigned char responsible; /* responsible for the next fault (if any) */
26 } Player;
28 void game() {
29 int i, w;
30 int werbung[4];
31 float phase;
32 int ground_state = 0;
34 Ball ball = { GAME_X_MID, GAME_Y_MID, BALL_DEFAULT_SPEED, 0.2, 7.5 };
35 Ball ground = { 0, 0, 0, 0, 0 };
36 Player player1 = { GAME_X_MIN-4, GAME_Y_MID, 0, 0, 1 };
37 Player player2 = { GAME_X_MAX, GAME_Y_MID, 0, 0, 0 };
39 Uint8 *keys;
40 SDL_Event e;
42 for( w=0; w<4; w++) {
43 werbung[w] = rand()%SPONSOR_COUNT;
46 clearscr();
47 updatescr();
48 wait_keypress();
50 sound_audience();
52 while( 1) {
53 clearscr();
54 show_bmp( "data/court.bmp", 0, 0, 255);
56 show_bmp( "data/shadow.bmp", ball.x, ball.y, 128);
58 for( w=0; w<4; w++) {
59 show_sprite( SPONSOR_BMP, werbung[w], SPONSOR_COUNT, 60+50*w+5*(w>1), 7, 255);
62 show_sprite( RACKET_BMP, (!player1.state), 4, player1.x, player1.y, 255);
63 show_sprite( RACKET_BMP, (!player2.state)+2, 4, player2.x, player2.y, 255);
65 phase = 1.6*ball.jump*get_phase( ball.x, GAME_X_MIN, GAME_X_MAX, ball.move_x);
66 if( phase < 1.0) {
67 if( !ground_state) {
68 sound_ground();
69 /* after the ball hit the ground, responsibilities change */
70 player1.responsible = !(player2.responsible = !player2.responsible);
72 ground_state = 1;
73 ground.jump = 3;
74 ground.x = ball.x;
75 ground.y = ball.y;
76 } else {
77 ground_state = 0;
78 if( ground.jump && !(i%10)) ground.jump--;
81 if( ground.jump) {
82 show_sprite( "data/ground.bmp", ground.jump-1, 3, ground.x, ground.y, 255);
85 show_bmp( "data/ball.bmp", ball.x, ball.y-phase, 255);
87 show_bmp( "data/standings.bmp", 115, 160, 255);
88 show_digit( player1.score/10%10, 140, 180, 100);
89 show_digit( player1.score%10, 148, 180, 100);
90 show_digit( 10, 156, 180, 100);
91 show_digit( player2.score/10%10, 164, 180, 100);
92 show_digit( player2.score%10, 172, 180, 100);
94 updatescr();
96 if( i%2) {
97 if( IS_OUT_X(ball.x) || IS_OUT_Y(ball.y)) {
98 if( (IS_OUT_Y(ball.y) && player1.responsible) || (!(player1.state && IS_NEAR_Y(player1.y, ball.y+phase)) && ball.x < GAME_X_MIN)) {
99 player2.score++;
100 sound_applause();
101 player2.responsible = !(player1.responsible = 1);
102 ball.x = GAME_X_MID;
103 ball.y = GAME_Y_MID;
104 ball.move_x = fabsf( ball.move_x);
105 limit_value( &ball.move_x, ball.move_x, BALL_DEFAULT_SPEED);
106 ball.move_y = -0.1;
107 wait_keypress();
108 sound_applause_stop();
111 if( (IS_OUT_Y(ball.y) && player2.responsible) || (!(player2.state && IS_NEAR_Y(player2.y, ball.y+phase)) && ball.x > GAME_X_MAX)) {
112 player1.score++;
113 sound_applause();
114 player1.responsible = !(player2.responsible = 1);
115 ball.x = GAME_X_MID;
116 ball.y = GAME_Y_MID;
117 ball.move_x = -fabsf( ball.move_x);
118 limit_value( &ball.move_x, -BALL_DEFAULT_SPEED, ball.move_x);
119 ball.move_y = 0.1;
120 wait_keypress();
121 sound_applause_stop();
124 if( IS_OUT_X(ball.x)) {
125 if( ball.move_x < 0) {
126 ball.x = GAME_X_MIN;
127 if( player1.state == PLAYER_STATE_MAX) {
128 ball.move_x = PLAYER_POWERSHOT;
129 } else {
130 ball.move_x = 2.5 + 2.0*player1.state/PLAYER_STATE_MAX;
132 ball.move_y = get_move_y( player1.y, ball.y-phase, PLAYER_AREA, ball.move_x, phase);
133 ball.jump += 1.0-2.0*(player1.state<5);
134 sound_racket( player1.state == PLAYER_STATE_MAX);
135 } else {
136 ball.x = GAME_X_MAX;
137 if( player2.state == PLAYER_STATE_MAX) {
138 ball.move_x = -PLAYER_POWERSHOT;
139 } else {
140 ball.move_x = -(2.5 + 2.0*player2.state/PLAYER_STATE_MAX);
142 ball.move_y = get_move_y( player2.y, ball.y-phase, PLAYER_AREA, ball.move_x, phase);
143 ball.jump += 1.0-2.0*(player2.state<5);
144 sound_racket( player2.state == PLAYER_STATE_MAX);
149 ball.x += ball.move_x;
150 ball.y += ball.move_y;
152 if( player1.state) player1.state--;
153 if( player2.state) player2.state--;
156 limit_value( &player1.y, PLAYER_Y_MIN, PLAYER_Y_MAX);
157 limit_value( &player2.y, PLAYER_Y_MIN, PLAYER_Y_MAX);
158 limit_value( &ball.jump, BALL_JUMP_MIN, BALL_JUMP_MAX);
160 SDL_PollEvent( &e);
161 keys = SDL_GetKeyState( NULL);
163 if( keys['2']) player1.y-=3;
164 if( keys['w']) player1.y-=2;
165 if( keys['s']) player1.y+=2;
166 if( keys['x']) player1.y+=3;
167 if( keys['d'] && !player1.state) player1.state = PLAYER_STATE_MAX;
169 if( keys['9']) player2.y-=3;
170 if( keys['o']) player2.y-=2;
171 if( keys['l']) player2.y+=2;
172 if( keys['.']) player2.y+=3;
173 if( keys['k'] && !player2.state) player2.state = PLAYER_STATE_MAX;
175 if( keys['f']) SDL_WM_ToggleFullScreen( screen);
177 if( keys[SDLK_ESCAPE] || keys['q']) break;
180 SDL_Delay( 7);
181 i++;
186 void limit_value( float* value, float min, float max) {
187 if( *value < min) {
188 *value = min;
189 } else if( *value > max) {
190 *value = max;
194 float get_phase( float x, float min, float max, float direction) {
195 float pos, fract;
197 pos = (direction>0)?(1-GROUND_PHASE):(GROUND_PHASE);
199 fract = (x-min)/(max-min);
201 if( fract < pos) {
202 fract = fract/pos;
203 return fabsf( cosf(PI*fract/2));
204 } else {
205 fract = (pos-fract)/(1-pos);
206 return fabsf( sinf(PI*fract/2));
210 float get_move_y( float py, float by, float pa, float move_x, float phase) {
211 float pct, dest, x_len, y_len;
213 printf( "py = %.0f, by = %.0f, pa = %.0f\n", py, by, pa);
215 /* 0.0 .. 1.0 for racket hit position */
216 pct = ((py+pa)-by)/(2*pa);
217 limit_value( &pct, 0.0, 1.0);
219 /* Y destination for ball */
220 dest = GAME_Y_MIN + pct*(GAME_Y_MAX-GAME_Y_MIN);
222 /* lengths for the ball's journey */
223 x_len = GAME_X_MAX - GAME_X_MIN;
224 y_len = dest - py + phase;
226 printf( "py = %f, dest = %f, pct = %f, x_len = %f, y_len = %f\n", py, dest, pct, x_len, y_len);
228 /* return the should-be value for move_y */
229 return (y_len*move_x)/(x_len);