1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17 #define MELEESETUP_INTERNAL
18 #include "port.h"
19 #include "meleesetup.h"
20
21 #include "../master.h"
22 #include "libs/log.h"
23
24
25 ///////////////////////////////////////////////////////////////////////////
26
27 // Temporary
28 const size_t MeleeTeam_serialSize = MELEE_FLEET_SIZE +
29 sizeof (((MeleeTeam*)0)->name);
30
31 void
MeleeTeam_init(MeleeTeam * team)32 MeleeTeam_init (MeleeTeam *team)
33 {
34 FleetShipIndex slotI;
35
36 for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
37 team->ships[slotI] = MELEE_NONE;
38
39 team->name[0] = '\0';
40 }
41
42 void
MeleeTeam_uninit(MeleeTeam * team)43 MeleeTeam_uninit (MeleeTeam *team)
44 {
45 (void) team;
46 }
47
48 MeleeTeam *
MeleeTeam_new(void)49 MeleeTeam_new (void)
50 {
51 MeleeTeam *result = HMalloc (sizeof (MeleeTeam));
52 MeleeTeam_init (result);
53 return result;
54 }
55
56 void
MeleeTeam_delete(MeleeTeam * team)57 MeleeTeam_delete (MeleeTeam *team)
58 {
59 MeleeTeam_uninit (team);
60 HFree (team);
61 }
62
63 int
MeleeTeam_serialize(const MeleeTeam * team,uio_Stream * stream)64 MeleeTeam_serialize (const MeleeTeam *team, uio_Stream *stream)
65 {
66 FleetShipIndex slotI;
67
68 for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) {
69 if (uio_putc ((int) team->ships[slotI], stream) == EOF)
70 return -1;
71 }
72 if (uio_fwrite ((const char *) team->name, sizeof team->name, 1,
73 stream) != 1)
74 return -1;
75
76 return 0;
77 }
78
79 int
MeleeTeam_deserialize(MeleeTeam * team,uio_Stream * stream)80 MeleeTeam_deserialize (MeleeTeam *team, uio_Stream *stream)
81 {
82 FleetShipIndex slotI;
83
84 // Sanity check on the ships.
85 for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
86 {
87 int ship = uio_getc (stream);
88 if (ship == EOF)
89 goto err;
90 team->ships[slotI] = (MeleeShip) ship;
91
92 if (team->ships[slotI] == MELEE_NONE)
93 continue;
94
95 if (team->ships[slotI] >= NUM_MELEE_SHIPS)
96 {
97 log_add (log_Warning, "Invalid ship type in loaded team (index "
98 "%d, ship type is %d, max valid is %d).",
99 slotI, team->ships[slotI], NUM_MELEE_SHIPS - 1);
100 team->ships[slotI] = MELEE_NONE;
101 }
102 }
103
104 if (uio_fread (team->name, sizeof team->name, 1, stream) != 1)
105 goto err;
106
107 team->name[MAX_TEAM_CHARS] = '\0';
108
109 return 0;
110
111 err:
112 MeleeTeam_delete(team);
113 return -1;
114 }
115
116 // XXX: move this to elsewhere?
117 COUNT
MeleeTeam_getValue(const MeleeTeam * team)118 MeleeTeam_getValue (const MeleeTeam *team)
119 {
120 COUNT total = 0;
121 FleetShipIndex slotI;
122
123 for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
124 {
125 MeleeShip ship = team->ships[slotI];
126 COUNT shipValue = GetShipValue (ship);
127 if (shipValue == (COUNT)~0)
128 {
129 // Invalid ship.
130 continue;
131 }
132 total += shipValue;
133 }
134
135 return total;
136 }
137
138 MeleeShip
MeleeTeam_getShip(const MeleeTeam * team,FleetShipIndex slotNr)139 MeleeTeam_getShip (const MeleeTeam *team, FleetShipIndex slotNr)
140 {
141 return team->ships[slotNr];
142 }
143
144 void
MeleeTeam_setShip(MeleeTeam * team,FleetShipIndex slotNr,MeleeShip ship)145 MeleeTeam_setShip (MeleeTeam *team, FleetShipIndex slotNr, MeleeShip ship)
146 {
147 team->ships[slotNr] = ship;
148 }
149
150 const MeleeShip *
MeleeTeam_getFleet(const MeleeTeam * team)151 MeleeTeam_getFleet (const MeleeTeam *team)
152 {
153 return team->ships;
154 }
155
156 const char *
MeleeTeam_getTeamName(const MeleeTeam * team)157 MeleeTeam_getTeamName (const MeleeTeam *team)
158 {
159 return team->name;
160 }
161
162 // Returns true iff the state has actually changed.
163 void
MeleeTeam_setName(MeleeTeam * team,const char * name)164 MeleeTeam_setName (MeleeTeam *team, const char *name)
165 {
166 strncpy (team->name, name, sizeof team->name - 1);
167 team->name[sizeof team->name - 1] = '\0';
168 }
169
170 void
MeleeTeam_copy(MeleeTeam * copy,const MeleeTeam * original)171 MeleeTeam_copy (MeleeTeam *copy, const MeleeTeam *original)
172 {
173 *copy = *original;
174 }
175
176 #if 0
177 bool
178 MeleeTeam_isEqual (const MeleeTeam *team1, const MeleeTeam *team2)
179 {
180 const MeleeShip *fleet1;
181 const MeleeShip *fleet2;
182 FleetShipIndex slotI;
183
184 if (strcmp (team1->name, team2->name) != 0)
185 return false;
186
187 fleet1 = team1->ships;
188 fleet2 = team2->ships;
189
190 for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
191 {
192 if (fleet1[slotI] != fleet2[slotI])
193 return false;
194 }
195
196 return true;
197 }
198 #endif
199
200 ///////////////////////////////////////////////////////////////////////////
201
202 #ifdef NETPLAY
203 static void
MeleeSetup_initSentTeam(MeleeSetup * setup,size_t teamNr)204 MeleeSetup_initSentTeam (MeleeSetup *setup, size_t teamNr)
205 {
206 MeleeTeam *team = &setup->sentTeams[teamNr];
207 FleetShipIndex slotI;
208
209 for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
210 MeleeTeam_setShip (team, slotI, MELEE_UNSET);
211
212 setup->haveSentTeamName[teamNr] = false;
213 #ifdef DEBUG
214 // The actual team name should be irrelevant if haveSentTeamName is
215 // set to false. In a debug build, we set it to invalid, so that
216 // it is more likely that it will be noticed if it is ever used.
217 MeleeTeam_setName (team, "<INVALID>");
218 #endif /* DEBUG */
219 }
220 #endif /* NETPLAY */
221
222 MeleeSetup *
MeleeSetup_new(void)223 MeleeSetup_new (void)
224 {
225 size_t teamI;
226 MeleeSetup *result = HMalloc (sizeof (MeleeSetup));
227 if (result == NULL)
228 return NULL;
229
230 for (teamI = 0; teamI < NUM_SIDES; teamI++)
231 {
232 MeleeTeam_init (&result->teams[teamI]);
233 result->fleetValue[teamI] = 0;
234 #ifdef NETPLAY
235 MeleeSetup_initSentTeam (result, teamI);
236 #endif /* NETPLAY */
237 }
238 return result;
239 }
240
241 void
MeleeSetup_delete(MeleeSetup * setup)242 MeleeSetup_delete (MeleeSetup *setup)
243 {
244 HFree (setup);
245 }
246
247 #ifdef NETPLAY
248 void
MeleeSetup_resetSentTeams(MeleeSetup * setup)249 MeleeSetup_resetSentTeams (MeleeSetup *setup)
250 {
251 size_t teamI;
252
253 for (teamI = 0; teamI < NUM_SIDES; teamI++)
254 MeleeSetup_initSentTeam (setup, teamI);
255 }
256 #endif /* NETPLAY */
257
258 // Returns true iff the state has actually changed.
259 bool
MeleeSetup_setShip(MeleeSetup * setup,size_t teamNr,FleetShipIndex slotNr,MeleeShip ship)260 MeleeSetup_setShip (MeleeSetup *setup, size_t teamNr, FleetShipIndex slotNr,
261 MeleeShip ship)
262 {
263 MeleeTeam *team = &setup->teams[teamNr];
264 MeleeShip oldShip = MeleeTeam_getShip (team, slotNr);
265
266 if (ship == oldShip)
267 return false;
268
269 if (oldShip != MELEE_NONE)
270 setup->fleetValue[teamNr] -= GetShipCostFromIndex (oldShip);
271
272 MeleeTeam_setShip (team, slotNr, ship);
273
274 if (ship != MELEE_NONE)
275 setup->fleetValue[teamNr] += GetShipCostFromIndex (ship);
276
277 return true;
278 }
279
280 MeleeShip
MeleeSetup_getShip(const MeleeSetup * setup,size_t teamNr,FleetShipIndex slotNr)281 MeleeSetup_getShip (const MeleeSetup *setup, size_t teamNr,
282 FleetShipIndex slotNr)
283 {
284 return MeleeTeam_getShip (&setup->teams[teamNr], slotNr);
285 }
286
287 const MeleeShip *
MeleeSetup_getFleet(const MeleeSetup * setup,size_t teamNr)288 MeleeSetup_getFleet (const MeleeSetup *setup, size_t teamNr)
289 {
290 return MeleeTeam_getFleet (&setup->teams[teamNr]);
291 }
292
293 // Returns true iff the state has actually changed.
294 bool
MeleeSetup_setTeamName(MeleeSetup * setup,size_t teamNr,const char * name)295 MeleeSetup_setTeamName (MeleeSetup *setup, size_t teamNr,
296 const char *name)
297 {
298 MeleeTeam *team = &setup->teams[teamNr];
299 const char *oldName = MeleeTeam_getTeamName (team);
300
301 if (strcmp (oldName, name) == 0)
302 return false;
303
304 MeleeTeam_setName (team, name);
305 return true;
306 }
307
308 // NB. This function returns a pointer to a static buffer, which is
309 // overwritten by calls to MeleeSetup_setTeamName().
310 const char *
MeleeSetup_getTeamName(const MeleeSetup * setup,size_t teamNr)311 MeleeSetup_getTeamName (const MeleeSetup *setup, size_t teamNr)
312 {
313 return MeleeTeam_getTeamName (&setup->teams[teamNr]);
314 }
315
316 COUNT
MeleeSetup_getFleetValue(const MeleeSetup * setup,size_t teamNr)317 MeleeSetup_getFleetValue (const MeleeSetup *setup, size_t teamNr)
318 {
319 return setup->fleetValue[teamNr];
320 }
321
322 int
MeleeSetup_deserializeTeam(MeleeSetup * setup,size_t teamNr,uio_Stream * stream)323 MeleeSetup_deserializeTeam (MeleeSetup *setup, size_t teamNr,
324 uio_Stream *stream)
325 {
326 MeleeTeam *team = &setup->teams[teamNr];
327 int ret = MeleeTeam_deserialize (team, stream);
328 if (ret == 0)
329 setup->fleetValue[teamNr] = MeleeTeam_getValue (team);
330 return ret;
331 }
332
333 int
MeleeSetup_serializeTeam(const MeleeSetup * setup,size_t teamNr,uio_Stream * stream)334 MeleeSetup_serializeTeam (const MeleeSetup *setup, size_t teamNr,
335 uio_Stream *stream)
336 {
337 const MeleeTeam *team = &setup->teams[teamNr];
338 return MeleeTeam_serialize (team, stream);
339 }
340
341 #ifdef NETPLAY
342 MeleeShip
MeleeSetup_getSentShip(const MeleeSetup * setup,size_t teamNr,FleetShipIndex slotNr)343 MeleeSetup_getSentShip (const MeleeSetup *setup, size_t teamNr,
344 FleetShipIndex slotNr)
345 {
346 return MeleeTeam_getShip (&setup->sentTeams[teamNr], slotNr);
347 }
348
349 // Returns NULL if there is no team name set. This is not the same
350 // as when an empty (zero-length) team name is set.
351 // NB. This function returns a pointer to a static buffer, which is
352 // overwritten by calls to MeleeSetup_setSentTeamName().
353 const char *
MeleeSetup_getSentTeamName(const MeleeSetup * setup,size_t teamNr)354 MeleeSetup_getSentTeamName (const MeleeSetup *setup, size_t teamNr)
355 {
356 if (!setup->haveSentTeamName[teamNr])
357 return NULL;
358
359 return MeleeTeam_getTeamName (&setup->sentTeams[teamNr]);
360 }
361
362 // Returns true iff the state has actually changed.
363 bool
MeleeSetup_setSentShip(MeleeSetup * setup,size_t teamNr,FleetShipIndex slotNr,MeleeShip ship)364 MeleeSetup_setSentShip (MeleeSetup *setup, size_t teamNr,
365 FleetShipIndex slotNr, MeleeShip ship)
366 {
367 MeleeTeam *team = &setup->sentTeams[teamNr];
368 MeleeShip oldShip = MeleeTeam_getShip (team, slotNr);
369
370 if (ship == oldShip)
371 return false;
372
373 MeleeTeam_setShip (team, slotNr, ship);
374 return true;
375 }
376
377 // Returns true iff the state has actually changed.
378 // 'name' can be NULL to indicate that no team name set. This is not the same
379 // as when an empty (zero-length) team name is set.
380 bool
MeleeSetup_setSentTeamName(MeleeSetup * setup,size_t teamNr,const char * name)381 MeleeSetup_setSentTeamName (MeleeSetup *setup, size_t teamNr,
382 const char *name)
383 {
384 bool haveSentName = setup->haveSentTeamName[teamNr];
385
386 if (name == NULL)
387 {
388 if (!haveSentName)
389 {
390 // Had not sent a team name, and still haven't.
391 return false;
392 }
393
394 #ifdef DEBUG
395 {
396 // The actual team name should be irrelevant if haveSentTeamName
397 // is set to false. In a debug build, we set it to invalid, so
398 // that it is more likely that it will be noticed if it is ever
399 // used.
400 MeleeTeam *team = &setup->sentTeams[teamNr];
401 MeleeTeam_setName (team, "<INVALID>");
402 }
403 #endif
404 }
405 else
406 {
407 MeleeTeam *team = &setup->sentTeams[teamNr];
408
409 if (haveSentName)
410 {
411 // Have sent a team name. Check whether it has actually changed.
412 const char *oldName = MeleeTeam_getTeamName (team);
413 if (strcmp (oldName, name) == 0)
414 return false; // Team name has not changed.
415 }
416
417 MeleeTeam_setName (team, name);
418 }
419
420 setup->haveSentTeamName[teamNr] = (name != NULL);
421
422 return true;
423 }
424
425 #if 0
426 bool
427 MeleeSetup_isTeamSent (MeleeSetup *setup, size_t teamNr)
428 {
429 MeleeTeam *localTeam = &setup->teams[teamNr];
430 MeleeTeam *sentTeam = &setup->sentTeams[teamNr];
431
432 return MeleeTeam_isEqual (localTeam, sentTeam);
433 }
434 #endif
435
436 #endif /* NETPLAY */
437
438 ///////////////////////////////////////////////////////////////////////////
439
440
441