tennis.map: Texture tweak
[neverball] / ball / st_ball.c
1 /*
2  * Copyright (C) 2003-2010 Neverball authors
3  *
4  * NEVERBALL 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 "gui.h"
16 #include "state.h"
17 #include "array.h"
18 #include "dir.h"
19 #include "config.h"
20 #include "fs.h"
21 #include "common.h"
22 #include "ball.h"
23 #include "cmd.h"
24 #include "audio.h"
25 #include "geom.h"
26 #include "video.h"
27 #include "demo.h"
28
29 #include "game_server.h"
30 #include "game_proxy.h"
31 #include "game_client.h"
32 #include "game_common.h"
33
34 #include "st_ball.h"
35 #include "st_conf.h"
36 #include "st_shared.h"
37
38 enum
39 {
40     BALL_NEXT = 1,
41     BALL_PREV,
42     BALL_BACK
43 };
44
45 static Array balls;
46 static int   curr_ball;
47 static char  ball_file[64];
48
49 static int name_id;
50
51 static int has_ball_sols(struct dir_item *item)
52 {
53     char *solid, *inner, *outer;
54     int yes;
55
56     solid = concat_string(item->path,
57                           "/",
58                           base_name(item->path),
59                           "-solid.sol",
60                           NULL);
61     inner = concat_string(item->path,
62                           "/",
63                           base_name(item->path),
64                           "-inner.sol",
65                           NULL);
66     outer = concat_string(item->path,
67                           "/",
68                           base_name(item->path),
69                           "-outer.sol",
70                           NULL);
71
72     yes = (fs_exists(solid) || fs_exists(inner) || fs_exists(outer));
73
74     free(solid);
75     free(inner);
76     free(outer);
77
78     return yes;
79 }
80
81 static void scan_balls(void)
82 {
83     int i;
84
85     SAFECPY(ball_file, config_get_s(CONFIG_BALL_FILE));
86
87     if ((balls = fs_dir_scan("ball", has_ball_sols)))
88     {
89         for (i = 0; i < array_len(balls); i++)
90         {
91             const char *path = DIR_ITEM_GET(balls, i)->path;
92
93             if (strncmp(ball_file, path, strlen(path)) == 0)
94             {
95                 curr_ball = i;
96                 break;
97             }
98         }
99     }
100 }
101
102 static void free_balls(void)
103 {
104     fs_dir_free(balls);
105     balls = NULL;
106 }
107
108 static void set_curr_ball(void)
109 {
110     sprintf(ball_file, "%s/%s",
111             DIR_ITEM_GET(balls, curr_ball)->path,
112             base_name(DIR_ITEM_GET(balls, curr_ball)->path));
113
114     config_set_s(CONFIG_BALL_FILE, ball_file);
115
116     ball_free();
117     ball_init();
118
119     gui_set_label(name_id, base_name(ball_file));
120 }
121
122 static int ball_action(int i)
123 {
124     audio_play(AUD_MENU, 1.0f);
125
126     switch (i)
127     {
128     case BALL_NEXT:
129         if (++curr_ball == array_len(balls))
130             curr_ball = 0;
131
132         set_curr_ball();
133
134         break;
135
136     case BALL_PREV:
137         if (--curr_ball == -1)
138             curr_ball = array_len(balls) - 1;
139
140         set_curr_ball();
141
142         break;
143
144     case BALL_BACK:
145         goto_state(&st_conf);
146         break;
147     }
148
149     return 1;
150 }
151
152 static void load_ball_demo(void)
153 {
154     int g;
155
156     /* "g" is a stupid hack to keep the goal locked. */
157
158     demo_replay_init("gui/ball.nbr", &g, NULL, NULL, NULL, NULL);
159     audio_music_fade_to(0.0f, "bgm/inter.ogg");
160     game_client_fly(0);
161     game_kill_fade();
162
163     back_init("back/gui.png");
164 }
165
166 static int ball_gui(void)
167 {
168     int id, jd;
169     int i;
170
171     if ((id = gui_vstack(0)))
172     {
173         if ((jd = gui_harray(id)))
174         {
175             gui_label(jd, _("Ball Model"), GUI_SML, GUI_ALL, 0, 0);
176             gui_space(jd);
177             gui_start(jd, _("Back"), GUI_SML, BALL_BACK, 0);
178         }
179
180         gui_space(id);
181
182         if ((jd = gui_hstack(id)))
183         {
184             gui_state(jd, " > ", GUI_SML, BALL_NEXT, 0);
185
186             name_id = gui_label(jd, "very-long-ball-name",
187                                 GUI_SML, GUI_ALL,
188                                 gui_wht, gui_wht);
189
190             gui_set_trunc(name_id, TRUNC_TAIL);
191             gui_set_fill(name_id);
192
193             gui_state(jd, " < ", GUI_SML, BALL_PREV, 0);
194         }
195
196         for (i = 0; i < 12; i++)
197             gui_space(id);
198
199         gui_layout(id, 0, 0);
200
201         gui_set_label(name_id, base_name(ball_file));
202     }
203
204     return id;
205 }
206
207 static int ball_enter(struct state *st, struct state *prev)
208 {
209     scan_balls();
210     load_ball_demo();
211
212     return ball_gui();
213 }
214
215 static void ball_leave(struct state *st, struct state *next, int id)
216 {
217     gui_delete(id);
218     back_free();
219     demo_replay_stop(0);
220     free_balls();
221 }
222
223 static void ball_paint(int id, float t)
224 {
225     video_push_persp((float) config_get_d(CONFIG_VIEW_FOV), 0.1f, FAR_DIST);
226     {
227         back_draw_easy();
228     }
229     video_pop_matrix();
230
231     game_client_draw(POSE_BALL, t);
232     gui_paint(id);
233 }
234
235 static void ball_timer(int id, float dt)
236 {
237     gui_timer(id, dt);
238
239     if (!demo_replay_step(dt))
240     {
241         demo_replay_stop(0);
242         load_ball_demo();
243     }
244
245     game_client_blend(demo_replay_blend());
246 }
247
248 static int ball_buttn(int b, int d)
249 {
250     if (d)
251     {
252         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
253             return ball_action(gui_token(gui_click()));
254
255         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
256             return ball_action(BALL_BACK);
257     }
258     return 1;
259 }
260
261 struct state st_ball = {
262     ball_enter,
263     ball_leave,
264     ball_paint,
265     ball_timer,
266     shared_point,
267     shared_stick,
268     NULL,
269     shared_click,
270     NULL,
271     ball_buttn
272 };