640x480 version, graphics updated
[tennix.git] / game.c
bloba3af6e91d0a4998cea74c0850e89f583b87fa403
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;
30 float phase;
31 int ground_state = 0;
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 };
38 Uint8 *keys;
39 SDL_Event e;
41 clearscr();
42 updatescr();
43 wait_keypress();
45 sound_audience();
47 while( 1) {
48 clearscr();
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);
56 if( phase < 1.0) {
57 if( !ground_state) {
58 sound_ground();
59 /* after the ball hit the ground, responsibilities change */
60 player1.responsible = !(player2.responsible = !player2.responsible);
62 ground_state = 1;
63 ground.jump = 3;
64 ground.x = ball.x;
65 ground.y = ball.y;
66 } else {
67 ground_state = 0;
68 if( ground.jump && !(i%5)) ground.jump--;
71 if( 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);
77 } else {
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);
87 updatescr();
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)) {
91 player2.score++;
92 sound_applause();
93 player2.responsible = !(player1.responsible = 1);
94 ball.x = GAME_X_MID;
95 ball.y = GAME_Y_MID;
96 ball.move_x = fabsf( ball.move_x);
97 limit_value( &ball.move_x, ball.move_x, BALL_DEFAULT_SPEED);
98 ball.move_y = -0.1;
99 wait_keypress();
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)) {
104 player1.score++;
105 sound_applause();
106 player1.responsible = !(player2.responsible = 1);
107 ball.x = GAME_X_MID;
108 ball.y = GAME_Y_MID;
109 ball.move_x = -fabsf( ball.move_x);
110 limit_value( &ball.move_x, -BALL_DEFAULT_SPEED, ball.move_x);
111 ball.move_y = 0.1;
112 wait_keypress();
113 sound_applause_stop();
116 if( IS_OUT_X(ball.x)) {
117 if( ball.move_x < 0) {
118 ball.x = GAME_X_MIN;
119 if( player1.state == PLAYER_STATE_MAX) {
120 ball.move_x = PLAYER_POWERSHOT;
121 } else {
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);
127 } else {
128 ball.x = GAME_X_MAX;
129 if( player2.state == PLAYER_STATE_MAX) {
130 ball.move_x = -PLAYER_POWERSHOT;
131 } else {
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--;
147 SDL_PollEvent( &e);
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);
171 SDL_Delay( 7);
172 i++;
177 void limit_value( float* value, float min, float max) {
178 if( *value < min) {
179 *value = min;
180 } else if( *value > max) {
181 *value = max;
185 float get_phase( float x, float min, float max, float direction) {
186 float pos, fract;
188 pos = (direction>0)?(1-GROUND_PHASE):(GROUND_PHASE);
190 fract = (x-min)/(max-min);
192 if( fract < pos) {
193 fract = fract/pos;
194 return fabsf( cosf(PI*fract/2));
195 } else {
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);