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)
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 ***********************************************************************/
15 #include <fc_config.h>
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. */
41 struct player_list
*plrlist
;
42 struct team_slot
*slot
;
46 struct team_slot
*slots
;
50 /****************************************************************************
51 Initialise all team slots.
52 ****************************************************************************/
53 void team_slots_init(void)
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
61 for (i
= 0; i
< team_slot_count(); i
++) {
62 struct team_slot
*tslot
= team_slots
.slots
+ i
;
65 tslot
->defined_name
= NULL
;
66 tslot
->rule_name
= NULL
;
67 #ifdef FREECIV_ENABLE_NLS
68 tslot
->name_translation
= NULL
;
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
)
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
);
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()) {
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())) {
182 return team_slots
.slots
+ team_id
;
185 /****************************************************************************
186 Does a linear search for a (defined) team name. Returns NULL when none
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
)) {
199 } team_slots_iterate_end
;
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
)
321 fc_assert_ret_val(team_slots_initialised(), NULL
);
324 team_slots_iterate(aslot
) {
325 if (!team_slot_is_used(aslot
)) {
329 } team_slots_iterate_end
;
331 fc_assert_ret_val(NULL
!= tslot
, NULL
);
332 } else if (NULL
!= 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
));
342 /* Set default values. */
343 pteam
->plrlist
= player_list_new();
345 /* Increase number of teams. */
346 team_slots
.used_slots
++;
351 /****************************************************************************
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
));
363 fc_assert(tslot
->team
== pteam
);
365 player_list_destroy(pteam
->plrlist
);
368 team_slots
.used_slots
--;
371 /****************************************************************************
372 Return the current number of teams.
373 ****************************************************************************/
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
)
434 if (NULL
!= pteam
->slot
->defined_name
) {
435 return fc_snprintf(buf
, buf_len
, _("team %s"),
436 team_slot_name_translation(pteam
->slot
));
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
);
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
460 ****************************************************************************/
461 void team_add_player(struct player
*pplayer
, struct team
*pteam
)
463 fc_assert_ret(pplayer
!= 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. */
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
)
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) {
510 pplayer
->team
= NULL
;