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