Moved some "game mode" related stuff into ball/mode and removed the
[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 void level_scan_metadata(struct level *l, const struct s_file *fp)
45 {
46     int i;
47
48     for (i = 0; i < fp->dc; i++)
49     {
50         char *k = fp->av + fp->dv[i].ai;
51         char *v = fp->av + fp->dv[i].aj;
52
53         if (strcmp(k, "message") == 0)
54             strncpy(l->message, v, MAXSTR);
55         else if (strcmp(k, "back") == 0)
56             strncpy(l->back, v, PATHMAX);
57         else if (strcmp(k, "song") == 0)
58             strncpy(l->song, v, PATHMAX);
59         else if (strcmp(k, "grad") == 0)
60             strncpy(l->grad, v, PATHMAX);
61         else if (strcmp(k, "shot") == 0)
62             strncpy(l->shot, v, PATHMAX);
63         else if (strcmp(k, "goal") == 0)
64         {
65             l->goal = atoi(v);
66             l->score.most_coins.coins[2] = l->goal;
67         }
68         else if (strcmp(k, "time") == 0)
69         {
70             l->time = atoi(v);
71             l->score.best_times.timer[2] = l->time;
72             l->score.unlock_goal.timer[2] = l->time;
73         }
74         else if (strcmp(k, "time_hs") == 0)
75             sscanf(v, "%d %d",
76                    &l->score.best_times.timer[0],
77                    &l->score.best_times.timer[1]);
78         else if (strcmp(k, "goal_hs") == 0)
79             sscanf(v, "%d %d",
80                    &l->score.unlock_goal.timer[0],
81                    &l->score.unlock_goal.timer[1]);
82         else if (strcmp(k, "coin_hs") == 0)
83             sscanf(v, "%d %d",
84                    &l->score.most_coins.coins[0],
85                    &l->score.most_coins.coins[1]);
86         else if (strcmp(k, "version") == 0)
87             strncpy(l->version, v, MAXSTR);
88         else if (strcmp(k, "author") == 0)
89             strncpy(l->author, v, MAXSTR);
90         else if (strcmp(k, "bonus") == 0)
91             l->is_bonus = atoi(v);
92     }
93 }
94
95 /* Load the sol file 'filename' and fill the 'level' structure.  Return 1 on
96  * success, 0 on error. */
97
98 int level_load(const char *filename, struct level *level)
99 {
100     struct s_file sol;
101
102     int money;
103     int i;
104
105     memset(level, 0, sizeof (struct level));
106     memset(&sol,  0, sizeof (sol));
107
108     /* Try to load the sol file */
109     if (!sol_load_only_file(&sol, config_data(filename)))
110     {
111         fprintf(stderr,
112                 _("Error while loading level file '%s': %s\n"), filename,
113                 errno ? strerror(errno) : _("Not a valid level file"));
114         return 0;
115     }
116
117     strcpy(level->file, filename);
118
119     /* Init hs with default values */
120     score_init_hs(&level->score.best_times, 59999, 0);
121     score_init_hs(&level->score.unlock_goal, 59999, 0);
122     score_init_hs(&level->score.most_coins, 59999, 0);
123
124     /* Compute money and default max money */
125     money = 0;
126     for (i = 0; i < sol.hc; i++)
127         if (sol.hv[i].t == ITEM_COIN)
128             money += sol.hv[i].n;
129     level->score.most_coins.coins[0] = money;
130
131     /* Scan sol metadata */
132     if (sol.dc > 0)
133         level_scan_metadata(level, &sol);
134
135     /* Compute initial hs default values */
136
137 #define HOP(t, c) \
138     if (t[2] c t[0]) \
139         t[0] = t[1] = t[2]; \
140     else if (t[2] c t[1]) \
141         t[1] = (t[0] + t[2]) / 2
142
143     HOP(level->score.best_times.timer, <=);
144     HOP(level->score.unlock_goal.timer, <=);
145     HOP(level->score.most_coins.coins, >=);
146
147     sol_free(&sol);
148
149     return 1;
150 }
151
152 /*---------------------------------------------------------------------------*/
153
154 void level_dump_info(const struct level *l)
155 {
156     printf("filename:        %s\n"
157            "version:         %s\n"
158            "author:          %s\n"
159            "time limit:      %d\n"
160            "goal count:      %d\n"
161            "time hs:         %d %d %d\n"
162            "goal hs:         %d %d %d\n"
163            "coin hs:         %d %d %d\n"
164            "message:         %s\n"
165            "background:      %s\n"
166            "gradient:        %s\n"
167            "screenshot:      %s\n"
168            "song:            %s\n",
169            l->file,
170            l->version,
171            l->author,
172            l->time,
173            l->goal,
174            l->score.best_times.timer[0],
175            l->score.best_times.timer[1],
176            l->score.best_times.timer[2],
177            l->score.unlock_goal.timer[0],
178            l->score.unlock_goal.timer[1],
179            l->score.unlock_goal.timer[2],
180            l->score.most_coins.coins[0],
181            l->score.most_coins.coins[1],
182            l->score.most_coins.coins[2],
183            l->message,
184            l->back,
185            l->grad,
186            l->shot,
187            l->song);
188 }
189
190 /*---------------------------------------------------------------------------*/
191
192 const char *state_to_str(int m)
193 {
194     switch (m)
195     {
196     case GAME_NONE:    return _("Aborted");
197     case GAME_TIME:    return _("Time-out");
198     case GAME_SPEC:
199     case GAME_GOAL:    return _("Success");
200     case GAME_FALL:    return _("Fall-out");
201     default:           return _("Unknown");
202     }
203 }
204
205 /*---------------------------------------------------------------------------*/