50b8baaf046b8591558c1e0223404da24ab1bcc7
[neverball] / putt / hole.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERPUTT is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <math.h>
18
19 #include "hole.h"
20 #include "glext.h"
21 #include "image.h"
22 #include "game.h"
23 #include "geom.h"
24 #include "hud.h"
25 #include "back.h"
26 #include "audio.h"
27 #include "config.h"
28 #include "fs.h"
29
30 /*---------------------------------------------------------------------------*/
31
32 struct hole
33 {
34     char   file[MAXSTR];
35     char   back[MAXSTR];
36     char   song[MAXSTR];
37     int    par;
38 };
39
40 static int hole;
41 static int party;
42 static int player;
43 static int count;
44 static int done;
45
46 static int         stat_v[MAXPLY];
47 static float       ball_p[MAXPLY][3];
48 static float       ball_e[MAXPLY][3][3];
49 static struct hole hole_v[MAXHOL];
50 static int        score_v[MAXHOL][MAXPLY];
51
52 /*---------------------------------------------------------------------------*/
53
54 static void hole_init_rc(const char *filename)
55 {
56     fs_file fin;
57     char buff[MAXSTR];
58
59     hole   = 0;
60     player = 0;
61     count  = 0;
62     done   = 0;
63
64     /* Load the holes list. */
65
66     if ((fin = fs_open(filename, "r")))
67     {
68         /* Skip shot and description. */
69
70         if (fs_gets(buff, sizeof (buff), fin) &&
71             fs_gets(buff, sizeof (buff), fin))
72         {
73             /* Read the list. */
74
75             while (fs_gets(buff, sizeof (buff), fin) &&
76                    sscanf(buff, "%s %s %d %s",
77                           hole_v[count].file,
78                           hole_v[count].back,
79                           &hole_v[count].par,
80                           hole_v[count].song) == 4)
81                 count++;
82         }
83
84         fs_close(fin);
85     }
86 }
87
88 /*---------------------------------------------------------------------------*/
89
90 void hole_init(const char *filename)
91 {
92     int i;
93
94     memset(hole_v,  0, sizeof (struct hole) * MAXHOL);
95     memset(score_v, 0, sizeof (int) * MAXPLY * MAXHOL);
96
97     hole_init_rc(filename);
98
99     for (i = 0; i < count; i++)
100         score_v[i][0] = hole_v[i].par;
101 }
102
103 void hole_free(void)
104 {
105     game_free();
106     back_free();
107
108     count = 0;
109 }
110
111 /*---------------------------------------------------------------------------*/
112
113 char *hole_player(int p)
114 {
115     if (p == 0)               return _("Par");
116
117     if (p == 1 && 1 <= party) return _("P1");
118     if (p == 2 && 2 <= party) return _("P2");
119     if (p == 3 && 3 <= party) return _("P3");
120     if (p == 4 && 4 <= party) return _("P4");
121
122     return NULL;
123 }
124
125 char *hole_score(int h, int p)
126 {
127     static char str[MAXSTR];
128
129     if (1 <= h && h <= hole)
130     {
131         if (h <= hole && 0 <= p && p <= party)
132         {
133             sprintf(str, "%d", score_v[h][p]);
134             return str;
135         }
136     }
137     return NULL;
138 }
139
140 char *hole_tot(int p)
141 {
142     static char str[MAXSTR];
143
144     int h, T = 0;
145
146     if (p <= party)
147     {
148         for (h = 1; h <= hole && h < count; h++)
149             T += score_v[h][p];
150
151         sprintf(str, "%d", T);
152
153         return str;
154     }
155     return NULL;
156 }
157
158 char *hole_out(int p)
159 {
160     static char str[MAXSTR];
161
162     int h, T = 0;
163
164     if (p <= party)
165     {
166         for (h = 1; h <= hole && h <= count / 2; h++)
167             T += score_v[h][p];
168
169         sprintf(str, "%d", T);
170
171         return str;
172     }
173     return NULL;
174 }
175
176 char *hole_in(int p)
177 {
178     static char str[MAXSTR];
179
180     int h, T = 0;
181     int out = count / 2;
182
183     if (hole > out && p <= party)
184     {
185         for (h = out + 1; h <= hole && h < count; h++)
186             T += score_v[h][p];
187
188         sprintf(str, "%d", T);
189
190         return str;
191     }
192     return NULL;
193 }
194
195 /*---------------------------------------------------------------------------*/
196
197 int curr_hole(void)   { return hole;   }
198 int curr_party(void)  { return party;  }
199 int curr_player(void) { return player; }
200 int curr_count(void)  { return count;  }
201
202 const char *curr_scr(void)
203 {
204     static char buf[8];
205
206     sprintf(buf, "%d", score_v[hole][player]);
207
208     return buf;
209 }
210
211 const char *curr_par(void)
212 {
213     static char buf[8];
214
215     sprintf(buf, "%d", score_v[hole][0]);
216
217     return buf;
218 }
219
220 /*---------------------------------------------------------------------------*/
221
222 void hole_goto(int h, int p)
223 {
224     int i;
225
226     if (h < count)
227     {
228         if (h >= 0) hole  = h;
229         if (p >= 0) party = p;
230
231         player = (hole - 1) % party + 1;
232         done   = 0;
233
234         back_init(hole_v[hole].back);
235         game_init(hole_v[hole].file);
236
237         for (i = 1; i <= party; i++)
238         {
239             game_get_pos(ball_p[i], ball_e[i]);
240             stat_v[i] = 0;
241         }
242         game_ball(player);
243         hole_song();
244     }
245 }
246
247 int hole_next(void)
248 {
249     if (done < party)
250     {
251         do
252         {
253             player = player % party + 1;
254         }
255         while (stat_v[player]);
256
257         game_ball(player);
258         game_get_pos(ball_p[player], ball_e[player]);
259
260         return 1;
261     }
262     return 0;
263 }
264
265 int hole_move(void)
266 {
267     if (hole + 1 < count)
268     {
269         hole++;
270
271         game_free();
272         back_free();
273
274         hole_goto(hole, party);
275
276         return 1;
277     }
278     return 0;
279 }
280
281 void hole_goal(void)
282 {
283     score_v[hole][player]++;
284
285     if (score_v[hole][player] == 1)
286         audio_play(AUD_ONE, 1.0f);
287
288     else if (score_v[hole][player] == score_v[hole][0] - 2)
289         audio_play(AUD_EAGLE, 1.0f);
290     else if (score_v[hole][player] == score_v[hole][0] - 1)
291         audio_play(AUD_BIRDIE, 1.0f);
292     else if (score_v[hole][player] == score_v[hole][0])
293         audio_play(AUD_PAR, 1.0f);
294     else if (score_v[hole][player] == score_v[hole][0] + 1)
295         audio_play(AUD_BOGEY, 1.0f);
296     else if (score_v[hole][player] == score_v[hole][0] + 2)
297         audio_play(AUD_DOUBLE, 1.0f);
298     else
299         audio_play(AUD_SUCCESS, 1.0f);
300
301     stat_v[player] = 1;
302     done++;
303
304     if (done == party)
305         audio_music_fade_out(2.0f);
306 }
307
308 void hole_stop(void)
309 {
310     score_v[hole][player]++;
311
312     /* Cap scores at 12 or par plus 3. */
313
314     if (score_v[hole][player] >= 12 &&
315         score_v[hole][player] >= score_v[hole][0] + 3)
316     {
317         score_v[hole][player] = (score_v[hole][0] > 12 - 3) ? score_v[hole][0] + 3 : 12;
318         stat_v[player] = 1;
319         done++;
320     }
321 }
322
323 void hole_fall(void)
324 {
325     audio_play(AUD_PENALTY, 1.0f);
326
327     /* Reset to the position of the putt, and apply a one-stroke penalty. */
328
329     game_set_pos(ball_p[player], ball_e[player]);
330     score_v[hole][player] += 2;
331
332     /* Cap scores at 12 or par plus 3. */
333
334     if (score_v[hole][player] >= 12 &&
335         score_v[hole][player] >= score_v[hole][0] + 3)
336     {
337         score_v[hole][player] = (score_v[hole][0] > 12 - 3) ? score_v[hole][0] + 3 : 12;
338         stat_v[player] = 1;
339         done++;
340     }
341 }
342
343 /*---------------------------------------------------------------------------*/
344
345 void hole_song(void)
346 {
347     audio_music_fade_to(0.5f, hole_v[hole].song);
348 }