mirror of
https://github.com/tstellar/bygfoot.git
synced 2025-03-13 09:10:07 +01:00
Implement promotion and relegation rules for reserve teams
This adds some new rules for promoting and relegating reserve teams: + Reserve teams will not be promoted into a league that contains its first team or a higher-level reserve team. + If a first team or higher-level reserve team is relegated to a league with a lower reserve team, then that reserve team will also be relegated. In order to enable these rules, you must add the <reserve_promotion_rules>default</reserve_promotion_rules> tag to your contry xml file, and also define reserve teams in your league/team_defs file using the <first_team> and <reserve_level> tags.
This commit is contained in:
parent
c05e968f32
commit
4d5886da4b
@ -133,6 +133,15 @@ enum ExitCodes
|
|||||||
EXIT_END
|
EXIT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum representing a countries promotion rules for reserve teams.
|
||||||
|
*/
|
||||||
|
enum ReservePromRules
|
||||||
|
{
|
||||||
|
RESERVE_PROM_RULES_NONE = 0,
|
||||||
|
RESERVE_PROM_RULES_DEFAULT
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A struct representing a country.
|
* A struct representing a country.
|
||||||
*/
|
*/
|
||||||
@ -147,6 +156,8 @@ typedef struct
|
|||||||
Spain, for instance, has rating 10, whereas Ireland has only 5. */
|
Spain, for instance, has rating 10, whereas Ireland has only 5. */
|
||||||
gint rating;
|
gint rating;
|
||||||
|
|
||||||
|
enum ReservePromRules reserve_promotion_rules;
|
||||||
|
|
||||||
/** Leagues and cups arrays. */
|
/** Leagues and cups arrays. */
|
||||||
GArray *leagues, *cups;
|
GArray *leagues, *cups;
|
||||||
|
|
||||||
|
468
src/league.c
468
src/league.c
@ -581,6 +581,397 @@ query_league_matches_in_week(const League *league, gint week_number)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
league_get_max_movements(const League *league, enum PromRelType type)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
const GArray *elements = league->prom_rel.elements;
|
||||||
|
unsigned max = 0;
|
||||||
|
for (i = 0; i < elements->len; i++) {
|
||||||
|
const PromRelElement *element = &g_array_index(elements,
|
||||||
|
PromRelElement, i);
|
||||||
|
if (element->type != type)
|
||||||
|
continue;
|
||||||
|
max+= element->num_teams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: What about promotion games? */
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will handle the case were a reserve team needs to be
|
||||||
|
* relegated, because it's first team or a higher reserve team has been
|
||||||
|
* relegated into its division. For Example:
|
||||||
|
*
|
||||||
|
* League 1:
|
||||||
|
* Blue
|
||||||
|
* Red
|
||||||
|
* ------
|
||||||
|
* Green [Relegated]
|
||||||
|
*
|
||||||
|
* League 2:
|
||||||
|
* Orange
|
||||||
|
* Green B [Needs to be relegated since first team is joining League 2]
|
||||||
|
* ------
|
||||||
|
* Red B
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
handle_required_reserve_relegation(const TeamMove *move, GArray *team_movements)
|
||||||
|
{
|
||||||
|
gint i, j;
|
||||||
|
for (i = 0; i < move->dest_idcs->len; i++) {
|
||||||
|
gint idx = g_array_index(move->dest_idcs, gint, i);
|
||||||
|
const League *dest_league = &g_array_index(country.leagues,
|
||||||
|
League, idx);
|
||||||
|
/* If the destination league (league 2 in example above) allows
|
||||||
|
* multiple reserve teams than we don't need to relegate reserve
|
||||||
|
* teams (Green B in example above) that are already in it. */
|
||||||
|
if (league_allows_multiple_reserve_teams(dest_league))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Search through the destination league (League 2 in example above)
|
||||||
|
* to see if there are any teams with the same first team of the
|
||||||
|
* team (Green in the example above) we are relegating. */
|
||||||
|
for (j = 0; j < dest_league->teams->len; j++) {
|
||||||
|
gint k;
|
||||||
|
TeamMove new_move;
|
||||||
|
const Team *reserve_team = &g_array_index(dest_league->teams,
|
||||||
|
Team, j);
|
||||||
|
if (move->tm.first_team_id != reserve_team->first_team_id)
|
||||||
|
continue; /* Teams do not share the same first team. */
|
||||||
|
|
||||||
|
/* We have found a reserve team (Green B in the example above)
|
||||||
|
* that shares a first team with the team we are relegating (Green
|
||||||
|
* in the example above). So no we need to also relegate this
|
||||||
|
* reserve team. */
|
||||||
|
new_move.tm = *reserve_team;
|
||||||
|
new_move.prom_rel_type = PROM_REL_RELEGATION;
|
||||||
|
new_move.dest_assigned = FALSE;
|
||||||
|
|
||||||
|
/* Search for a place to insert the new relegation into
|
||||||
|
* team_movements, we want it to be added at the end of this
|
||||||
|
* leagues relegation list so it is preferred over the other
|
||||||
|
* relegations. Also, if we were already planning to relegate
|
||||||
|
* this team, delete the relegation. */
|
||||||
|
for (k = team_movements->len - 1; k >= 0; k--) {
|
||||||
|
const TeamMove *move = &g_array_index(team_movements, TeamMove, k);
|
||||||
|
if (move->prom_rel_type != PROM_REL_RELEGATION)
|
||||||
|
continue;
|
||||||
|
if (move->tm.id == reserve_team->id) {
|
||||||
|
/* Found another relegation for this team, so we need to
|
||||||
|
* remove it. */
|
||||||
|
g_array_remove_index(team_movements, k);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move->tm.clid == reserve_team->clid) {
|
||||||
|
/* We have found the last relegation for this league, so
|
||||||
|
* insert the new_move here. */
|
||||||
|
gint insert_index = k + 1;
|
||||||
|
new_move.dest_idcs = g_array_copy(move->dest_idcs);
|
||||||
|
|
||||||
|
if(debug > 70) {
|
||||||
|
printf("Adding relegation of %s\n", reserve_team->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insert_index == team_movements->len)
|
||||||
|
g_array_append_val(team_movements, new_move);
|
||||||
|
else
|
||||||
|
g_array_insert_val(team_movements, insert_index, new_move);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: There is one case we aren't handling yet, and that is
|
||||||
|
* where a reserve team (Green B in the example above), needs to
|
||||||
|
* be relegated becasue its first team (Green in the example above)
|
||||||
|
* is relegated to its league *and* the league the reserve team
|
||||||
|
* (Green B) is being relegated to has no teams eligible for
|
||||||
|
* promotion for example:
|
||||||
|
*
|
||||||
|
* League 3:
|
||||||
|
* Green C
|
||||||
|
* Orange B
|
||||||
|
* Red C
|
||||||
|
*
|
||||||
|
* None of theses teams would be elegible, since they all have
|
||||||
|
* first teams in League 2. So, if we were to relegated (Green B),
|
||||||
|
* then we'd end up with an extra team in League 3.
|
||||||
|
* I'm not sure how to handle this, so for now, when this scenario
|
||||||
|
* happens, we just league the reserve team (Green B) in the league
|
||||||
|
* with its first team (Green). */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
league_team_is_top_reserve_team(const League *league, const Team *team)
|
||||||
|
{
|
||||||
|
gint reserve_level, i;
|
||||||
|
|
||||||
|
for (i = 0; i < league->teams->len; i++) {
|
||||||
|
gint other_level;
|
||||||
|
const Team *other_team = &g_array_index(league->teams, Team, i);
|
||||||
|
if (team->first_team_id != other_team->first_team_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (team->reserve_level > other_team->reserve_level)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_next_movement_search(gint *current_layer, enum PromRelType *type)
|
||||||
|
{
|
||||||
|
if (*type == PROM_REL_PROMOTION) {
|
||||||
|
*current_layer = *current_layer - 1;
|
||||||
|
*type = PROM_REL_RELEGATION;
|
||||||
|
} else if (*type == PROM_REL_RELEGATION) {
|
||||||
|
*current_layer = *current_layer + 2;
|
||||||
|
*type = PROM_REL_PROMOTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
country_filter_promotions(const Country *country, GArray *team_movements,
|
||||||
|
GArray *move_summaries, gint current_layer)
|
||||||
|
{
|
||||||
|
gint i = 0, j;
|
||||||
|
while (i < team_movements->len) {
|
||||||
|
gint additions = 0;
|
||||||
|
const TeamMove *move = &g_array_index(team_movements, TeamMove, i++);
|
||||||
|
const League *league = league_from_clid(move->tm.clid);
|
||||||
|
gint league_idx = league_index_from_sid(league->sid);
|
||||||
|
MoveSummary *summary = &g_array_index(move_summaries, MoveSummary, league_idx);
|
||||||
|
gint dest_idx;
|
||||||
|
gpointer hash_value;
|
||||||
|
|
||||||
|
if (move->prom_rel_type != PROM_REL_PROMOTION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (league->layer != current_layer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(debug > 70) {
|
||||||
|
gint dest_idx = g_array_index(move->dest_idcs, gint, 0);
|
||||||
|
const League *dest_league = &g_array_index(country->leagues,
|
||||||
|
League, dest_idx);
|
||||||
|
|
||||||
|
printf("Looking at promotion of %s from %s to %s.\n", move->tm.name,
|
||||||
|
league->name, dest_league->name);
|
||||||
|
}
|
||||||
|
if (summary->max_promotions && summary->num_promotions_from == summary->max_promotions)
|
||||||
|
goto remove_promotion;
|
||||||
|
|
||||||
|
/* If there are other reserve teams with the same first team that
|
||||||
|
* are a higher level, then we can't promote this team. */
|
||||||
|
if (!league_team_is_top_reserve_team(league, &move->tm))
|
||||||
|
goto remove_promotion;
|
||||||
|
|
||||||
|
for (j = 0; j < move->dest_idcs->len; j++) {
|
||||||
|
gint idx = g_array_index(move->dest_idcs, gint, j);
|
||||||
|
const League *dest_league = &g_array_index(country->leagues,
|
||||||
|
League, idx);
|
||||||
|
if (!league_can_accept_promoted_team(dest_league, &move->tm, team_movements))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j < move->dest_idcs->len) {
|
||||||
|
/* This means we found a destination league that we can't promote to,
|
||||||
|
* so we can't promote this team. */
|
||||||
|
goto remove_promotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can promote this team */
|
||||||
|
/* FIXME: How to handle multiple dest_idcs */
|
||||||
|
dest_idx = g_array_index(move->dest_idcs, gint, 0);
|
||||||
|
summary->num_promotions_from++;
|
||||||
|
g_array_index(move_summaries, MoveSummary, dest_idx).num_promotions_to++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
remove_promotion:
|
||||||
|
if(debug > 70) {
|
||||||
|
printf("Removing the promotion.\n");
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
g_array_remove_index(team_movements, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
country_filter_relegations(const Country *country, GArray *team_movements,
|
||||||
|
GArray *move_summaries, gint current_layer)
|
||||||
|
{
|
||||||
|
gint i = team_movements->len - 1;
|
||||||
|
while (i >= 0) {
|
||||||
|
const TeamMove *move = &g_array_index(team_movements, TeamMove, i--);
|
||||||
|
const League *league = league_from_clid(move->tm.clid);
|
||||||
|
gint league_idx = league_index_from_sid(league->sid);
|
||||||
|
MoveSummary *summary = &g_array_index(move_summaries, MoveSummary, league_idx);
|
||||||
|
const Team *first_team;
|
||||||
|
gint reserve_level;
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
if (move->prom_rel_type != PROM_REL_RELEGATION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (league->layer != current_layer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(debug > 70) {
|
||||||
|
gint dest_idx = g_array_index(move->dest_idcs, gint, 0);
|
||||||
|
const League *dest_league = &g_array_index(country->leagues,
|
||||||
|
League, dest_idx);
|
||||||
|
|
||||||
|
printf("Looking at relegation of %s from %s to %s.\n", move->tm.name,
|
||||||
|
league->name, dest_league->name);
|
||||||
|
}
|
||||||
|
if (summary->num_relegations_from == summary->num_promotions_to) {
|
||||||
|
if(debug > 70)
|
||||||
|
printf("Removing the relegation.\n");
|
||||||
|
/* We can't relegate this team */
|
||||||
|
g_array_remove_index(team_movements, i + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary->num_relegations_from++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next check if any of our relegations would cause a lower level reserve
|
||||||
|
* team to also be relegated. */
|
||||||
|
for (i = 0; i < team_movements->len; i++) {
|
||||||
|
const TeamMove *move = &g_array_index(team_movements, TeamMove, i);
|
||||||
|
const League *league = league_from_clid(move->tm.clid);
|
||||||
|
if (move->prom_rel_type != PROM_REL_RELEGATION)
|
||||||
|
continue;
|
||||||
|
if (league->layer != current_layer)
|
||||||
|
continue;
|
||||||
|
handle_required_reserve_relegation(move, team_movements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the maximum league layer for \p country. This function does not
|
||||||
|
* assume that the last league has the maximum layer even though this is
|
||||||
|
* usually the case.
|
||||||
|
*/
|
||||||
|
static gint
|
||||||
|
country_get_max_layer(const Country *country)
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
gint max_layer = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < country->leagues->len; i++) {
|
||||||
|
const League *league = &g_array_index(country->leagues, League, i);
|
||||||
|
max_layer = MAX(league->layer, max_layer);
|
||||||
|
}
|
||||||
|
return max_layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Filter out movemnts that may not be allowed due to league rules,
|
||||||
|
* e.g. promotion of reserve teams. */
|
||||||
|
void
|
||||||
|
country_apply_reserve_prom_rules(const Country *country, GArray *team_movements)
|
||||||
|
{
|
||||||
|
gint num_promotions;
|
||||||
|
GArray *move_summaries;
|
||||||
|
gint i = 0, j = 0;
|
||||||
|
gint current_layer, max_layer;
|
||||||
|
enum PromRelType current_type;
|
||||||
|
|
||||||
|
if (country->reserve_promotion_rules != RESERVE_PROM_RULES_DEFAULT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
move_summaries = g_array_sized_new(FALSE, TRUE, sizeof(MoveSummary),
|
||||||
|
country->leagues->len);
|
||||||
|
g_array_set_size(move_summaries, country->leagues->len);
|
||||||
|
|
||||||
|
/* Initialize the move summaries */
|
||||||
|
for (i = 0; i < move_summaries->len; i++) {
|
||||||
|
const League *league = &g_array_index(country->leagues, League, i);
|
||||||
|
MoveSummary *summary = &g_array_index(move_summaries, MoveSummary, i);
|
||||||
|
summary->max_promotions = league_get_max_movements(league, PROM_REL_PROMOTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* We need to analyze the relegations and promotions in a specific order
|
||||||
|
* due to the dependencies between relegations in promotions in different
|
||||||
|
* leagues. You can model the dependencies as a graph that looks like this:
|
||||||
|
*
|
||||||
|
* -----1-- (2P) --3-----
|
||||||
|
* | |
|
||||||
|
* \/ \/
|
||||||
|
* (1R) --4-----------> (3P)--3----> (4P)
|
||||||
|
* | | ^ |
|
||||||
|
* | 1 ---4---| 1
|
||||||
|
* | | / |
|
||||||
|
* | \/ / \/
|
||||||
|
* -----2-----------> (2R) --2---> (3R)
|
||||||
|
*
|
||||||
|
* Where the number is the league layer, and P stands for promotion and R
|
||||||
|
* stands for relegation. The numbers describe why there is a dependeny:
|
||||||
|
*
|
||||||
|
* 1. Normal promotion / relegation dependency. The number of relegations
|
||||||
|
* depends on the number of promotions from the lower league.
|
||||||
|
*
|
||||||
|
* 2. Forced relegation of reserve team when first team is relegated into
|
||||||
|
* its division. This means that the relegations of a lower league
|
||||||
|
* depend on the relegations of the higher league.
|
||||||
|
*
|
||||||
|
* 3. A first team being promoted out of a league that allows the reserve
|
||||||
|
* team to be promoted into it. This means that promotions from a lower
|
||||||
|
* league depend on the promotions from the league abvoe it.
|
||||||
|
*
|
||||||
|
* 4. A first team being relegated to a lower league at the same time
|
||||||
|
* a reserve team is being promoted into that league. This means
|
||||||
|
* that promotions from a league depend an relegations from a league
|
||||||
|
* 2 levels above it.
|
||||||
|
*
|
||||||
|
* This graph helps to illistrate the correct in order in which we should
|
||||||
|
* determine promotions and relegations in this country so that all
|
||||||
|
* dependencies are resolved before we start analyzing promotions and
|
||||||
|
* relegations for a specific league.
|
||||||
|
*
|
||||||
|
* In this case, the correct order is:
|
||||||
|
*
|
||||||
|
* 2P -> 1R -> 3P -> 2R -> 4P -> 3R
|
||||||
|
*/
|
||||||
|
|
||||||
|
max_layer = country_get_max_layer(country);
|
||||||
|
current_layer = 2;
|
||||||
|
current_type = PROM_REL_PROMOTION;
|
||||||
|
|
||||||
|
/* Loop through the team_movements in the order from the comment above.
|
||||||
|
* We are making the following assumptions about the list of team_movements:
|
||||||
|
* 1. Movements from the same league are listed in order of the teams rank
|
||||||
|
* in the fixtures.
|
||||||
|
* 2. The leagues have 'normal' promotions e.g. layer 2 promotes to layer 1
|
||||||
|
* and relegates to layer 3, etc.
|
||||||
|
*
|
||||||
|
* We are not making the assumption that the list is ordered based on the layer
|
||||||
|
* of the team's league (even though it likely is).
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
if (current_type == PROM_REL_PROMOTION)
|
||||||
|
country_filter_promotions(country, team_movements,
|
||||||
|
move_summaries, current_layer);
|
||||||
|
else if (current_type == PROM_REL_RELEGATION)
|
||||||
|
country_filter_relegations(country, team_movements,
|
||||||
|
move_summaries, current_layer);
|
||||||
|
|
||||||
|
get_next_movement_search(¤t_layer, ¤t_type);
|
||||||
|
} while(current_layer <= max_layer);
|
||||||
|
|
||||||
|
|
||||||
|
/* Next handle relegations. */
|
||||||
|
|
||||||
|
/* Iterate in reverse order to ensure that the lowest ranked teams are
|
||||||
|
* preferred for relegation. */
|
||||||
|
|
||||||
|
g_array_unref(move_summaries);
|
||||||
|
}
|
||||||
|
|
||||||
/** Add the teams to promote/relegate (from the prom_rel elements)
|
/** Add the teams to promote/relegate (from the prom_rel elements)
|
||||||
from the league to the array. */
|
from the league to the array. */
|
||||||
void
|
void
|
||||||
@ -1172,3 +1563,80 @@ country_lookup_first_team_ids(const Country *country)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
league_can_accept_promoted_team(const League *league, const Team *tm,
|
||||||
|
const GArray *team_movements)
|
||||||
|
{
|
||||||
|
gint i, j;
|
||||||
|
|
||||||
|
/* Reserve teams are currently the only kind of teams that have restrictions
|
||||||
|
* around promotion. */
|
||||||
|
if (!team_is_reserve_team(tm))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!league_allows_reserve_teams(league))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* If the first team or a higher reserve team is in the league, then we
|
||||||
|
* can't promote the reserve team.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < league->teams->len; i++) {
|
||||||
|
gboolean upper_team_promoted = FALSE;
|
||||||
|
const Team *upper_team = &g_array_index(league->teams, Team, i);
|
||||||
|
if (tm->first_team_id != upper_team->first_team_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If the upper team is going to be promoted, then it is ok to
|
||||||
|
* promote the reserve team.
|
||||||
|
* This code assumes than team_movements is ordered so that higher
|
||||||
|
* divisions come first and have already been filtered for
|
||||||
|
* ineligible promotions. */
|
||||||
|
for (j = 0; j < team_movements->len; j++) {
|
||||||
|
const TeamMove *move = &g_array_index(team_movements, TeamMove, j);
|
||||||
|
if (move->prom_rel_type != PROM_REL_PROMOTION)
|
||||||
|
continue;
|
||||||
|
if (move->tm.id == upper_team->id) {
|
||||||
|
upper_team_promoted = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* The upper team has not been promoted. */
|
||||||
|
if (!upper_team_promoted)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the first team or a higher reserve team is going to be relegated into
|
||||||
|
* this league, then we can't promote this team. */
|
||||||
|
for (i = 0; i < team_movements->len; i++) {
|
||||||
|
const TeamMove *move = &g_array_index(team_movements, TeamMove, i);
|
||||||
|
if (move->prom_rel_type != PROM_REL_RELEGATION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tm->first_team_id != move->tm.first_team_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < move->dest_idcs->len; j++) {
|
||||||
|
gint idx = g_array_index(move->dest_idcs, gint, j);
|
||||||
|
const League *dest_league = &g_array_index(country.leagues,
|
||||||
|
League, idx);
|
||||||
|
if(dest_league->id == league->id)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The league has no upper teams, so we can continue. */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
league_allows_reserve_teams(const League *league)
|
||||||
|
{
|
||||||
|
return league->layer != 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
league_allows_multiple_reserve_teams(const League *league)
|
||||||
|
{
|
||||||
|
return lig(ligs->len - 1).layer == league->layer;
|
||||||
|
}
|
||||||
|
21
src/league.h
21
src/league.h
@ -53,6 +53,14 @@ typedef struct
|
|||||||
} TeamMove;
|
} TeamMove;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gint num_promotions_from;
|
||||||
|
gint num_promotions_to;
|
||||||
|
gint num_relegations_from;
|
||||||
|
gint max_promotions;
|
||||||
|
} MoveSummary;
|
||||||
|
|
||||||
League
|
League
|
||||||
league_new(gboolean new_id);
|
league_new(gboolean new_id);
|
||||||
|
|
||||||
@ -104,6 +112,9 @@ query_league_prom_games_begin(const League *league);
|
|||||||
gboolean
|
gboolean
|
||||||
query_league_matches_in_week(const League *league, gint week_number);
|
query_league_matches_in_week(const League *league, gint week_number);
|
||||||
|
|
||||||
|
void
|
||||||
|
country_apply_reserve_prom_rules(const Country *country, GArray *team_movements);
|
||||||
|
|
||||||
void
|
void
|
||||||
league_get_team_movements_prom_rel(const League *league, GArray *team_movements);
|
league_get_team_movements_prom_rel(const League *league, GArray *team_movements);
|
||||||
|
|
||||||
@ -173,4 +184,14 @@ league_cup_get_week_with_break(gint clid, gint week_number);
|
|||||||
void
|
void
|
||||||
country_lookup_first_team_ids(const Country *country);
|
country_lookup_first_team_ids(const Country *country);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
league_can_accept_promoted_team(const League *league, const Team *tm,
|
||||||
|
const GArray *team_movements);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
league_allows_reserve_teams(const League *league);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
league_allows_multiple_reserve_teams(const League *league);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -794,6 +794,9 @@ start_new_season_league_changes(void)
|
|||||||
for(i=0;i<ligs->len;i++)
|
for(i=0;i<ligs->len;i++)
|
||||||
league_get_team_movements(&lig(i), team_movements);
|
league_get_team_movements(&lig(i), team_movements);
|
||||||
|
|
||||||
|
if (country.reserve_promotion_rules)
|
||||||
|
country_apply_reserve_prom_rules(&country, team_movements);
|
||||||
|
|
||||||
for(i=0;i<ligs->len;i++)
|
for(i=0;i<ligs->len;i++)
|
||||||
league_size[i] = lig(i).teams->len;
|
league_size[i] = lig(i).teams->len;
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#define TAG_LEAGUE "league"
|
#define TAG_LEAGUE "league"
|
||||||
#define TAG_CUPS "cups"
|
#define TAG_CUPS "cups"
|
||||||
#define TAG_CUP "cup"
|
#define TAG_CUP "cup"
|
||||||
|
#define TAG_RESERVE_PROMOTION_RULES "reserve_promotion_rules"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum with the states used in the XML parser functions.
|
* Enum with the states used in the XML parser functions.
|
||||||
@ -59,6 +60,7 @@ enum XmlCountryStates
|
|||||||
STATE_LEAGUE,
|
STATE_LEAGUE,
|
||||||
STATE_CUPS,
|
STATE_CUPS,
|
||||||
STATE_CUP,
|
STATE_CUP,
|
||||||
|
STATE_RESERVE_PROMOTION_RULES,
|
||||||
STATE_END
|
STATE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -112,6 +114,8 @@ xml_country_read_start_element (GMarkupParseContext *context,
|
|||||||
}
|
}
|
||||||
else if(strcmp(element_name, TAG_CUP) == 0)
|
else if(strcmp(element_name, TAG_CUP) == 0)
|
||||||
state = STATE_CUP;
|
state = STATE_CUP;
|
||||||
|
else if(strcmp(element_name, TAG_RESERVE_PROMOTION_RULES) == 0)
|
||||||
|
state = STATE_RESERVE_PROMOTION_RULES;
|
||||||
else if(strcmp(element_name, TAG_COUNTRY) != 0)
|
else if(strcmp(element_name, TAG_COUNTRY) != 0)
|
||||||
debug_print_message("xml_country_read_start_element: unknown tag: %s; I'm in state %d\n",
|
debug_print_message("xml_country_read_start_element: unknown tag: %s; I'm in state %d\n",
|
||||||
element_name, state);
|
element_name, state);
|
||||||
@ -139,6 +143,7 @@ xml_country_read_end_element (GMarkupParseContext *context,
|
|||||||
strcmp(element_name, TAG_DEF_SID) == 0 ||
|
strcmp(element_name, TAG_DEF_SID) == 0 ||
|
||||||
strcmp(element_name, TAG_SUPERNATIONAL) == 0 ||
|
strcmp(element_name, TAG_SUPERNATIONAL) == 0 ||
|
||||||
strcmp(element_name, TAG_LEAGUES) == 0 ||
|
strcmp(element_name, TAG_LEAGUES) == 0 ||
|
||||||
|
strcmp(element_name, TAG_RESERVE_PROMOTION_RULES) == 0 ||
|
||||||
strcmp(element_name, TAG_CUPS) == 0)
|
strcmp(element_name, TAG_CUPS) == 0)
|
||||||
state = STATE_COUNTRY;
|
state = STATE_COUNTRY;
|
||||||
else if(strcmp(element_name, TAG_LEAGUE) == 0)
|
else if(strcmp(element_name, TAG_LEAGUE) == 0)
|
||||||
@ -198,6 +203,16 @@ xml_country_read_text (GMarkupParseContext *context,
|
|||||||
xml_league_read(buf, cntry->leagues);
|
xml_league_read(buf, cntry->leagues);
|
||||||
else if(state == STATE_CUP)
|
else if(state == STATE_CUP)
|
||||||
xml_cup_read(buf, cntry->cups);
|
xml_cup_read(buf, cntry->cups);
|
||||||
|
else if(state == STATE_RESERVE_PROMOTION_RULES) {
|
||||||
|
if (!strcmp(buf, "none"))
|
||||||
|
cntry->reserve_promotion_rules = RESERVE_PROM_RULES_NONE;
|
||||||
|
else if (!strcmp(buf, "default"))
|
||||||
|
cntry->reserve_promotion_rules = RESERVE_PROM_RULES_DEFAULT;
|
||||||
|
else {
|
||||||
|
g_warning("Unknown value for <reserve_promotion_rules>: %s\n", buf);
|
||||||
|
cntry->reserve_promotion_rules = RESERVE_PROM_RULES_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ enum XmlLoadSaveCountryTags
|
|||||||
TAG_MISC_BET_ODD,
|
TAG_MISC_BET_ODD,
|
||||||
TAG_MISC_VERSION,
|
TAG_MISC_VERSION,
|
||||||
TAG_MISC_CURRENT_INTEREST,
|
TAG_MISC_CURRENT_INTEREST,
|
||||||
|
TAG_MISC_RESERVE_PROMOTION_RULES,
|
||||||
TAG_END
|
TAG_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -116,6 +117,7 @@ xml_loadsave_misc_end_element (GMarkupParseContext *context,
|
|||||||
if(tag == TAG_NAME ||
|
if(tag == TAG_NAME ||
|
||||||
tag == TAG_SYMBOL ||
|
tag == TAG_SYMBOL ||
|
||||||
tag == TAG_SID ||
|
tag == TAG_SID ||
|
||||||
|
tag == TAG_MISC_RESERVE_PROMOTION_RULES ||
|
||||||
tag == TAG_MISC_VERSION ||
|
tag == TAG_MISC_VERSION ||
|
||||||
tag == TAG_MISC_CURRENT_INTEREST ||
|
tag == TAG_MISC_CURRENT_INTEREST ||
|
||||||
tag == TAG_MISC_RATING ||
|
tag == TAG_MISC_RATING ||
|
||||||
@ -175,6 +177,8 @@ xml_loadsave_misc_text (GMarkupParseContext *context,
|
|||||||
misc_string_assign(&country.symbol, buf);
|
misc_string_assign(&country.symbol, buf);
|
||||||
else if(state == TAG_SID)
|
else if(state == TAG_SID)
|
||||||
misc_string_assign(&country.sid, buf);
|
misc_string_assign(&country.sid, buf);
|
||||||
|
else if (state == TAG_MISC_RESERVE_PROMOTION_RULES)
|
||||||
|
country.reserve_promotion_rules = int_value;
|
||||||
else if(state == TAG_MISC_SEASON)
|
else if(state == TAG_MISC_SEASON)
|
||||||
season = int_value;
|
season = int_value;
|
||||||
else if(state == TAG_MISC_WEEK)
|
else if(state == TAG_MISC_WEEK)
|
||||||
@ -263,6 +267,7 @@ xml_loadsave_misc_write(const gchar *prefix)
|
|||||||
xml_write_string(fil, country.name, TAG_NAME, I0);
|
xml_write_string(fil, country.name, TAG_NAME, I0);
|
||||||
xml_write_string(fil, country.symbol, TAG_SYMBOL, I0);
|
xml_write_string(fil, country.symbol, TAG_SYMBOL, I0);
|
||||||
xml_write_string(fil, country.sid, TAG_SID, I0);
|
xml_write_string(fil, country.sid, TAG_SID, I0);
|
||||||
|
xml_write_int(fil, country.reserve_promotion_rules, TAG_MISC_RESERVE_PROMOTION_RULES, I0);
|
||||||
xml_write_int(fil, country.rating, TAG_MISC_RATING, I0);
|
xml_write_int(fil, country.rating, TAG_MISC_RATING, I0);
|
||||||
xml_write_int(fil, season, TAG_MISC_SEASON, I0);
|
xml_write_int(fil, season, TAG_MISC_SEASON, I0);
|
||||||
xml_write_int(fil, week, TAG_MISC_WEEK, I0);
|
xml_write_int(fil, week, TAG_MISC_WEEK, I0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user