add infos in Modes and Secrets tabs
[neverball] / ball / level.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
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 <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19 #include <errno.h>
20
21 #include "level.h"
22 #include "solid.h"
23
24 /*---------------------------------------------------------------------------*/
25
26 void score_init_hs(struct score *s, int timer, int coins)
27 {
28     int i;
29
30     strcpy(s->player[0], "Hard");
31     strcpy(s->player[1], "Medium");
32     strcpy(s->player[2], "Easy");
33     strcpy(s->player[3], "");
34
35     for (i = 0; i < NSCORE + 1; i++)
36     {
37         s->timer[i] = timer;
38         s->coins[i] = coins;
39     }
40 }
41
42 /*---------------------------------------------------------------------------*/
43
44 static int level_scan_metadata(struct level *l, char *av)
45 {
46 #define CASE(x) (strcmp((x), c) == 0)
47     char *c    = av;
48     char *stop = av + strlen(av);
49     char *v, *e;
50
51     while (c < stop)
52     {
53         /* look for the start of the value */
54         v = strchr(c, '=');
55         if (v == NULL)
56             return 0;
57         *v = '\0';
58         v++;
59
60         /* look the end of the value */
61         e = strchr(v, '\n');
62         if (e == NULL)
63             return 0;
64         *e = '\0';
65         e++;
66
67         /* test metadata */
68         if (CASE("message"))
69             strcpy(l->message, v);
70         else if (CASE("back"))
71             strcpy(l->back, v);
72         else if (CASE("song"))
73             strcpy(l->song, v);
74         else if (CASE("grad"))
75             strcpy(l->grad, v);
76         else if (CASE("shot"))
77             strcpy(l->shot, v);
78         else if (CASE("goal"))
79         {
80             l->goal = atoi(v);
81             l->score.most_coins.coins[2] = l->goal;
82         }
83         else if (CASE("time"))
84         {
85             l->time = atoi(v);
86             l->score.best_times.timer[2] = l->time;
87             l->score.unlock_goal.timer[2] = l->time;
88         }
89         else if (CASE("time_hs"))
90             sscanf(v, "%d %d",
91                    &l->score.best_times.timer[0],
92                    &l->score.best_times.timer[1]);
93         else if (CASE("goal_hs"))
94             sscanf(v, "%d %d",
95                    &l->score.unlock_goal.timer[0],
96                    &l->score.unlock_goal.timer[1]);
97         else if (CASE("coin_hs"))
98             sscanf(v, "%d %d",
99                    &l->score.most_coins.coins[0],
100                    &l->score.most_coins.coins[1]);
101         else if (CASE("version"))
102             strcpy(l->version, v);
103         else if (CASE("author"))
104             strcpy(l->author, v);
105         else if (CASE("special"))
106             l->is_bonus = atoi(v);
107
108         c = e;
109     }
110     return 1;
111 }
112
113 /* Load the sol file 'filename' and fill the 'level' structure.  Return 1 on
114  * success, 0 on error. */
115
116 int level_load(const char *filename, struct level *level)
117 {
118     struct s_file sol;
119
120     int money;
121     int i;
122
123     memset(level, 0, sizeof (struct level));
124     memset(&sol,  0, sizeof (sol));
125
126     /* Try to load the sol file */
127     if (!sol_load_only_head(&sol, config_data(filename)))
128     {
129         fprintf(stderr,
130                 _("Error while loading level file '%s': %s\n"), filename,
131                 errno ? strerror(errno) : _("Not a valid level file"));
132         return 0;
133     }
134
135     strcpy(level->file, filename);
136
137     /* Init hs with default values */
138     score_init_hs(&level->score.best_times, 59999, 0);
139     score_init_hs(&level->score.unlock_goal, 59999, 0);
140     score_init_hs(&level->score.most_coins, 59999, 0);
141
142     /* Compute money and default max money */
143     money = 0;
144     for (i = 0; i < sol.hc; i++)
145         if (sol.hv[i].t == ITEM_COIN)
146             money += sol.hv[i].n;
147     level->score.most_coins.coins[0] = money;
148
149     /* Scan sol metadata */
150     if (sol.ac > 0)
151         level_scan_metadata(level, sol.av);
152
153     /* Compute initial hs default values */
154
155 #define HOP(t, c) \
156     if (t[2] c t[0]) \
157         t[0] = t[1] = t[2]; \
158     else if (t[2] c t[1]) \
159         t[1] = (t[0] + t[2]) / 2
160
161     HOP(level->score.best_times.timer, <=);
162     HOP(level->score.unlock_goal.timer, <=);
163     HOP(level->score.most_coins.coins, >=);
164
165     sol_free(&sol);
166
167     return 1;
168 }
169
170 /*---------------------------------------------------------------------------*/
171
172 void level_dump_info(const struct level *l)
173 {
174     printf("filename:        %s\n"
175            "version:         %s\n"
176            "author:          %s\n"
177            "time limit:      %d\n"
178            "goal count:      %d\n"
179            "time hs:         %d %d %d\n"
180            "goal hs:         %d %d %d\n"
181            "coin hs:         %d %d %d\n"
182            "message:         %s\n"
183            "background:      %s\n"
184            "gradiant:        %s\n"
185            "screenshot:      %s\n"
186            "song:            %s\n",
187            l->file,
188            l->version,
189            l->author,
190            l->time,
191            l->goal,
192            l->score.best_times.timer[0],
193            l->score.best_times.timer[1],
194            l->score.best_times.timer[2],
195            l->score.unlock_goal.timer[0],
196            l->score.unlock_goal.timer[1],
197            l->score.unlock_goal.timer[2],
198            l->score.most_coins.coins[0],
199            l->score.most_coins.coins[1],
200            l->score.most_coins.coins[2],
201            l->message,
202            l->back,
203            l->grad,
204            l->shot,
205            l->song);
206 }
207
208 /*---------------------------------------------------------------------------*/
209
210 const char *mode_to_str(int m)
211 {
212     switch (m)
213     {
214     case MODE_CHALLENGE: return _("Challenge");
215     case MODE_NORMAL:    return _("Normal");
216     case MODE_PRACTICE:  return _("Practice");
217     case MODE_SINGLE:    return _("Single");
218     default:             return _("Unknown");
219     }
220 }
221
222 /*---------------------------------------------------------------------------*/
223
224 const char *state_to_str(int m)
225 {
226     switch (m)
227     {
228     case GAME_NONE:    return _("Aborted");
229     case GAME_TIME:    return _("Time-out");
230     case GAME_SPEC:
231     case GAME_GOAL:    return _("Success");
232     case GAME_FALL:    return _("Fall-out");
233     default:           return _("Unknown");
234     }
235 }
236
237 /*---------------------------------------------------------------------------*/