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