1 /*
2  * Hedgewars, a free turn based strategy game
3  * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 
20 #include "team.h"
21 
22 #include "../util/inihelper.h"
23 #include "../util/util.h"
24 #include "../util/logging.h"
25 
26 #include <string.h>
27 #include <stdlib.h>
28 
from_ini_handleError(flib_team * result,flib_ini * settingfile)29 static flib_team *from_ini_handleError(flib_team *result, flib_ini *settingfile) {
30     flib_ini_destroy(settingfile);
31     flib_team_destroy(result);
32     return NULL;
33 }
34 
flib_team_from_ini(const char * filename)35 flib_team *flib_team_from_ini(const char *filename) {
36     if(log_badargs_if(filename==NULL)) {
37         return NULL;
38     }
39 
40     flib_team *result = flib_calloc(1, sizeof(flib_team));
41     flib_ini *ini = NULL;
42 
43     if(!result) {
44         return from_ini_handleError(result, ini);
45     }
46 
47     ini = flib_ini_load(filename);
48     if(!ini) {
49         flib_log_e("Error loading team file %s", filename);
50         return from_ini_handleError(result, ini);
51     }
52 
53     if(flib_ini_enter_section(ini, "team")) {
54         flib_log_e("Missing section \"Team\" in team file %s", filename);
55         return from_ini_handleError(result, ini);
56     }
57     bool error = false;
58     error |= flib_ini_get_str(ini, &result->name, "name");
59     error |= flib_ini_get_str(ini, &result->grave, "grave");
60     error |= flib_ini_get_str(ini, &result->fort, "fort");
61     error |= flib_ini_get_str(ini, &result->voicepack, "voicepack");
62     error |= flib_ini_get_str(ini, &result->flag, "flag");
63     error |= flib_ini_get_int(ini, &result->rounds, "rounds");
64     error |= flib_ini_get_int(ini, &result->wins, "wins");
65     error |= flib_ini_get_int(ini, &result->campaignProgress, "campaignprogress");
66 
67     int difficulty = 0;
68     error |= flib_ini_get_int(ini, &difficulty, "difficulty");
69 
70     if(error) {
71         flib_log_e("Missing or malformed entry in section \"Team\" in file %s", filename);
72         return from_ini_handleError(result, ini);
73     }
74 
75     for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
76         char sectionName[32];
77         if(snprintf(sectionName, sizeof(sectionName), "hedgehog%i", i) <= 0) {
78             return from_ini_handleError(result, ini);
79         }
80         if(flib_ini_enter_section(ini, sectionName)) {
81             flib_log_e("Missing section \"%s\" in team file %s", sectionName, filename);
82             return from_ini_handleError(result, ini);
83         }
84         flib_hog *hog = &result->hogs[i];
85         error |= flib_ini_get_str(ini, &hog->name, "name");
86         error |= flib_ini_get_str(ini, &hog->hat, "hat");
87         error |= flib_ini_get_int(ini, &hog->rounds, "rounds");
88         error |= flib_ini_get_int(ini, &hog->kills, "kills");
89         error |= flib_ini_get_int(ini, &hog->deaths, "deaths");
90         error |= flib_ini_get_int(ini, &hog->suicides, "suicides");
91         result->hogs[i].difficulty = difficulty;
92         result->hogs[i].initialHealth = TEAM_DEFAULT_HEALTH;
93 
94         if(error) {
95             flib_log_e("Missing or malformed entry in section \"%s\" in file %s", sectionName, filename);
96             return from_ini_handleError(result, ini);
97         }
98     }
99 
100     if(!flib_ini_enter_section(ini, "binds")) {
101         result->bindingCount = flib_ini_get_keycount(ini);
102         if(result->bindingCount<0) {
103             flib_log_e("Error reading bindings from file %s", filename);
104             result->bindingCount = 0;
105         }
106         result->bindings = flib_calloc(result->bindingCount, sizeof(flib_binding));
107         if(!result->bindings) {
108             return from_ini_handleError(result, ini);
109         }
110         for(int i=0; i<result->bindingCount; i++) {
111             char *keyname = flib_ini_get_keyname(ini, i);
112             if(!keyname) {
113                 error = true;
114             } else {
115                 result->bindings[i].action = flib_urldecode(keyname);
116                 error |= !result->bindings[i].action;
117                 error |= flib_ini_get_str(ini, &result->bindings[i].binding, keyname);
118             }
119             free(keyname);
120         }
121     }
122 
123     if(error) {
124         flib_log_e("Error reading team file %s", filename);
125         return from_ini_handleError(result, ini);
126     }
127 
128     flib_ini_destroy(ini);
129     return result;
130 }
131 
flib_team_destroy(flib_team * team)132 void flib_team_destroy(flib_team *team) {
133     if(team) {
134         for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
135             free(team->hogs[i].name);
136             free(team->hogs[i].hat);
137             flib_weaponset_destroy(team->hogs[i].weaponset);
138         }
139         free(team->name);
140         free(team->grave);
141         free(team->fort);
142         free(team->voicepack);
143         free(team->flag);
144         if(team->bindings) {
145             for(int i=0; i<team->bindingCount; i++) {
146                 free(team->bindings[i].action);
147                 free(team->bindings[i].binding);
148             }
149         }
150         free(team->bindings);
151         free(team->ownerName);
152         free(team);
153     }
154 }
155 
writeTeamSection(const flib_team * team,flib_ini * ini)156 static int writeTeamSection(const flib_team *team, flib_ini *ini) {
157     if(flib_ini_create_section(ini, "team")) {
158         return -1;
159     }
160     bool error = false;
161     error |= flib_ini_set_str(ini, "name",  team->name);
162     error |= flib_ini_set_str(ini, "grave", team->grave);
163     error |= flib_ini_set_str(ini, "fort", team->fort);
164     error |= flib_ini_set_str(ini, "voicepack", team->voicepack);
165     error |= flib_ini_set_str(ini, "flag", team->flag);
166     error |= flib_ini_set_int(ini, "rounds", team->rounds);
167     error |= flib_ini_set_int(ini, "wins", team->wins);
168     error |= flib_ini_set_int(ini, "campaignprogress", team->campaignProgress);
169     error |= flib_ini_set_int(ini, "difficulty", team->hogs[0].difficulty);
170     return error;
171 }
172 
writeHogSections(const flib_team * team,flib_ini * ini)173 static int writeHogSections(const flib_team *team, flib_ini *ini) {
174     for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
175         const flib_hog *hog = &team->hogs[i];
176         char sectionName[32];
177         if(snprintf(sectionName, sizeof(sectionName), "hedgehog%i", i) <= 0) {
178             return -1;
179         }
180         if(flib_ini_create_section(ini, sectionName)) {
181             return -1;
182         }
183         bool error = false;
184         error |= flib_ini_set_str(ini, "name", hog->name);
185         error |= flib_ini_set_str(ini, "hat", hog->hat);
186         error |= flib_ini_set_int(ini, "rounds", hog->rounds);
187         error |= flib_ini_set_int(ini, "kills", hog->kills);
188         error |= flib_ini_set_int(ini, "deaths", hog->deaths);
189         error |= flib_ini_set_int(ini, "suicides", hog->suicides);
190         if(error) {
191             return error;
192         }
193     }
194     return 0;
195 }
196 
writeBindingSection(const flib_team * team,flib_ini * ini)197 static int writeBindingSection(const flib_team *team, flib_ini *ini) {
198     if(team->bindingCount == 0) {
199         return 0;
200     }
201     if(flib_ini_create_section(ini, "binds")) {
202         return -1;
203     }
204     for(int i=0; i<team->bindingCount; i++) {
205         bool error = false;
206         char *action = flib_urlencode(team->bindings[i].action);
207         if(action) {
208             error |= flib_ini_set_str(ini, action, team->bindings[i].binding);
209             free(action);
210         } else {
211             error = true;
212         }
213         if(error) {
214             return error;
215         }
216     }
217     return 0;
218 }
219 
flib_team_to_ini(const char * filename,const flib_team * team)220 int flib_team_to_ini(const char *filename, const flib_team *team) {
221     int result = -1;
222     if(!log_badargs_if2(filename==NULL, team==NULL)) {
223         flib_ini *ini = flib_ini_create(filename);
224         bool error = false;
225         error |= writeTeamSection(team, ini);
226         error |= writeHogSections(team, ini);
227         error |= writeBindingSection(team, ini);
228         if(!error) {
229             result = flib_ini_save(ini, filename);
230         }
231         flib_ini_destroy(ini);
232     }
233     return result;
234 }
235 
flib_team_set_weaponset(flib_team * team,const flib_weaponset * set)236 int flib_team_set_weaponset(flib_team *team, const flib_weaponset *set) {
237     if(team) {
238         for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
239             flib_weaponset_destroy(team->hogs[i].weaponset);
240             team->hogs[i].weaponset = flib_weaponset_copy(set);
241             if(set && !team->hogs[i].weaponset) {
242                 return -1;
243             }
244         }
245     }
246     return 0;
247 }
248 
flib_team_set_health(flib_team * team,int health)249 void flib_team_set_health(flib_team *team, int health) {
250     if(team) {
251         for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
252             team->hogs[i].initialHealth = health;
253         }
254     }
255 }
256 
strdupWithError(const char * in,bool * error)257 static char *strdupWithError(const char *in, bool *error) {
258     char *out = flib_strdupnull(in);
259     if(in && !out) {
260         *error = true;
261     }
262     return out;
263 }
264 
flib_team_copy(const flib_team * team)265 flib_team *flib_team_copy(const flib_team *team) {
266     flib_team *result = NULL;
267     if(team) {
268         flib_team *tmpTeam = flib_calloc(1, sizeof(flib_team));
269         if(tmpTeam) {
270             bool error = false;
271 
272             for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
273                 tmpTeam->hogs[i].name = strdupWithError(team->hogs[i].name, &error);
274                 tmpTeam->hogs[i].hat = strdupWithError(team->hogs[i].hat, &error);
275                 tmpTeam->hogs[i].rounds = team->hogs[i].rounds;
276                 tmpTeam->hogs[i].kills = team->hogs[i].kills;
277                 tmpTeam->hogs[i].deaths = team->hogs[i].deaths;
278                 tmpTeam->hogs[i].suicides = team->hogs[i].suicides;
279                 tmpTeam->hogs[i].difficulty = team->hogs[i].difficulty;
280                 tmpTeam->hogs[i].initialHealth = team->hogs[i].initialHealth;
281                 tmpTeam->hogs[i].weaponset = flib_weaponset_copy(team->hogs[i].weaponset);
282                 if(team->hogs[i].weaponset && !tmpTeam->hogs[i].weaponset) {
283                     error = true;
284                 }
285             }
286 
287             tmpTeam->name = strdupWithError(team->name, &error);
288             tmpTeam->grave = strdupWithError(team->grave, &error);
289             tmpTeam->fort = strdupWithError(team->fort, &error);
290             tmpTeam->voicepack = strdupWithError(team->voicepack, &error);
291             tmpTeam->flag = strdupWithError(team->flag, &error);
292             tmpTeam->ownerName = strdupWithError(team->ownerName, &error);
293 
294             tmpTeam->bindingCount = team->bindingCount;
295             if(team->bindings) {
296                 tmpTeam->bindings = flib_calloc(team->bindingCount, sizeof(flib_binding));
297                 if(tmpTeam->bindings) {
298                     for(int i=0; i<tmpTeam->bindingCount; i++) {
299                         tmpTeam->bindings[i].action = strdupWithError(team->bindings[i].action, &error);
300                         tmpTeam->bindings[i].binding = strdupWithError(team->bindings[i].binding, &error);
301                     }
302                 } else {
303                     error = true;
304                 }
305             }
306 
307             tmpTeam->rounds = team->rounds;
308             tmpTeam->wins = team->wins;
309             tmpTeam->campaignProgress = team->campaignProgress;
310 
311             tmpTeam->colorIndex = team->colorIndex;
312             tmpTeam->hogsInGame = team->hogsInGame;
313             tmpTeam->remoteDriven = team->remoteDriven;
314 
315             if(!error) {
316                 result = tmpTeam;
317                 tmpTeam = 0;
318             }
319         }
320         flib_team_destroy(tmpTeam);
321     }
322     return result;
323 }
324