Metadata inclusion in levels. I hope everybody will be happy.
[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     while (c < stop)
49     {
50         /* look for the start of the value */
51         v = strchr(c, '=');
52         if (v==NULL)
53             return 0;
54         *v = '\0';
55         v++;
56         
57         /* look the end of the value */
58         e = strchr(v, '\n');
59         if (e==NULL)
60             return 0;
61         *e = '\0';
62         e ++;
63
64         /* test metadata */
65         if (CASE("message"))
66             strcpy(l->message, v);
67         else if (CASE("back"))
68             strcpy(l->back, v);
69         else if (CASE("song"))
70             strcpy(l->song, v);
71         else if (CASE("grad"))
72             strcpy(l->grad, v);
73         else if (CASE("shot"))
74             strcpy(l->shot, v);
75         else if (CASE("goal"))
76         {
77             l->goal = atoi(v);
78             l->coin_score.coins[2] = l->goal;
79         }
80         else if (CASE("time"))
81         {
82             l->time = atoi(v);
83             l->time_score.timer[2] = l->time;
84             l->goal_score.timer[2] = l->time;
85         }
86         else if (CASE("time_hs"))
87             sscanf(v, "%d %d",
88                     &l->time_score.timer[0],
89                     &l->time_score.timer[1]);
90         else if (CASE("goal_hs"))
91             sscanf(v, "%d %d",
92                     &l->goal_score.timer[0],
93                     &l->goal_score.timer[1]);
94         else if (CASE("coin_hs"))
95             sscanf(v, "%d %d",
96                     &l->coin_score.coins[0],
97                     &l->coin_score.coins[1]);
98         else if (CASE("levelname"))
99             strcpy(l->name, v);
100         else if (CASE("version"))
101             l->version = atoi(v);
102         else if (CASE("author"))
103             strcpy(l->author, v);
104         /*else
105             fprintf(stderr, "File %s, ignore %s metadata.\n", l->file, c);*/
106
107         c = e;
108     }
109     return 1;
110 }
111
112 int level_load(const char *filename, struct level *level)
113 /* Load the sol file 'filename' and fill the 'level' structure
114  * return 1 on success, 0 on error */
115 {
116     struct s_file sol; /* The solid file data */
117     int i;
118     int money; /* sum of coin value */
119    
120     /* raz level */
121     memset(level, 0, sizeof(struct level));
122     
123     memset(&sol, 0, sizeof(sol));
124
125     /* Try to load the sol file */
126     if (!sol_load_only_file(&sol, filename))
127     {
128         fprintf(stderr, "Error while loading level file '%s': ", filename);
129         if (errno)
130            perror(NULL);
131         else
132            fprintf(stderr, _("Not a valid level file\n"));
133         return 0;
134     }
135
136     /* Set filename */
137     strcpy(level->file, filename);
138     
139     /* Init hs with default values */
140     score_init_hs(&level->time_score, 59999, 0);
141     score_init_hs(&level->goal_score, 59999, 0);
142     score_init_hs(&level->coin_score, 59999, 0);
143
144     /* Compute money and default max money */
145     money = 0;
146     for (i = 0; i < sol.cc; i++)
147         money += sol.cv[i].n;
148     level->coin_score.coins[0] = money;
149     
150     /* Scan sol metadata */
151     if (sol.ac > 0)
152         level_scan_metadata(level, sol.av);
153
154     /* Compute initial hs default values */
155 #define HOP(t, c) if (t[2] c t[0]) t[0] = t[1] = t[2]; else if (t[2] c t[1]) t[1] = (t[0] + t[2]) / 2
156     HOP(level->time_score.timer, <=);
157     HOP(level->goal_score.timer, <=);
158     HOP(level->coin_score.coins, >=);
159
160     /* Free the sol structure, no more needed */    
161     sol_free(&sol);
162
163     return 1;
164 }
165
166 void level_dump_info(const struct level * level)
167 {
168     printf("filename:        %s\n"
169            "background:      %s\n"
170            "gradiant:        %s\n"
171            "screenshot:      %s\n"
172            "song:            %s\n"
173            "time limit:      %d\n"
174            "goal count:      %d\n",
175            level->file, level->back, level->grad, level->shot, level->song,
176            level->time, level->goal);
177 }
178
179 /*---------------------------------------------------------------------------*/
180
181 const char * mode_to_str(int m)
182 {
183     switch (m)
184     {
185     case MODE_CHALLENGE: return _("Challenge");
186     case MODE_NORMAL:    return _("Normal");
187     case MODE_PRACTICE:  return _("Practice");
188     case MODE_SINGLE:    return _("Single");
189     default:             return "???";
190     }
191 }
192
193 /*---------------------------------------------------------------------------*/
194
195 const char * state_to_str(int m)
196 {
197     switch (m)
198     {
199     case GAME_NONE:    return _("Aborted");
200     case GAME_TIME:    return _("Time-out");
201     case GAME_GOAL:    return _("Success");
202     case GAME_FALL:    return _("Fall-out");
203     default:           return "???";
204     }
205 }
206
207 /*---------------------------------------------------------------------------*/