/* cup.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 "free.h" #include "fixture.h" #include "league.h" #include "main.h" #include "maths.h" #include "misc.h" #include "option.h" #include "table.h" #include "team.h" #include "variables.h" #include "xml_league.h" /** Create and return a new cup with default values. @return The new cup. @see #Cup */ Cup cup_new(gboolean new_id) { #ifdef DEBUG printf("cup_new\n"); #endif Cup new; new.name = NULL; new.short_name = NULL; new.symbol = NULL; new.sid = NULL; new.id = (new_id) ? cup_id_new : -1; new.group = -1; new.add_week = 0; new.last_week = -1; new.week_gap = 1; new.yellow_red = 1000; new.talent_diff = 0; new.rounds = g_array_new(FALSE, FALSE, sizeof(CupRound)); new.teams = g_ptr_array_new(); new.team_names = g_ptr_array_new(); new.fixtures = g_array_new(FALSE, FALSE, sizeof(Fixture)); new.week_breaks = g_array_new(FALSE, FALSE, sizeof(WeekBreak)); new.skip_weeks_with = g_ptr_array_new(); new.bye = g_ptr_array_new(); new.properties = g_ptr_array_new(); new.next_fixture_update_week = -1; new.next_fixture_update_week_round = -1; return new; } /** Return a CupChooseTeam with default values. */ CupChooseTeam cup_choose_team_new(void) { #ifdef DEBUG printf("cup_choose_team_new\n"); #endif #ifdef DEBUG printf("cup_choose_team_new\n"); #endif CupChooseTeam new; new.sid = NULL; new.number_of_teams = -1; new.start_idx = new.end_idx = -1; new.randomly = FALSE; new.generate = FALSE; new.skip_group_check = FALSE; new.from_table = 0; new.preload = TRUE; new.optional = FALSE; new.next = NULL; return new; } /** Return a CupRound with default values. */ CupRound cup_round_new(void) { #ifdef DEBUG printf("cup_round_new\n"); #endif CupRound new; new.name = NULL; new.new_teams = 0; new.byes = -1; new.home_away = TRUE; new.replay = 0; new.neutral = FALSE; new.randomise_teams = TRUE; new.delay = 0; new.round_robin_number_of_groups = 0; new.round_robin_number_of_advance = 0; new.round_robin_number_of_best_advance = 0; new.round_robins = 2; new.rr_breaks = g_array_new(FALSE, FALSE, sizeof(gint)); new.two_match_weeks[0] = g_array_new(FALSE, FALSE, sizeof(gint)); new.two_match_weeks[1] = g_array_new(FALSE, FALSE, sizeof(gint)); new.two_match_week = FALSE; new.tables = g_array_new(FALSE, FALSE, sizeof(Table)); new.choose_teams = g_array_new(FALSE, FALSE, sizeof(CupChooseTeam)); new.waits = g_array_new(FALSE, FALSE, sizeof(CupRoundWait)); new.team_ptrs = g_ptr_array_new(); return new; } /** Reset some arrays at the beginning of a new season. */ void cup_reset(Cup *cup) { #ifdef DEBUG printf("cup_reset\n"); #endif gint i; free_gchar_array(&cup->team_names); cup->team_names = g_ptr_array_new(); if(cup->teams->len > 0) { g_ptr_array_free(cup->teams, TRUE); cup->teams = g_ptr_array_new(); } g_array_free(cup->fixtures, TRUE); cup->fixtures = g_array_new(FALSE, FALSE, sizeof(Fixture)); free_g_ptr_array(&cup->bye); for(i=0;irounds->len;i++) { CupRound *cup_round = &g_array_index(cup->rounds, CupRound, i); if(cup_round->tables->len > 0) { free_tables(&cup_round->tables); cup_round->tables = g_array_new(FALSE, FALSE, sizeof(Table)); } g_ptr_array_free(cup_round->team_ptrs, TRUE); cup_round->team_ptrs = g_ptr_array_new(); } } /** Find out whether a choose_team definition refers to a league in the country. If so, no teams get loaded for that choose_team. */ gboolean query_cup_choose_team_is_league(const gchar *sid) { #ifdef DEBUG printf("query_cup_choose_team_is_league\n"); #endif gint i; for(i=0;ilen;i++) if(strcmp(lig(i).sid, sid) == 0) return TRUE; return FALSE; } /** @return TRUE if the team(s) referenced by \p sid need to be * generated. */ static gboolean cup_choose_team_should_generate(const CupChooseTeam *ct) { if (g_str_has_prefix(ct->sid, "LEAGUE") || g_str_has_prefix(ct->sid, "CUP")) return FALSE; return !country_get_league_sid(&country, ct->sid) && !country_get_cup_sid(&country, ct->sid); } /** Write the cup or league of the chooseteam into the appropriate pointer and return TRUE; return FALSE if no cup/league is found. */ void cup_get_choose_team_league_cup(const CupChooseTeam *ct, const League **league, const Cup **cup) { #ifdef DEBUG printf("cup_get_choose_team_league_cup\n"); #endif gint i, idx; gchar trash[SMALL]; gchar prefix[SMALL]; *league = NULL; *cup = NULL; sscanf(ct->sid, "%[^0-9]%d", trash, &idx); if(g_str_has_prefix(ct->sid, "LEAGUE") && idx >=0 && idx <= ligs->len) { *league = &lig(idx - 1); *cup = NULL; } else if(g_str_has_prefix(ct->sid, "CUP") && idx >=0 && idx <= cps->len) { *cup = &cp(idx - 1); *league = NULL; } else { if(g_str_has_suffix(ct->sid, "*")) g_utf8_strncpy(prefix, ct->sid, g_utf8_strlen(ct->sid, -1) - 1); else strcpy(prefix, "NONAME"); for(i=0;ilen;i++) { if(strcmp(lig(i).sid, ct->sid) == 0 || g_str_has_prefix(lig(i).sid, prefix)) { *league = &lig(i); *cup = NULL; break; } } for(i=0;ilen;i++) { if(strcmp(cp(i).sid, ct->sid) == 0 || g_str_has_prefix(cp(i).sid, prefix)) { *cup = &cp(i); *league = NULL; break; } } } if(*league == NULL && *cup == NULL) main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_get_choose_team_league_cup: no league nor cup found for chooseteam %s", ct->sid); if(debug > 100) { if(*league == NULL) printf("cup_get_choose_team_league_cup: sid %s cup %s\n", ct->sid, (*cup)->name); else printf("cup_get_choose_team_league_cup: sid %s league %s\n", ct->sid, (*league)->name); } } /** Load the pointers to the teams participating in the cup round. If necessary, teams are generated and stored in the teams array of the cup round. */ void cup_get_team_pointers(Cup *cup, gint round, GPtrArray *teams_sorted, gboolean preload) { #ifdef DEBUG printf("cup_get_team_pointers\n"); #endif gint i, existing_teams; CupRound *cup_round = &g_array_index(cup->rounds, CupRound, round); GPtrArray *teams = cup_round->team_ptrs; if(debug > 60) g_print("cup_get_team_pointers %s round %d\n", cup->name, round); existing_teams = cup_round->team_ptrs->len; for(i=0;ichoose_teams->len;i++) { const CupChooseTeam *choose_team = &g_array_index(cup_round->choose_teams, CupChooseTeam, i); if(choose_team->preload == preload) { if(cup_choose_team_should_generate(choose_team)) cup_load_choose_team_generate(cup, cup_round, choose_team); else cup_load_choose_team(cup, teams, teams_sorted, choose_team); } } for(i=existing_teams;iteam_ptrs->len;i++) { Team *team = g_ptr_array_index(cup_round->team_ptrs, i); g_ptr_array_add(cup->teams, team); } country_lookup_first_team_ids(&country); if(debug > 70) for(i=0;ilen;i++) g_print("cup_get_team_pointers: %s (%s) round %d team %d %s (clid %d)\n", cup->name, cup->sid, round, i, ((Team*)g_ptr_array_index(teams, i))->name, ((Team*)g_ptr_array_index(teams, i))->clid); } /** Get the pointers to the teams (already generated, in one of the leagues or cups) specified in the chooseteam. Add them to the 'teams' pointer array. */ void cup_load_choose_team(Cup *cup, GPtrArray *teams, GPtrArray *teams_sorted, const CupChooseTeam *ct) { #ifdef DEBUG printf("cup_load_choose_team\n"); #endif gint i; gint debug_num = teams->len; const League *league = NULL; const Cup *cup_temp = NULL; if(debug > 60) g_print("cup_load_choose_team: %s, %s, teams %d to %d, random: %d \n", cup->name, ct->sid, ct->start_idx, ct->end_idx, ct->randomly); cup_get_choose_team_league_cup(ct, &league, &cup_temp); if(cup_temp == NULL) cup_load_choose_team_from_league(cup, league, teams, ct); else cup_load_choose_team_from_cup(cup, cup_temp, teams, teams_sorted, ct); if(debug > 80) for(i=debug_num;ilen;i++) g_print("cup_load_choose_team: %d %s \n", i, ((Team*)g_ptr_array_index(teams, i))->name); } void cup_load_choose_team_from_cup(Cup *cup, const Cup *cup_temp, GPtrArray *teams, GPtrArray *teams_sorted, const CupChooseTeam *ct) { #ifdef DEBUG printf("cup_load_choose_team_from_cup\n"); #endif gint i; gint start, end; gint number_of_teams; GPtrArray *cup_teams_sorted; number_of_teams = 0; cup_teams_sorted = NULL; if(season == 1 && week == 1 && cup->add_week == 0) { if(lig(0).teams->len < ct->number_of_teams) main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_load_choose_team_from_cup: not enough teams in league 0 for chooseteam %s (%d; required: %d) in cup %s\n", ct->sid, lig(0).teams->len, ct->number_of_teams, cup->name); gint permutation[lig(0).teams->len]; math_generate_permutation(permutation, 0, lig(0).teams->len - 1); for(i = ct->start_idx - 1; i <= ct->end_idx - 1; i++) { if(ct->skip_group_check || !query_team_is_in_cups( &g_array_index(lig(0).teams, Team, permutation[i - ct->start_idx + 1]), cup->group)) { g_ptr_array_add(teams, &g_array_index(lig(0).teams, Team, permutation[i - ct->start_idx + 1])); g_ptr_array_add(cup->team_names, g_strdup(g_array_index(lig(0).teams, Team, permutation[i - ct->start_idx + 1]).name)); number_of_teams++; } if(number_of_teams == ct->number_of_teams) break; } if(number_of_teams != ct->number_of_teams) { if (ct->next) return cup_load_choose_team(cup, teams, teams_sorted, ct->next); main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_load_choose_team_from_cup (2): not enough teams found in league 0 for chooseteam %s (%d; required: %d) in cup %s (group %d)\n", ct->sid, number_of_teams, ct->number_of_teams, cup->name, cup->group); } } else { /* Self-referential cup or no? */ cup_teams_sorted = (cup == cup_temp) ? teams_sorted : cup_get_teams_sorted(cup_temp); if(ct->number_of_teams == -1) { start = 0; end = cup_teams_sorted->len; } else { start = ct->start_idx - 1; end = ct->end_idx; } for(i = start; i < end; i++) { if(ct->skip_group_check || !query_team_is_in_cups( (Team*)g_ptr_array_index(cup_teams_sorted, i), cup->group)) { g_ptr_array_add(teams, g_ptr_array_index(cup_teams_sorted, i)); g_ptr_array_add(cup->team_names, g_strdup(((Team*)g_ptr_array_index(cup_teams_sorted, i))->name)); number_of_teams++; if(number_of_teams == ct->number_of_teams) break; } } if(cup != cup_temp) g_ptr_array_free(cup_teams_sorted, TRUE); if(ct->number_of_teams != -1 && number_of_teams != ct->number_of_teams) { if (ct->next) return cup_load_choose_team(cup, teams, teams_sorted, ct->next); main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_load_choose_team_from_cup (3): not enough teams (that don't participate in international cups yet) found in chooseteam %s for cup %s (%d specified, %d found) cup group %d.\n ", ct->sid, cup->name, ct->number_of_teams, number_of_teams, cup->group); } } } void cup_load_choose_team_from_league(Cup *cup, const League *league, GPtrArray *teams, const CupChooseTeam *ct) { #ifdef DEBUG printf("cup_load_choose_team_from_league\n"); #endif gint start, end; gint number_of_teams; gint j; Table *table; number_of_teams = 0; if(league->tables->len == 0) table = &g_array_index(league->tables, Table, 0); else table = &g_array_index(league->tables, Table, ct->from_table); if(ct->number_of_teams == -1) { for(j=0;jelements->len;j++) { Team *team = team_of_id( g_array_index(table->elements, TableElement, j).team_id); if (team_is_reserve_team(team) && !query_league_cup_has_property(cup->id, "include_reserve_teams")) continue; g_ptr_array_add(teams, team); g_ptr_array_add(cup->team_names, g_strdup(team->name)); } } else { start = ct->start_idx - 1; end = ct->end_idx - start; gint order[end]; for(j=0;jrandomly) math_generate_permutation(order, start, start + end - 1); for(j = 0; j < end; j++) { Team *team = team_of_id(g_array_index(table->elements, TableElement, order[j]).team_id); if (team_is_reserve_team(team) && !query_league_cup_has_property(cup->id, "include_reserve_teams")) continue; if(debug > 80) g_print("j %d order %d team %s isinint %d numteams %d\n", j, order[j], team_of_id(g_array_index(table->elements, TableElement, order[j]).team_id)->name, query_team_is_in_cups( team_of_id(g_array_index(table->elements, TableElement, order[j]).team_id), cup->group), number_of_teams); if(ct->skip_group_check || !query_team_is_in_cups(team, cup->group)) { g_ptr_array_add(teams, team); g_ptr_array_add(cup->team_names, g_strdup(team->name)); number_of_teams++; if(number_of_teams == ct->number_of_teams) break; } } } if(ct->number_of_teams != -1 && number_of_teams != ct->number_of_teams) main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_load_choose_team_from_league (1): not enough teams (that don't participate in international cups yet) found in chooseteam %s for cup %s (%d specified, %d found) cup group %d.\n ", ct->sid, cup->name, ct->number_of_teams, number_of_teams, cup->group); } /** This function is used when a CupChooseTeam object references a cup * that is outside of the users's league. It returns a list of teamas * that would participate in this cup. This is a best effort * function and the goal is to just get enough teams to satisfy the * requirements of the CupChooseTeam object, so it may omit some * teams especially if the cup definition is complex. */ static void cup_generate_team_list(const Cup *cup, GPtrArray *teams, gboolean league_talents) { int i; const League *top_league = NULL; for (i = 0; i < cup->rounds->len; i++) { const CupRound *round = &g_array_index(cup->rounds, CupRound, i); int j; for (j = 0; j < round->choose_teams->len; j++) { const CupChooseTeam *ct = &g_array_index(round->choose_teams, CupChooseTeam, j); const League *league = bygfoot_get_league_sid(ct->sid); if (!league) continue; if (!top_league || (league->layer < top_league->layer)) top_league = league; if (league->layer == 1) break; } } if (!top_league) return; for (i = 0; i < top_league->teams->len; i++) { Team *team = &g_array_index(top_league->teams, Team, i); if (league_talents) team->average_talent = top_league->average_talent; g_ptr_array_add(teams, team); } } /** Load the teams specified in the chooseteam from a non-country league. */ void cup_load_choose_team_generate(Cup *cup, CupRound *cup_round, const CupChooseTeam *ct) { #ifdef DEBUG printf("cup_load_choose_team_generate\n"); #endif gint j, k; gint number_of_teams, end_idx = -1; GPtrArray *teams_local = NULL; GPtrArray *sids = NULL; if(debug > 60) g_print("cup_load_choose_team_generate: %s, (%s) %s \n", cup->name, cup->sid, ct->sid); teams_local = g_ptr_array_new(); sids = misc_randomise_g_pointer_array(misc_separate_strings(ct->sid)); for(j=0;jlen;j++) { const gchar *sid = g_ptr_array_index(sids, j); Cup *generate_cup = bygfoot_get_cup_sid(sid); if (generate_cup) { cup_generate_team_list(generate_cup, teams_local, query_league_cup_has_property(cup->id, "league_talents")); continue; } if(!query_cup_choose_team_is_league(sid)) { const League *league = bygfoot_get_league_sid(sid); if (!league) { g_warning("Cup: %s choose_team_sid %s not found.", cup->sid, sid); continue; } for(k=0; k < league->teams->len; k++) { Team *team = &g_array_index(league->teams, Team, k); if(query_league_cup_has_property(cup->id, "league_talents")) { team->average_talent = league->average_talent; } g_ptr_array_add(teams_local, team); } } } free_gchar_array(&sids); /** No teams found. */ if(teams_local->len == 0) { g_ptr_array_free(teams_local, TRUE); return; } gint permutation[teams_local->len]; for(j=0;jlen;j++) permutation[j] = j; if(ct->randomly && teams_local->len > 0) { if(ct->start_idx == -1) math_generate_permutation(permutation, 0, teams_local->len - 1); else math_generate_permutation(permutation, ct->start_idx - 1, ct->end_idx - 1); } else { /* I'm doing this in the else here to avoid breaking other code * paths, since I don't really understand well enough what they * are doing. */ for (j = 0; j < teams_local->len; j++) { permutation[j] = ct->start_idx + j - 1; } } number_of_teams = 0; if(ct->start_idx == -1) end_idx = teams_local->len; else end_idx = ct->end_idx - ct->start_idx + 1; if(teams_local->len < end_idx) { main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_load_choose_team_generate: not enough teams (%d) in chooseteam %s in cup %s (%d are specified) \n", teams_local->len, ct->sid, cup->name, end_idx); } for(j = 0; j < end_idx; j++) { Team *team = g_ptr_array_index(teams_local, permutation[j]); if(ct->skip_group_check || !query_team_is_in_cups(team, cup->group)) { //g_array_append_val(cup_round->teams, g_array_index(teams_local, Team, permutation[j])); //g_array_index(cup_round->teams, Team, cup_round->teams->len - 1).clid = cup->id; team->clid = cup->id; g_ptr_array_add(cup->team_names, g_strdup(team->name)); g_ptr_array_add(cup_round->team_ptrs, team); number_of_teams++; } if(number_of_teams == ct->number_of_teams) break; } if(((ct->number_of_teams != -1 && number_of_teams != ct->number_of_teams) || (ct->number_of_teams == -1 && number_of_teams != teams_local->len)) && teams_local->len > 0) { /* TODO: handle number_of_teams > 0 */ g_ptr_array_free(teams_local, TRUE); if (ct->next) return cup_load_choose_team_generate(cup, cup_round, ct->next); if (ct->optional) return; main_exit_program(EXIT_CHOOSE_TEAM_ERROR, "cup_load_choose_team_generate: not enough teams (that don't participate in international cups yet) found in chooseteam %s for cup %s (%d specified, %d found).\n ", ct->sid, cup->name, ct->number_of_teams, number_of_teams); } g_ptr_array_free(teams_local, teams_local->len > 0); } /** Return a pointer array of teams ordered corresponding to their success in the cup. A bit tricky because we have to fetch the team pointers corresponding to their name because the team pointers in the fixtures are partially invalid because of promotion relegation. */ GPtrArray* cup_get_teams_sorted(const Cup *cup) { #ifdef DEBUG printf("cup_get_teams_sorted\n"); #endif gint i, j; GPtrArray *teams = g_ptr_array_new(); GArray *team_ids = g_array_new(FALSE, FALSE, sizeof(gint)); for(i=0;ifixtures->len;i++) for(j=0;j<2;j++) if(!query_misc_integer_is_in_g_array( g_array_index(cup->fixtures, Fixture, i).team_ids[j], team_ids)) { g_array_append_val(team_ids, g_array_index(cup->fixtures, Fixture, i).team_ids[j]); g_ptr_array_add(teams, team_of_id(g_array_index(cup->fixtures, Fixture, i).team_ids[j])); } g_ptr_array_sort_with_data(teams, cup_compare_success, (gpointer)cup); g_array_free(team_ids, TRUE); return teams; } /** Compare two teams in a pointer array taking into account their success in a cup. */ gint cup_compare_success(gconstpointer a, gconstpointer b, gpointer data) { #ifdef DEBUG printf("cup_compare_success\n"); #endif const Cup *cup = (const Cup*)data; const CupRound *cupround = NULL; const GArray *fixtures = cup->fixtures; const Team *team1 = *(const Team**)a; const Team *team2 = *(const Team**)b; gint round_reached1 = cup_get_round_reached(team1, fixtures), round_reached2 = cup_get_round_reached(team2, fixtures); gint return_value = 0; if(team1 == team2) return_value = 0; else if(round_reached1 < round_reached2) return_value = 1; else if(round_reached1 > round_reached2) return_value = -1; else { cupround = &g_array_index(cup->rounds, CupRound, round_reached1); if(cupround->tables->len > 0) return_value = cup_compare_success_tables(team1, team2, cup, round_reached1); else return_value = cup_compare_success_knockout(team1, team2, cup->fixtures); } return return_value; } /** Compare two teams that reached the same knockout round. */ gint cup_compare_success_knockout(const Team *tm1, const Team *tm2, const GArray *fixtures) { #ifdef DEBUG printf("cup_compare_success_knockout\n"); #endif gint i; gint winner1 = -1, winner2 = -1; gint return_value = 0; for(i=fixtures->len - 1; i>=0; i--) { if(winner1 == -1 && query_fixture_team_involved((&g_array_index(fixtures, Fixture, i)), tm1->id)) winner1 = GPOINTER_TO_INT( fixture_winner_of(&g_array_index(fixtures, Fixture, i), TRUE)); if(winner2 == -1 && query_fixture_team_involved((&g_array_index(fixtures, Fixture, i)), tm2->id)) winner2 = GPOINTER_TO_INT( fixture_winner_of(&g_array_index(fixtures, Fixture, i), TRUE)); if(winner1 != -1 && winner2 != -1) break; } if(winner1 == tm1->id && winner2 != tm2->id) return_value = -1; else if(winner1 != tm1->id && winner2 == tm2->id) return_value = 1; return return_value; } /** Compare two teams in cup tables. */ gint cup_compare_success_tables(const Team *tm1, const Team *tm2, const Cup *cup, gint round) { #ifdef DEBUG printf("cup_compare_success_tables\n"); #endif gint i, j; gint return_value = 0; const CupRound *cupround = &g_array_index(cup->rounds, CupRound, round); const TableElement *elem1 = NULL, *elem2 = NULL; if(team_get_cup_rank(tm1, cupround, TRUE) > team_get_cup_rank(tm2, cupround, TRUE)) return_value = 1; else if(team_get_cup_rank(tm1, cupround, TRUE) < team_get_cup_rank(tm2, cupround, TRUE)) return_value = -1; else { 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 == tm1->id) elem1 = &g_array_index(g_array_index(cupround->tables, Table, i).elements, TableElement, j); else if(g_array_index(g_array_index(cupround->tables, Table, i).elements, TableElement, j).team_id == tm2->id) elem2 = &g_array_index(g_array_index(cupround->tables, Table, i).elements, TableElement, j); return_value = table_element_compare_func(elem1, elem2, GINT_TO_POINTER(cup->id)); } return return_value; } /** Return the cup round that the team reached in the cup. @param fixtures The fixtures array of the cup. */ gint cup_get_round_reached(const Team *tm, const GArray *fixtures) { #ifdef DEBUG printf("cup_get_round_reached\n"); #endif gint round = -1; gint i; for(i=0;ilen;i++) if(g_array_index(fixtures, Fixture, i).team_ids[0] == tm->id || g_array_index(fixtures, Fixture, i).team_ids[1] == tm->id) round = MAX(round, g_array_index(fixtures, Fixture, i).round); return round; } /** Calculate the week number the first matchday of the given cup round takes place. @param cup The cup we examine. @param cup_round The index of the cup round in the cup.rounds array. @return A week number. */ gint cup_get_first_week_of_cup_round(Cup *cup, gint cup_round, gboolean with_delay) { #ifdef DEBUG printf("cup_get_first_week_of_cup_round\n"); #endif gint week_number; if(cup_round == cup->rounds->len - 1) week_number = cup->last_week - (cup_get_matchdays_in_cup_round(cup, cup_round) - 1) * cup->week_gap; else week_number = cup_get_first_week_of_cup_round(cup, cup_round + 1, FALSE) - cup_get_matchdays_in_cup_round(cup, cup_round) * cup->week_gap; if(with_delay) week_number += g_array_index(cup->rounds, CupRound, cup_round).delay; if(week_number <= 0) { debug_print_message("cup_get_first_week_of_cup_round: First week of cup %s, cup round %d is not positive (%d). Please correct the cup definition file!!!\n", cup->name, cup_round, week_number); if(cup->week_gap > 1) { cup->week_gap--; debug_print_message("Lowering week gap to %d and trying again.\n", cup->week_gap); } else { cup->last_week++; debug_print_message("Increasing last week to %d and trying again.\n", cup->last_week); } return cup_get_first_week_of_cup_round(cup, cup_round, with_delay); } return week_number; } /** Calculate the last week of a cup if we only know the first week. */ gint cup_get_last_week_from_first(const Cup *cup, gint first_week) { #ifdef DEBUG printf("cup_get_last_week_from_first\n"); #endif gint i; gint matchdays = 0; for(i=0;irounds->len;i++) matchdays += cup_get_matchdays_in_cup_round(cup, i); return first_week + (matchdays - 1) * cup->week_gap; } /** Return the number of matchdays for a given cup round. @param cup The cup we examine. @param cup_round The index of the cup round. @return The number of matchdays, mostly 1 or 2. */ gint cup_get_matchdays_in_cup_round(const Cup *cup, gint round) { #ifdef DEBUG printf("cup_get_matchdays_in_cup_round\n"); #endif gint i; const CupRound *cup_round = &g_array_index(cup->rounds, CupRound, round); gint number_of_teams = -1; gint number_of_matchdays = -1; gint diff; if(cup_round->round_robin_number_of_groups > 0) { number_of_teams = cup_round_get_number_of_teams(cup, round); number_of_teams += cup_round->round_robin_number_of_groups - 1; number_of_teams /= cup_round->round_robin_number_of_groups; /* Now, number_of_teams = number of teams in largest group */ if (number_of_teams % 2 == 0) number_of_matchdays = number_of_teams - 1; else number_of_matchdays = number_of_teams; number_of_matchdays *= cup_round->round_robins; for(i=0;itwo_match_weeks[0]->len;i++) { diff = g_array_index(cup_round->two_match_weeks[1], gint, i) - g_array_index(cup_round->two_match_weeks[0], gint, i); number_of_matchdays -= ((diff + diff % 2) / 2); } } else if(cup_round->home_away) number_of_matchdays = 2 - cup_round->two_match_week; else number_of_matchdays = 1; return number_of_matchdays; } /** Return the number of teams playing in the given cup round. @param cup The cup we examine. @param cup_round The index of the cup round. @return The number teams in the round. */ gint cup_round_get_number_of_teams(const Cup *cup, gint round) { #ifdef DEBUG printf("cup_round_get_number_of_teams\n"); #endif const CupRound *cup_round = &g_array_index(cup->rounds, CupRound, round); gint number_of_teams = 0; if(round == 0) number_of_teams = cup_round_get_new_teams(cup_round); else if(g_array_index(cup->rounds, CupRound, round - 1).round_robin_number_of_groups > 0) { number_of_teams = (g_array_index(cup->rounds, CupRound, round - 1).round_robin_number_of_groups * g_array_index(cup->rounds, CupRound, round - 1).round_robin_number_of_advance) + g_array_index(cup->rounds, CupRound, round - 1).round_robin_number_of_best_advance + cup_round_get_new_teams(cup_round) + cup_round_get_byes(cup, round - 1); } else number_of_teams = cup_round_get_number_of_teams(cup, round - 1) / 2 + cup_round_get_new_teams(cup_round) + cup_round_get_byes(cup, round - 1); return number_of_teams; } /** Get the number of byes in the given cup round. */ gint cup_round_get_byes(const Cup *cup, gint round) { #ifdef DEBUG printf("cup_round_get_byes\n"); #endif const CupRound *cup_round = &g_array_index(cup->rounds, CupRound, round); gint number_of_byes = 0, new_teams = 0; if(cup_round->byes != -1) number_of_byes = cup_round->byes; else { if(round == 0) new_teams = cup_round_get_new_teams(cup_round); else new_teams = cup_round_get_number_of_teams(cup, round); number_of_byes = (cup_round->round_robin_number_of_groups == 0) ? math_get_bye_len(new_teams) : 0; /* if(cup_round->round_robin_number_of_groups == 0) */ /* number_of_byes = math_get_bye_len(new_teams); */ /* else */ /* { */ /* while(new_teams % cup_round->round_robin_number_of_groups != 0) */ /* { */ /* new_teams--; */ /* number_of_byes++; */ /* } */ /* } */ } return number_of_byes; } /** Return the number of new teams that come into the cup in the given cup round. */ gint cup_round_get_new_teams(const CupRound *cup_round) { #ifdef DEBUG printf("cup_round_get_new_teams\n"); #endif gint i, new_teams = 0; const Cup *cup_temp = NULL; const League *league = NULL; GPtrArray *teams_sorted = NULL; if(cup_round->new_teams != 0) new_teams = cup_round->new_teams; else { for(i=0;ichoose_teams->len;i++) { if(g_array_index(cup_round->choose_teams, CupChooseTeam, i). number_of_teams != -1) new_teams += g_array_index(cup_round->choose_teams, CupChooseTeam, i). number_of_teams; else { cup_get_choose_team_league_cup( &g_array_index(cup_round->choose_teams, CupChooseTeam, i), &league, &cup_temp); if(cup_temp == NULL) new_teams += league->teams->len; else { teams_sorted = cup_get_teams_sorted(cup_temp); new_teams += teams_sorted->len; g_ptr_array_free(teams_sorted, TRUE); } } } } return new_teams; } /** Return the cup pointer belonging to the id. @param clid The id we look for. @return The cup pointer or NULL if failed. */ Cup* cup_from_clid(gint clid) { #ifdef DEBUG printf("cup_from_clid\n"); #endif gint i; for(i=0;ilen;i++) if(cp(i).id == clid) return &cp(i); main_exit_program(EXIT_POINTER_NOT_FOUND, "cup_from_clid: didn't find cup with id %d\n", clid); return NULL; } /** Find the cup with the given sid. */ Cup* cup_from_sid(const gchar *sid) { #ifdef DEBUG printf("cup_from_sid\n"); #endif gint i; for(i=0;ilen;i++) if(strcmp(cp(i).sid, sid) == 0) return &cp(i); main_exit_program(EXIT_POINTER_NOT_FOUND, "cup_from_sid: didn't find cup with sid %s \n", sid); return NULL; } /** Return a standard cup round name. */ void cup_get_round_name(const Cup *cup, gint round, gchar *buf) { #ifdef DEBUG printf("cup_get_round_name\n"); #endif const CupRound *cup_round = &g_array_index(cup->rounds, CupRound, round); if(cup_round->round_robin_number_of_groups > 0) { strcpy(buf, _("Round robin")); return; } switch(cup->rounds->len - round) { default: /* A cup stage, e.g. Last 32 when there are only 32 teams left. */ sprintf(buf, _("Last %d"), (gint)rint(powf(2, cup->rounds->len - round))); break; case 1: strcpy(buf, _("Final")); break; case 2: strcpy(buf, _("Semi-final")); break; case 3: strcpy(buf, _("Quarter-final")); break; } } /** Find out whether the cup contains tables that can be displayed. Returns -1 if false and the number of the cup round with tables otherwise. */ gint cup_has_tables(gint clid) { #ifdef DEBUG printf("cup_has_tables\n"); #endif const Cup *cup = cup_from_clid(clid); gint i; for(i=cup->rounds->len - 1; i>=0; i--) if(g_array_index(cup->rounds, CupRound, i).tables->len > 0) return i; return -1; } /** Return the team that won the cup. */ Team* cup_get_winner(const Cup *cup) { #ifdef DEBUG printf("cup_get_winner\n"); #endif GPtrArray *teams_sorted = cup_get_teams_sorted(cup); Team *tm = (Team*)g_ptr_array_index(teams_sorted, 0); g_ptr_array_free(teams_sorted, TRUE); return tm; } /** Find out whether a cup with add_week 1000 should begin now. */ gboolean query_cup_begins(const Cup *cup) { #ifdef DEBUG printf("query_cup_begins\n"); #endif gint i, j; const League *league = NULL; const Cup *cup_temp = NULL; const CupRound *cup_round = NULL; for(j=0;jrounds->len;j++) { cup_round = &g_array_index(cup->rounds, CupRound, j); for(i=0;ichoose_teams->len;i++) if(!cup_choose_team_should_generate(&g_array_index(cup_round->choose_teams,CupChooseTeam, i))) { const Fixture *last_fixture; cup_get_choose_team_league_cup( &g_array_index(cup_round->choose_teams, CupChooseTeam, i), &league, &cup_temp); if(cup_temp == NULL && query_league_active(league) && g_array_index(league->fixtures, Fixture, league->fixtures->len - 1).attendance == -1) return FALSE; /* Handle cups */ if (!cup_temp) continue; if (!cup_temp->fixtures->len) return FALSE; last_fixture = &g_array_index(cup_temp->fixtures, Fixture, cup_temp->fixtures->len - 1); /* attendance == 1 means there are scheduled games that have * not been played yet. If the last fixture is not for the * last round of the cup that means there are still games * that have not been scheduled yet. */ if (last_fixture->attendance == -1 || last_fixture->round != cup_temp->rounds->len - 1) return FALSE; } } return TRUE; } /** Return the number of international cups in the country. */ gboolean query_cup_transfer(void) { #ifdef DEBUG printf("query_cup_transfer\n"); #endif gint i; for(i=0;ilen;i++) if(acp(i)->teams->len > 0) return TRUE; return FALSE; } /** Find out whether the cup has a highlight property and return the highlight colour. */ gchar* cup_get_highlight_colour(const Cup *cup) { #ifdef DEBUG printf("cup_get_highlight_colour\n"); #endif #ifdef DEBUG printf("cup_get_highlight_colour\n"); #endif gint i; gchar buf[SMALL]; for(i=0;iproperties->len;i++) if(g_str_has_prefix((gchar*)g_ptr_array_index(cup->properties, i), "highlight")) { sprintf(buf, "string_cup_%s", (gchar*)g_ptr_array_index(cup->properties, i)); return const_app(buf); } return NULL; } /** Check the cup fixtures for suspicious entries. */ gboolean cup_check_fixtures(const Cup *cup) { #ifdef DEBUG printf("cup_check_fixtures\n"); #endif gint i; for(i = 0; i < cup->fixtures->len; i++) { if(g_array_index(cup->fixtures, Fixture, i).teams[0] == g_array_index(cup->fixtures, Fixture, i).teams[1]) { if(!query_league_cup_has_property(cup->id, "silent_on_fixture_error")) debug_print_message("cup_check_fixture: bad fixture found in cup %s; cup will be disabled\n", cup->name); return FALSE; } } return TRUE; } /** Check whether we have to wait for other cups before we can write fixtures for the cup round. */ gboolean cup_round_check_waits(const CupRound *cup_round) { gint i, j, k; gchar prefix[SMALL]; for(i = 0; i < cup_round->waits->len; i++) { if(g_str_has_suffix(g_array_index(cup_round->waits, CupRoundWait, i).cup_sid, "*")) g_utf8_strncpy(prefix, g_array_index(cup_round->waits, CupRoundWait, i).cup_sid, g_utf8_strlen(g_array_index(cup_round->waits, CupRoundWait, i).cup_sid, -1) - 1); else strcpy(prefix, "NONAME"); for(j = 0; j < acps->len; j++) { if(strcmp(acp(j)->sid, g_array_index(cup_round->waits, CupRoundWait, i).cup_sid) == 0 || g_str_has_prefix(acp(j)->sid, prefix)) { /* Cup round we're waiting for isn't even reached. */ if(g_array_index(acp(j)->fixtures, Fixture, acp(j)->fixtures->len - 1).round < g_array_index(cup_round->waits, CupRoundWait, i).cup_round) return TRUE; for(k = acp(j)->fixtures->len - 1; k >= 0; k--) { /* Cup round we've been waiting for is finished, we're not waiting anymore. */ if(g_array_index(acp(j)->fixtures, Fixture, k).round > g_array_index(cup_round->waits, CupRoundWait, i).cup_round) break; /* Still waiting for matches to be calculated. */ if(g_array_index(acp(j)->fixtures, Fixture, k).round == g_array_index(cup_round->waits, CupRoundWait, i).cup_round && g_array_index(acp(j)->fixtures, Fixture, k).attendance == -1) return TRUE; } break; } } } return FALSE; } /** Find out whether the cup chooses teams from itself (e.g. the defending champion from last season). */ gboolean query_cup_self_referential(const Cup *cup) { gint i, j; for(i = 0; i < cup->rounds->len; i++) for(j = 0; j < g_array_index(cup->rounds, CupRound, i).choose_teams->len; j++) if(strcmp(g_array_index(g_array_index(cup->rounds, CupRound, i).choose_teams, CupChooseTeam, j).sid, cup->sid) == 0) return TRUE; return FALSE; } /** Find out if the cup is part of the array of cups that are displayed in the game. */ gboolean query_cup_hidden(const Cup *cup) { gint i; for(i = 0; i < acps->len; i++) if(acp(i) == cup) return FALSE; return TRUE; }