/* team.c Bygfoot Football Manager -- a small and simple GTK2-based football management game. http://bygfoot.sourceforge.net Copyright (C) 2005 Gyözö Both (gyboth@bygfoot.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cup.h" #include "file.h" #include "finance.h" #include "fixture.h" #include "game.h" #include "game_gui.h" #include "league.h" #include "main.h" #include "maths.h" #include "misc.h" #include "option.h" #include "player.h" #include "strategy.h" #include "team.h" #include "transfer.h" #include "user.h" #include "xml_team.h" /** Generate a team with default values, e.g. random playing structure and an empty string as name. @return A new team. */ Team team_new(gboolean new_id) { Team new; new.name = new.names_file = new.symbol = new.def_file = new.stadium.name = new.strategy_sid = NULL; new.clid = -1; new.id = (new_id) ? team_id_new : -1; new.structure = 442; new.style = 0; new.boost = 0; new.average_talent = 0; new.luck = 1; new.players = g_array_new(FALSE, FALSE, sizeof(Player)); return new; } /* Fill the players array of the team and the stadium. @param tm The team that gets filled. */ void team_generate_players_stadium(Team *tm, gfloat av_talent) { gint i; gfloat skill_factor = math_rnd(1 - const_float("float_team_skill_variance"), 1 + const_float("float_team_skill_variance")); Player new; gfloat wages = 0, average_talent, league_av_talent; gchar *def_file = team_has_def_file(tm); tm->strategy_sid = strategy_get_random(); tm->stadium.average_attendance = tm->stadium.possible_attendance = tm->stadium.games = 0; tm->stadium.safety = math_rnd(const_float("float_team_stadium_safety_lower"), const_float("float_team_stadium_safety_upper")); if(tm->clid < ID_CUP_START) { league_av_talent = (av_talent > 0) ? av_talent : league_from_clid(tm->clid)->average_talent; average_talent = (tm->average_talent == 0) ? skill_factor * league_av_talent : tm->average_talent; } else average_talent = skill_factor * team_get_average_talents(lig(0).teams) * (1 + cup_from_clid(tm->clid)->talent_diff); average_talent = CLAMP(average_talent, 0, const_float("float_player_max_skill")); tm->average_talent = average_talent; if(def_file == NULL) { for(i=0;iplayers, new); } } else { xml_team_read(tm, def_file); g_free(def_file); } for(i=0;iplayers, Player, i).wage; tm->stadium.capacity = math_round_integer((gint)rint((wages / (gfloat)const_int("int_team_stadium_ticket_price")) * const_float("float_team_stadium_size_wage_factor")), 2); } /** Check whether the team is already part of an international cup. We'd like to avoid having Real Madrid both in the Champions' League and in the CWC. @param tm The team we check (by comparing names). @param group The cup group the team shouldn't be in. @return TRUE if the team's already participating in a cup, FALSE otherwise. */ gboolean query_team_is_in_cups(const Team *tm, gint group) { gint i, j; if(group == -1) return FALSE; for(i=0;ilen;i++) if(cp(i).group == group) for(j=0;jlen;j++) if(strcmp(tm->name, (gchar*)g_ptr_array_index(cp(i).team_names, j)) == 0) { if(debug > 90) g_print("team %s group %d found in %s \n", tm->name, group, cp(i).name); return TRUE; } return FALSE; } /** Check whether a team participates in a cup. @param tm The team. @param cup The cup. @return TRUE or FALSE. */ gboolean query_team_is_in_cup(const Team *tm, const Cup *cup) { gint i; for(i=0;iteam_names->len;i++) if(strcmp(tm->name, (gchar*)g_ptr_array_index(cup->team_names, i)) == 0) return TRUE; return FALSE; } /** Return a GPtrArray containing the pointers to the teams from the teams array. @param teams The teams array we use. @return A GPtrArray containing pointers to the teams. */ GPtrArray* team_get_pointers_from_array(const GArray *teams) { gint i; GPtrArray *team_pointers = g_ptr_array_new(); for(i=0;ilen;i++) g_ptr_array_add(team_pointers, (gpointer)&g_array_index(teams, Team, i)); return team_pointers; } /** Return the pointer to the team belonging to the id. */ Team* team_of_id(gint id) { gint i, j; for(i=0;ilen;i++) for(j=0;jlen;j++) if(g_array_index(lig(i).teams, Team, j).id == id) return &g_array_index(lig(i).teams, Team, j); for(i=0;ilen;i++) for(j=0;jlen;j++) if(((Team*)g_ptr_array_index(cp(i).teams, j))->id == id) return (Team*)g_ptr_array_index(cp(i).teams, j); main_exit_program(EXIT_POINTER_NOT_FOUND, "team_of_id: team with id %d not found.", id); return NULL; } /** Return a pointer to the next or last fixture the team participates in. @param tm The team we examine. @return The pointer to the fixture or NULL if none is found. */ Fixture* team_get_fixture(const Team *tm, gboolean last_fixture) { gint i, j; Fixture *fix = NULL; if(!last_fixture && (stat0 == STATUS_LIVE_GAME_PAUSE || stat0 == STATUS_SHOW_LIVE_GAME) && (tm == ((LiveGame*)statp)->fix->teams[0] || tm == ((LiveGame*)statp)->fix->teams[1])) return ((LiveGame*)statp)->fix; if(!last_fixture) { if(tm->clid < ID_CUP_START) for(i=0;ilen;i++) { if(lig(i).active && lig(i).id == tm->clid) { for(j=0;jlen;j++) if(g_array_index(lig(i).fixtures, Fixture, j).attendance == -1 && query_fixture_team_involved((&g_array_index(lig(i).fixtures, Fixture, j)), tm->id)) { fix = &g_array_index(lig(i).fixtures, Fixture, j); break; } break; } } for(i=0;ilen;i++) if(fix == NULL || fix->week_number != week || fix->week_round_number != week_round) { if(query_cup_is_national(acp(i)->id) || query_team_is_in_cup(tm, acp(i))) { for(j=0;jfixtures->len;j++) if(g_array_index(acp(i)->fixtures, Fixture, j).attendance == -1 && query_fixture_team_involved((&g_array_index(acp(i)->fixtures, Fixture, j)), tm->id) && (fix == NULL || query_fixture_is_earlier(&g_array_index(acp(i)->fixtures, Fixture, j), fix))) { fix = &g_array_index(acp(i)->fixtures, Fixture, j); break; } } } } else { if(tm->clid < ID_CUP_START) for(i=0;ilen;i++) { if(lig(i).active && lig(i).id == tm->clid) { for(j=lig(i).fixtures->len - 1;j>=0;j--) if(g_array_index(lig(i).fixtures, Fixture, j).attendance != -1 && query_fixture_team_involved((&g_array_index(lig(i).fixtures, Fixture, j)), tm->id)) { fix = &g_array_index(lig(i).fixtures, Fixture, j); break; } break; } } for(i=0;ilen;i++) if(fix == NULL || fix->week_number != week || fix->week_round_number != week_round - 1) { if(query_cup_is_national(acp(i)->id) || query_team_is_in_cup(tm, acp(i))) { for(j=acp(i)->fixtures->len - 1;j>=0;j--) if(g_array_index(acp(i)->fixtures, Fixture, j).attendance != -1 && query_fixture_team_involved((&g_array_index(acp(i)->fixtures, Fixture, j)), tm->id) && (fix == NULL || query_fixture_is_later(&g_array_index(acp(i)->fixtures, Fixture, j), fix))) { fix = &g_array_index(acp(i)->fixtures, Fixture, j); break; } } } } return fix; } /** Check whether the team is a user-managed team. @param tm The team we examine. @return The user's index in the #users array or -1.*/ gint team_is_user(const Team *tm) { gint i; for(i=0;ilen;i++) if(usr(i).team_id == tm->id) return i; return -1; } /** Check whether the team with given name is a user-managed team. @param team_name The team name we examine. @return The user's index in the #users array or -1.*/ gint team_name_is_user(const gchar *team_name) { gint i; for(i=0;ilen;i++) if(strcmp(team_name, usr(i).tm->name) == 0) return i; return -1; } /** Return the overall average skill or the cskill of the first 11 players. @param tm The team we examine. @param cskill Whether to take into account all players. */ gfloat team_get_average_skill(const Team *tm, gboolean cskill) { gint i, counter = 0; gfloat sum = 0; if(!cskill) { for(i=0;iplayers->len;i++) if(player_of_idx_team(tm, i)->cskill != 0) { sum += player_of_idx_team(tm, i)->skill; counter++; } } else for(i=0;i<11;i++) { sum += (player_get_game_skill(player_of_idx_team(tm, i), FALSE, FALSE)); counter++; } return (counter > 0) ? sum / (gfloat)counter : 0; } /** Return the overall average talent of the team's players. @param tm The team we examine. */ gfloat team_get_average_talent(const Team *tm) { gint i; gfloat sum = 0; for(i=0;iplayers->len;i++) sum += player_of_idx_team(tm, i)->talent; return (tm->players->len > 0) ? sum / (gfloat)tm->players->len : 0; } /** Return the rank of the team in the league tables. */ gint team_get_league_rank(const Team *tm) { gint i, clid = team_get_table_clid(tm), rank = 0; GArray *elements = NULL; if(clid < ID_CUP_START) { if(!league_from_clid(clid)->active) return 0; elements = league_from_clid(tm->clid)->table.elements; } else { rank = team_get_cup_rank( tm, &g_array_index(cup_from_clid(clid)->rounds, CupRound, cup_has_tables(clid)), FALSE); return (rank == -1) ? 0 : rank; } for(i=0;ilen;i++) if(g_array_index(elements, TableElement, i).team_id == tm->id) return i + 1; main_exit_program(EXIT_INT_NOT_FOUND, "team_get_league_rank: no rank found for team %s in league %s. \n", tm->name, league_cup_get_name_string(tm->clid)); return -1; } /** Return the rank of the team in the round robin stage. @param abort Whether to exit if no corresponding entry can be found. */ gint team_get_cup_rank(const Team *tm, const CupRound *cupround, gboolean abort) { gint i, j; for(i=0;itables->len;i++) { for(j=0;jtables, Table, i).elements->len;j++) if(g_array_index(g_array_index(cupround->tables, Table, i).elements, TableElement, j).team_id == tm->id) return j + 1; } if(abort) main_exit_program(EXIT_INT_NOT_FOUND, "team_get_cup_rank: no rank found for team %s. \n ", tm->name); return -1; } /** Return the structure that fits the positions of the first 11 players. @param tm The team we examine. @return A new structure. */ gint team_find_appropriate_structure(const Team *tm) { gint i; gint structure = 0; for(i=0;i<11;i++) if(player_of_idx_team(tm, i)->cskill > 0 && player_of_idx_team(tm, i)->cpos != 0) { if(player_of_idx_team(tm, i)->pos != 0) structure += (gint)rint(powf(10, PLAYER_POS_FORWARD - player_of_idx_team(tm, i)->pos)); else structure += (gint)rint(powf(10, PLAYER_POS_FORWARD - player_of_idx_team(tm, i)->cpos)); } return structure; } /** Change the structure of a team and the appropriate cpos and cskill values. @param tm The team. @param new_structure The new structure value, e.g. 442. */ void team_change_structure(Team *tm, gint new_structure) { gint i; tm->structure = new_structure; for(i=1;i<11;i++) { player_of_idx_team(tm, i)->cpos = player_get_position_from_structure(new_structure, i); player_of_idx_team(tm, i)->cskill = player_get_cskill(player_of_idx_team(tm, i), player_of_idx_team(tm, i)->cpos, TRUE); } } /* Try to set each of the first 11 players on his favoured position and sort the substitutes by position. @param tm The team we rearrange. */ void team_rearrange(Team *tm) { gint i; g_array_sort_with_data(tm->players, (GCompareDataFunc)player_compare_func, GINT_TO_POINTER(100 + PLAYER_COMPARE_ATTRIBUTE_POS)); for(i=0;iplayers->len;i++) { player_of_idx_team(tm, i)->cpos = (i < 11) ? player_get_position_from_structure(tm->structure, i) : player_of_idx_team(tm, i)->pos; if(player_of_idx_team(tm, i)->cskill > 0) player_of_idx_team(tm, i)->cskill = (i < 11) ? player_get_cskill(player_of_idx_team(tm, i), player_of_idx_team(tm, i)->cpos, TRUE) : player_of_idx_team(tm, i)->skill; } } /** Return the name of the current setting of a team attribute, e.g. style. @param tm The team. @param attribute The attribute. */ gchar* team_attribute_to_char(gint attribute, gint value) { switch(attribute) { default: main_exit_program(EXIT_INT_NOT_FOUND, "team_attribute_to_char: unknown attribute %d\n", attribute); break; case TEAM_ATTRIBUTE_STYLE: switch(value) { case -2: return _("ALL OUT DEFEND"); case -1: return _("DEFEND"); case 0: return _("BALANCED"); case 1: return _("ATTACK"); case 2: return _("ALL OUT ATTACK"); } break; case TEAM_ATTRIBUTE_BOOST: switch(value) { case -1: /* Boost value. */ return _("ANTI"); case 0: /* Boost value. */ return _("OFF"); case 1: /* Boost value. */ return _("ON"); } break; } return NULL; } /** Change a team attribute of the current user and print a message. @param attribute The attribute. @param new_value The new value. */ void team_change_attribute_with_message(Team *tm, gint attribute, gint new_value) { switch(attribute) { default: g_warning("team_attribute_to_char: unknown attribute %d\n", attribute); break; case TEAM_ATTRIBUTE_STYLE: current_user.tm->style = new_value; game_gui_print_message(_("Team style changed to %s."), team_attribute_to_char(attribute, new_value)); break; case TEAM_ATTRIBUTE_BOOST: current_user.tm->boost = new_value; if(new_value == 1) game_gui_print_message( _("Boost changed to %s (costs %d per minute)."), team_attribute_to_char(attribute, new_value), (gint)rint(finance_wage_unit(current_user.tm) * const_float("float_boost_cost_factor"))); else game_gui_print_message(_("Boost changed to %s."), team_attribute_to_char(attribute, new_value)); break; } } /** Replace some players by new ones in a team. */ void team_update_cpu_new_players(Team *tm) { gint i; gint number_of_new = math_rndi(const_int("int_team_new_players_lower"), const_int("int_team_new_players_upper")); gint player_numbers[tm->players->len]; math_generate_permutation(player_numbers, 0, tm->players->len - 1); for(i=0;iplayers->len - 1;i>=0;i--) player_update_weekly(&g_array_index(tm->players, Player, i)); if(team_is_user(tm) == -1 && math_rnd(0, 1) < const_float("float_team_new_player_probability")) team_update_cpu_new_players(tm); } /** Regenerate player fitness etc. after a match. @param tm The user team we examine. @param clid The fixture clid. */ void team_update_post_match(Team *tm, const Fixture *fix) { gint i; for(i=0;iplayers->len;i++) player_update_post_match(player_of_idx_team(tm, i), fix); } /** Some updates each round. @param tm The user team we examine. */ void team_update_team_week_roundly(Team *tm) { gint i; for(i=0;iplayers->len;i++) player_update_week_roundly(tm, i); if(team_is_user(tm) == -1) strategy_update_team_pre_match(tm); } /** Return a value from the league table element going with the team. @param type The type of the value. */ gint team_get_table_value(const Team *tm, gint type) { gint i; const GArray *elements = NULL; if(tm->clid >= ID_CUP_START) main_exit_program(EXIT_INT_NOT_FOUND, "team_get_table_value: team is not a league team: %s \n", tm->name); elements = league_from_clid(tm->clid)->table.elements; for(i=0;ilen;i++) if(g_array_index(elements, TableElement, i).team_id == tm->id) break; if(i == elements->len) main_exit_program(EXIT_INT_NOT_FOUND, "team_get_table_value: table entry not found for team %s \n", tm->name); return g_array_index(elements, TableElement, i).values[type]; } /** Compare function for team arrays or pointer arrays. */ gint team_compare_func(gconstpointer a, gconstpointer b, gpointer data) { gint type = GPOINTER_TO_INT(data) % 100; const Team *tm1 = (GPOINTER_TO_INT(data) < 100) ? *(const Team**)a : (const Team*)a; const Team *tm2 = (GPOINTER_TO_INT(data) < 100) ? *(const Team**)b : (const Team*)b; gint return_value = 0; if(type == TEAM_COMPARE_LEAGUE_RANK) { if(tm1->clid == tm2->clid) return_value = misc_int_compare(team_get_league_rank(tm2), team_get_league_rank(tm1)); else return_value = misc_int_compare(league_from_clid(tm2->clid)->layer, league_from_clid(tm1->clid)->layer); } else if(type == TEAM_COMPARE_LEAGUE_LAYER) return_value = (tm1->clid >= ID_CUP_START || tm2->clid >= ID_CUP_START) ? 0 : misc_int_compare(league_from_clid(tm2->clid)->layer, league_from_clid(tm1->clid)->layer); else if(type == TEAM_COMPARE_OFFENSIVE) { gint gf1 = team_get_table_value(tm1, TABLE_GF), gf2 = team_get_table_value(tm2, TABLE_GF), ga1 = team_get_table_value(tm1, TABLE_GA), ga2 = team_get_table_value(tm2, TABLE_GA); if(gf1 > gf2) return_value = -1; else if(gf1 < gf2) return_value = 1; else if(ga1 < ga2) return_value = -1; else if(ga1 > ga2) return_value = 1; else return_value = 0; } else if(type == TEAM_COMPARE_DEFENSE) { gint gf1 = team_get_table_value(tm1, TABLE_GF), gf2 = team_get_table_value(tm2, TABLE_GF), ga1 = team_get_table_value(tm1, TABLE_GA), ga2 = team_get_table_value(tm2, TABLE_GA); if(ga1 > ga2) return_value = 1; else if(ga1 < ga2) return_value = -1; else if(gf1 > gf2) return_value = -1; else if(gf1 < gf2) return_value = 1; else return_value = 0; } else if(type == TEAM_COMPARE_UNSORTED) return_value = 0; else if(type == TEAM_COMPARE_AV_SKILL) return_value = misc_float_compare(team_get_average_skill(tm1, FALSE), team_get_average_skill(tm2, FALSE)); return return_value; } /** Return the teams from all leagues sorted by the specified function. @param type The integer to pass to the compare function. @param cup Whether we return the international cup teams or league teams. */ GPtrArray* team_get_sorted(GCompareDataFunc compare_function, gint type, gboolean cup) { gint i, j; GPtrArray *teams = g_ptr_array_new(); if(!cup) { for(i=0;ilen;i++) for(j=0;jlen;j++) g_ptr_array_add(teams, &g_array_index(lig(i).teams, Team, j)); } else { for(i=0;ilen;i++) for(j=0;jteams->len;j++) g_ptr_array_add(teams, g_ptr_array_index(acp(i)->teams, j)); } g_ptr_array_sort_with_data(teams, compare_function, GINT_TO_POINTER(type)); return teams; } /** Find a new team for a user, depending on whether he's been fired or very successful. */ Team* team_get_new(const Team *tm, gboolean fire) { gint i; gint lower = 0, upper = 0; gint bound1 = (fire) ? const_int("int_team_new_bound_upper") : const_int("int_team_new_bound_lower"), bound2 = (fire) ? const_int("int_team_new_bound_lower") : const_int("int_team_new_bound_upper"); gint idx = -1; GPtrArray *teams = team_get_sorted(team_compare_func, TEAM_COMPARE_LEAGUE_RANK, FALSE); Team *return_value; for(i=0;ilen;i++) if((Team*)g_ptr_array_index(teams, i) != tm) upper++; else { idx = i; break; } for(i=teams->len - 1; i >= 0; i--) if((Team*)g_ptr_array_index(teams, i) != tm) lower++; else break; bound1 = MIN(bound1, upper); bound2 = MIN(bound2, lower); return_value = (Team*)g_ptr_array_index(teams, math_rndi(i - bound1, i + bound2)); while(return_value == tm) return_value = (Team*)g_ptr_array_index(teams, math_rndi(i - bound1, i + bound2)); g_ptr_array_free(teams, TRUE); return return_value; } /** Return the index of the team in the teams array. */ gint team_get_index(const Team *tm) { gint i; gpointer *teams = league_cup_get_teams(tm->clid); if(tm->clid < ID_CUP_START) { for(i=0;i<((GArray*)teams)->len;i++) if(&g_array_index((GArray*)teams, Team, i) == tm) return i; } else { for(i=0;i<((GPtrArray*)teams)->len;i++) if((Team*)g_ptr_array_index((GPtrArray*)teams, i) == tm) return i; } main_exit_program(EXIT_INT_NOT_FOUND, "team_get_index: team %s not found.\n", tm->name); return -1; } /** Return the average of the average talents of the teams in the array. */ gfloat team_get_average_talents(const GArray *teams) { gint i, j, cnt = 0; gfloat sum = 0; if(teams->len == 0) return 0; for(i=0;ilen;i++) for(j=0;jlen;j++) { sum += g_array_index(g_array_index(teams, Team, i).players, Player, j).talent; cnt++; } return sum / (gfloat)cnt; } /** Find out whether a team plays at a given date. */ gboolean query_team_plays(const Team *tm, gint week_number, gint week_round_number) { gint i, j; if(tm->clid < ID_CUP_START) for(i=0;ilen;i++) if(lig(i).id == tm->clid) for(j=0;jlen;j++) if(g_array_index(lig(i).fixtures, Fixture, j).week_number == week_number && g_array_index(lig(i).fixtures, Fixture, j).week_round_number == week_round_number && (g_array_index(lig(i).fixtures, Fixture, j).teams[0] == tm || g_array_index(lig(i).fixtures, Fixture, j).teams[1] == tm)) return TRUE; for(i=0;ilen;i++) if(query_cup_is_national(acp(i)->id) || query_team_is_in_cup(tm, acp(i))) for(j=0;jfixtures->len;j++) if(g_array_index(acp(i)->fixtures, Fixture, j).week_number == week_number && g_array_index(acp(i)->fixtures, Fixture, j).week_round_number == week_round_number && (g_array_index(acp(i)->fixtures, Fixture, j).teams[0] == tm || g_array_index(acp(i)->fixtures, Fixture, j).teams[1] == tm)) return TRUE; return FALSE; } /** Show the results of the user team against the specified team. @param buf The buffer to fill with the results. @param sort Whether to sort the results according to home/away. @param cup_matches Whether to take cup matches into account as well. */ void team_write_own_results(const Team *tm, gchar *buf, gboolean sort, gboolean cup_matches) { gint i, res[2]; gchar buf2[SMALL], buf3[SMALL], buf4[SMALL], neutral[SMALL]; gint place; GPtrArray *matches = fixture_get_matches(current_user.tm, tm); strcpy(buf4, ""); strcpy(neutral, ""); for(i=0;ilen;i++) if(cup_matches || ((Fixture*)g_ptr_array_index(matches, i))->clid < ID_CUP_START) { res[0] = math_sum_int_array(((Fixture*)g_ptr_array_index(matches, i))->result[0], 2); res[1] = math_sum_int_array(((Fixture*)g_ptr_array_index(matches, i))->result[1], 2); if(res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] != current_user.tm] > res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] == current_user.tm]) /* a won match */ sprintf(buf2, _("W %d : %d"), res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] != current_user.tm], res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] == current_user.tm]); else if(res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] != current_user.tm] < res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] == current_user.tm]) /* a lost match */ sprintf(buf2, _("L %d : %d"), res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] != current_user.tm], res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] == current_user.tm]); else /* a drawn match */ sprintf(buf2, _("Dw %d : %d"), res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] != current_user.tm], res[((Fixture*)g_ptr_array_index(matches, i))->teams[0] == current_user.tm]); if(((Fixture*)g_ptr_array_index(matches, i))->home_advantage) { if(((Fixture*)g_ptr_array_index(matches, i))->teams[0] == current_user.tm) { /* a match at home */ sprintf(buf3, _("%s (H) "), buf2); place = 0; } else { /* a match away */ sprintf(buf3, _("%s (A) "), const_app("string_treeview_live_game_commentary_away_bg"), const_app("string_treeview_live_game_commentary_away_fg"), buf2); place = 1; } } else { /* a match on neutral ground */ sprintf(buf3, _("%s (N) "), buf2); place = -1; } if(!sort || place == 1) strcat(buf4, buf3); else { if(place == 0) { strcpy(buf2, buf4); sprintf(buf4, "%s%s", buf3, buf2); } else if(place == -1) strcat(neutral, buf3); } } sprintf(buf, "%s%s", buf4, neutral); g_ptr_array_free(matches, TRUE); } /** Show a row of WDWWLL type results and the goals for and against. @param tm The team we find the results for. @param buf The buffer we print the results into. */ void team_write_results(const Team *tm, gchar *result_buf, gchar *goals_buf) { gint i; GPtrArray *latest_fixtures = fixture_get_latest(tm); gint res[2], goals[2] = {0, 0}; gint end_idx = latest_fixtures->len - const_int("int_treeview_latest_results"); strcpy(result_buf, ""); end_idx = MAX(0, end_idx); for(i=latest_fixtures->len - 1;i>=end_idx;i--) { res[0] = math_sum_int_array(((Fixture*)g_ptr_array_index(latest_fixtures, i))->result[0], 3); res[1] = math_sum_int_array(((Fixture*)g_ptr_array_index(latest_fixtures, i))->result[1], 3); goals[0] += math_sum_int_array(((Fixture*) g_ptr_array_index(latest_fixtures, i))-> result[(((Fixture*)g_ptr_array_index(latest_fixtures, i))->teams[0] != tm)], 2); goals[1] += math_sum_int_array(((Fixture*) g_ptr_array_index(latest_fixtures, i))-> result[(((Fixture*)g_ptr_array_index(latest_fixtures, i))->teams[0] == tm)], 2); if(res[0] == res[1]) /* draw */ strcat(result_buf, _("Dw ")); else if(res[(((Fixture*)g_ptr_array_index(latest_fixtures, i))->teams[0] == tm)] > res[(((Fixture*)g_ptr_array_index(latest_fixtures, i))->teams[0] != tm)]) /* lost */ strcat(result_buf, _("L ")); else /* won */ strcat(result_buf, _("W ")); } sprintf(goals_buf, "%d : %d", goals[0], goals[1]); g_ptr_array_free(latest_fixtures, TRUE); } /** Find out whether the team is in the given pointer array. */ gboolean query_team_is_in_teams_array(const Team *tm, const GPtrArray *teams) { gint i; for(i=0;ilen;i++) if((Team*)g_ptr_array_index(teams, i) == tm) return TRUE; return FALSE; } /** Check whether we find a definition file for the given team. */ gchar* team_has_def_file(const Team *tm) { gchar *return_value = NULL; gchar buf[SMALL]; if(tm->def_file != NULL && opt_int("int_opt_load_defs") != 0) { sprintf(buf, "team_%s.xml", tm->def_file); return_value = file_find_support_file(buf, FALSE); } return return_value; } /** Complete the definition of the team (add players, calculate wages etc. Called after reading a team def file. */ void team_complete_def(Team *tm) { gint i, new_pos, pos_sum; gint positions[4] = {0, 0, 0, 0}; Player new_player; gint add = const_int("int_team_cpu_players") - tm->players->len; gboolean is_user = (team_is_user(tm) != -1); for(i=0;iplayers->len;i++) { player_complete_def(&g_array_index(tm->players, Player, i), tm->average_talent); positions[g_array_index(tm->players, Player, i).pos]++; /** This is so we don't remove loaded players from the team at startup. */ if(is_user) g_array_index(tm->players, Player, i).recovery = 1; } for(i=0;iaverage_talent, TRUE); if(positions[0] < 2) new_pos = 0; else if((gfloat)positions[1] / (gfloat)pos_sum < const_float("float_player_pos_bound1")) new_pos = 1; else if((gfloat)positions[2] / (gfloat)pos_sum < const_float("float_player_pos_bound1")) new_pos = 2; else new_pos = 3; new_player.pos = new_player.cpos = new_pos; positions[new_pos]++; g_array_append_val(tm->players, new_player); } team_complete_def_sort(tm); } /** Sort the players in the team according to the team structure and the player positions. */ void team_complete_def_sort(Team *tm) { gint i, j; gint positions[4] = {0, 0, 0, 0}; gint structure[4] = {1, math_get_place(tm->structure, 3), math_get_place(tm->structure, 2), math_get_place(tm->structure, 1)}; Player player_tmp, player_tmp2; for(i=0;i<11;i++) positions[g_array_index(tm->players, Player, i).pos]++; for(i=0;i<4;i++) { while(positions[i] > structure[i]) { for(j=0;j<11;j++) if(g_array_index(tm->players, Player, j).pos == i) { player_tmp = g_array_index(tm->players, Player, j); g_array_remove_index(tm->players, j); break; } for(j=10;jplayers->len;j++) { if(g_array_index(tm->players, Player, j).pos != i) { player_tmp2 = g_array_index(tm->players, Player, j); g_array_remove_index(tm->players, j); break; } } if(j == tm->players->len) main_exit_program(EXIT_DEF_SORT, "team_complete_def_sort (1): cannot sort according to structure %d (team %s).", tm->structure, tm->name); positions[i]--; positions[player_tmp2.pos]++; g_array_append_val(tm->players, player_tmp); g_array_prepend_val(tm->players, player_tmp2); } while(positions[i] < structure[i]) { for(j=0;j<11;j++) if(g_array_index(tm->players, Player, j).pos > i) { player_tmp = g_array_index(tm->players, Player, j); g_array_remove_index(tm->players, j); break; } if(j == 11) main_exit_program(EXIT_DEF_SORT, "team_complete_def_sort (2): cannot sort according to structure %d (team %s).", tm->structure, tm->name); for(j=10;jplayers->len;j++) if(g_array_index(tm->players, Player, j).pos == i) { player_tmp2 = g_array_index(tm->players, Player, j); g_array_remove_index(tm->players, j); break; } if(j == tm->players->len) main_exit_program(EXIT_DEF_SORT, "team_complete_def_sort (3): cannot sort according to structure %d (team %s).", tm->structure, tm->name); positions[i]++; positions[player_tmp.pos]--; g_array_append_val(tm->players, player_tmp); g_array_prepend_val(tm->players, player_tmp2); } } team_rearrange(tm); } /** Find out which cup or league table the team belongs to. */ gint team_get_table_clid(const Team *tm) { gint i; if(tm->clid >= ID_CUP_START || (tm->clid < ID_CUP_START && !league_from_clid(tm->clid)->active)) { for(i = acps->len - 1; i >= 0; i--) if(cup_has_tables(acp(i)->id) != -1 && query_team_is_in_cup(tm, acp(i))) return acp(i)->id; } return tm->clid; }