webperimental: killstack decides stack protects.
[freeciv.git] / common / team.c
blobb63845dbbc5963c01c4f7715b2f4b934fa593f56
1 /***********************************************************************
2 Freeciv - Copyright (C) 2005 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdlib.h>
20 /* utility */
21 #include "fcintl.h"
22 #include "log.h"
23 #include "shared.h"
24 #include "support.h"
26 /* common */
27 #include "game.h"
28 #include "player.h"
29 #include "team.h"
31 struct team_slot {
32 struct team *team;
33 char *defined_name; /* Defined by the ruleset. */
34 char *rule_name; /* Usable untranslated name. */
35 #ifdef FREECIV_ENABLE_NLS
36 char *name_translation; /* Translated name. */
37 #endif
40 struct team {
41 struct player_list *plrlist;
42 struct team_slot *slot;
45 static struct {
46 struct team_slot *slots;
47 int used_slots;
48 } team_slots;
50 /****************************************************************************
51 Initialise all team slots.
52 ****************************************************************************/
53 void team_slots_init(void)
55 int i;
57 /* Init team slots and names. */
58 team_slots.slots = fc_calloc(team_slot_count(), sizeof(*team_slots.slots));
59 /* Can't use the defined functions as the needed data will be
60 * defined here. */
61 for (i = 0; i < team_slot_count(); i++) {
62 struct team_slot *tslot = team_slots.slots + i;
64 tslot->team = NULL;
65 tslot->defined_name = NULL;
66 tslot->rule_name = NULL;
67 #ifdef FREECIV_ENABLE_NLS
68 tslot->name_translation = NULL;
69 #endif
71 team_slots.used_slots = 0;
74 /****************************************************************************
75 Returns TRUE if the team slots have been initialized.
76 ****************************************************************************/
77 bool team_slots_initialised(void)
79 return (team_slots.slots != NULL);
82 /****************************************************************************
83 Remove all team slots.
84 ****************************************************************************/
85 void team_slots_free(void)
87 team_slots_iterate(tslot) {
88 if (NULL != tslot->team) {
89 team_destroy(tslot->team);
91 if (NULL != tslot->defined_name) {
92 free(tslot->defined_name);
94 if (NULL != tslot->rule_name) {
95 free(tslot->rule_name);
97 #ifdef FREECIV_ENABLE_NLS
98 if (NULL != tslot->name_translation) {
99 free(tslot->name_translation);
101 #endif /* FREECIV_ENABLE_NLS */
102 } team_slots_iterate_end;
103 free(team_slots.slots);
104 team_slots.slots = NULL;
106 team_slots.used_slots = 0;
109 /****************************************************************************
110 Returns the total number of team slots (including used slots).
111 ****************************************************************************/
112 int team_slot_count(void)
114 return (MAX_NUM_TEAM_SLOTS);
117 /****************************************************************************
118 Returns the first team slot.
119 ****************************************************************************/
120 struct team_slot *team_slot_first(void)
122 return team_slots.slots;
125 /****************************************************************************
126 Returns the next team slot.
127 ****************************************************************************/
128 struct team_slot *team_slot_next(struct team_slot *tslot)
130 tslot++;
131 return (tslot < team_slots.slots + team_slot_count() ? tslot : NULL);
135 /****************************************************************************
136 Returns the index of the team slots.
137 ****************************************************************************/
138 int team_slot_index(const struct team_slot *tslot)
140 fc_assert_ret_val(team_slots_initialised(), -1);
141 fc_assert_ret_val(tslot != NULL, -1);
143 return tslot - team_slots.slots;
146 /****************************************************************************
147 Returns the team corresponding to the slot. If the slot is not used, it
148 will return NULL. See also team_slot_is_used().
149 ****************************************************************************/
150 struct team *team_slot_get_team(const struct team_slot *tslot)
152 fc_assert_ret_val(team_slots_initialised(), NULL);
153 fc_assert_ret_val(tslot != NULL, NULL);
155 return tslot->team;
158 /****************************************************************************
159 Returns TRUE is this slot is "used" i.e. corresponds to a
160 valid, initialized team that exists in the game.
161 ****************************************************************************/
162 bool team_slot_is_used(const struct team_slot *tslot)
164 /* No team slot available, if the game is not initialised. */
165 if (!team_slots_initialised()) {
166 return FALSE;
169 return NULL != tslot->team;
172 /****************************************************************************
173 Return the possibly unused and uninitialized team slot.
174 ****************************************************************************/
175 struct team_slot *team_slot_by_number(int team_id)
177 if (!team_slots_initialised()
178 || !(0 <= team_id && team_id < team_slot_count())) {
179 return NULL;
182 return team_slots.slots + team_id;
185 /****************************************************************************
186 Does a linear search for a (defined) team name. Returns NULL when none
187 match.
188 ****************************************************************************/
189 struct team_slot *team_slot_by_rule_name(const char *team_name)
191 fc_assert_ret_val(team_name != NULL, NULL);
193 team_slots_iterate(tslot) {
194 const char *tname = team_slot_rule_name(tslot);
196 if (NULL != tname && 0 == fc_strcasecmp(tname, team_name)) {
197 return tslot;
199 } team_slots_iterate_end;
201 return NULL;
204 /****************************************************************************
205 Creates a default name for this team slot.
206 ****************************************************************************/
207 static inline void team_slot_create_default_name(struct team_slot *tslot)
209 char buf[MAX_LEN_NAME];
211 fc_assert(NULL == tslot->defined_name);
212 fc_assert(NULL == tslot->rule_name);
213 #ifdef FREECIV_ENABLE_NLS
214 fc_assert(NULL == tslot->name_translation);
215 #endif /* FREECIV_ENABLE_NLS */
217 fc_snprintf(buf, sizeof(buf), "Team %d", team_slot_index(tslot) + 1);
218 tslot->rule_name = fc_strdup(buf);
220 #ifdef FREECIV_ENABLE_NLS
221 fc_snprintf(buf, sizeof(buf), _("Team %d"), team_slot_index(tslot) + 1);
222 tslot->name_translation = fc_strdup(buf);
223 #endif /* FREECIV_ENABLE_NLS */
225 log_verbose("No name defined for team %d! Creating a default name: %s.",
226 team_slot_index(tslot), tslot->rule_name);
229 /****************************************************************************
230 Returns the name (untranslated) of the slot. Creates a default one if it
231 doesn't exist currently.
232 ****************************************************************************/
233 const char *team_slot_rule_name(const struct team_slot *tslot)
235 fc_assert_ret_val(team_slots_initialised(), NULL);
236 fc_assert_ret_val(NULL != tslot, NULL);
238 if (NULL == tslot->rule_name) {
239 /* Get the team slot as changeable (not _const_) struct. */
240 struct team_slot *changeable
241 = team_slot_by_number(team_slot_index(tslot));
242 team_slot_create_default_name(changeable);
243 return changeable->rule_name;
246 return tslot->rule_name;
249 /****************************************************************************
250 Returns the name (translated) of the slot. Creates a default one if it
251 doesn't exist currently.
252 ****************************************************************************/
253 const char *team_slot_name_translation(const struct team_slot *tslot)
255 #ifdef FREECIV_ENABLE_NLS
256 fc_assert_ret_val(team_slots_initialised(), NULL);
257 fc_assert_ret_val(NULL != tslot, NULL);
259 if (NULL == tslot->name_translation) {
260 /* Get the team slot as changeable (not _const_) struct. */
261 struct team_slot *changeable
262 = team_slot_by_number(team_slot_index(tslot));
263 team_slot_create_default_name(changeable);
264 return changeable->name_translation;
267 return tslot->name_translation;
268 #else /* FREECIV_ENABLE_NLS */
269 return team_slot_rule_name(tslot);
270 #endif /* FREECIV_ENABLE_NLS */
273 /****************************************************************************
274 Returns the name defined in the ruleset for this slot. It may return NULL
275 if the ruleset didn't defined a such name.
276 ****************************************************************************/
277 const char *team_slot_defined_name(const struct team_slot *tslot)
279 fc_assert_ret_val(team_slots_initialised(), NULL);
280 fc_assert_ret_val(NULL != tslot, NULL);
282 return tslot->defined_name;
285 /****************************************************************************
286 Set the name defined in the ruleset for this slot.
287 ****************************************************************************/
288 void team_slot_set_defined_name(struct team_slot *tslot,
289 const char *team_name)
291 fc_assert_ret(team_slots_initialised());
292 fc_assert_ret(NULL != tslot);
293 fc_assert_ret(NULL != team_name);
295 if (NULL != tslot->defined_name) {
296 free(tslot->defined_name);
298 tslot->defined_name = fc_strdup(team_name);
300 if (NULL != tslot->rule_name) {
301 free(tslot->rule_name);
303 tslot->rule_name = fc_strdup(Qn_(team_name));
305 #ifdef FREECIV_ENABLE_NLS
306 if (NULL != tslot->name_translation) {
307 free(tslot->name_translation);
309 tslot->name_translation = fc_strdup(Q_(team_name));
310 #endif /* FREECIV_ENABLE_NLS */
313 /****************************************************************************
314 Creates a new team for the slot. If slot is NULL, it will lookup to a
315 free slot. If the slot already used, then just return the team.
316 ****************************************************************************/
317 struct team *team_new(struct team_slot *tslot)
319 struct team *pteam;
321 fc_assert_ret_val(team_slots_initialised(), NULL);
323 if (NULL == tslot) {
324 team_slots_iterate(aslot) {
325 if (!team_slot_is_used(aslot)) {
326 tslot = aslot;
327 break;
329 } team_slots_iterate_end;
331 fc_assert_ret_val(NULL != tslot, NULL);
332 } else if (NULL != tslot->team) {
333 return tslot->team;
336 /* Now create the team. */
337 log_debug("Create team for slot %d.", team_slot_index(tslot));
338 pteam = fc_calloc(1, sizeof(*pteam));
339 pteam->slot = tslot;
340 tslot->team = pteam;
342 /* Set default values. */
343 pteam->plrlist = player_list_new();
345 /* Increase number of teams. */
346 team_slots.used_slots++;
348 return pteam;
351 /****************************************************************************
352 Destroys a team.
353 ****************************************************************************/
354 void team_destroy(struct team *pteam)
356 struct team_slot *tslot;
358 fc_assert_ret(team_slots_initialised());
359 fc_assert_ret(NULL != pteam);
360 fc_assert(0 == player_list_size(pteam->plrlist));
362 tslot = pteam->slot;
363 fc_assert(tslot->team == pteam);
365 player_list_destroy(pteam->plrlist);
366 free(pteam);
367 tslot->team = NULL;
368 team_slots.used_slots--;
371 /****************************************************************************
372 Return the current number of teams.
373 ****************************************************************************/
374 int team_count(void)
376 return team_slots.used_slots;
379 /****************************************************************************
380 Return the team index.
381 ****************************************************************************/
382 int team_index(const struct team *pteam)
384 return team_number(pteam);
387 /****************************************************************************
388 Return the team index/number/id.
389 ****************************************************************************/
390 int team_number(const struct team *pteam)
392 fc_assert_ret_val(NULL != pteam, -1);
393 return team_slot_index(pteam->slot);
396 /****************************************************************************
397 Return struct team pointer for the given team index.
398 ****************************************************************************/
399 struct team *team_by_number(const int team_id)
401 const struct team_slot *tslot = team_slot_by_number(team_id);
403 return (NULL != tslot ? team_slot_get_team(tslot) : NULL);
406 /****************************************************************************
407 Returns the name (untranslated) of the team.
408 ****************************************************************************/
409 const char *team_rule_name(const struct team *pteam)
411 fc_assert_ret_val(NULL != pteam, NULL);
413 return team_slot_rule_name(pteam->slot);
416 /****************************************************************************
417 Returns the name (translated) of the team.
418 ****************************************************************************/
419 const char *team_name_translation(const struct team *pteam)
421 fc_assert_ret_val(NULL != pteam, NULL);
423 return team_slot_name_translation(pteam->slot);
426 /****************************************************************************
427 Set in 'buf' the name of the team 'pteam' in a format like
428 "team <team_name>". To avoid to see "team Team 0", it only prints the
429 the team number when the name of this team is not defined in the ruleset.
430 ****************************************************************************/
431 int team_pretty_name(const struct team *pteam, char *buf, size_t buf_len)
433 if (NULL != pteam) {
434 if (NULL != pteam->slot->defined_name) {
435 return fc_snprintf(buf, buf_len, _("team %s"),
436 team_slot_name_translation(pteam->slot));
437 } else {
438 return fc_snprintf(buf, buf_len, _("team %d"), team_number(pteam));
442 /* No need to translate, it's an error. */
443 fc_strlcpy(buf, "(null team)", buf_len);
444 return -1;
447 /****************************************************************************
448 Returns the member list of the team.
449 ****************************************************************************/
450 const struct player_list *team_members(const struct team *pteam)
452 fc_assert_ret_val(NULL != pteam, NULL);
454 return pteam->plrlist;
457 /****************************************************************************
458 Set a player to a team. Removes the previous team affiliation if
459 necessary.
460 ****************************************************************************/
461 void team_add_player(struct player *pplayer, struct team *pteam)
463 fc_assert_ret(pplayer != NULL);
465 if (pteam == NULL) {
466 pteam = team_new(NULL);
469 fc_assert_ret(pteam != NULL);
471 if (pteam == pplayer->team) {
472 /* It is the team of the player. */
473 return;
476 log_debug("Adding player %d/%s to team %s.", player_number(pplayer),
477 pplayer->username, team_rule_name(pteam));
479 /* Remove the player from the old team, if any. */
480 team_remove_player(pplayer);
482 /* Put the player on the new team. */
483 pplayer->team = pteam;
484 player_list_append(pteam->plrlist, pplayer);
487 /****************************************************************************
488 Remove the player from the team. This should only be called when deleting
489 a player; since every player must always be on a team.
491 Note in some very rare cases a player may not be on a team. It's safe
492 to call this function anyway.
493 ****************************************************************************/
494 void team_remove_player(struct player *pplayer)
496 struct team *pteam;
498 if (pplayer->team) {
499 pteam = pplayer->team;
501 log_debug("Removing player %d/%s from team %s (%d)",
502 player_number(pplayer), player_name(pplayer),
503 team_rule_name(pteam), player_list_size(pteam->plrlist));
504 player_list_remove(pteam->plrlist, pplayer);
506 if (player_list_size(pteam->plrlist) == 0) {
507 team_destroy(pteam);
510 pplayer->team = NULL;