mirror of
https://github.com/tstellar/bygfoot.git
synced 2025-02-23 14:57:39 +01:00
709 lines
20 KiB
C
709 lines
20 KiB
C
/*
|
|
strategy.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 "fixture.h"
|
|
#include "league.h"
|
|
#include "live_game.h"
|
|
#include "main.h"
|
|
#include "misc.h"
|
|
#include "option.h"
|
|
#include "player.h"
|
|
#include "strategy.h"
|
|
#include "team.h"
|
|
|
|
GPtrArray *token_strat[2];
|
|
|
|
/** Return the sid of a random strategy from the
|
|
strategies array (also dependent on the priorities
|
|
of the strategies). */
|
|
gchar*
|
|
strategy_get_random(void)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_get_random\n");
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
printf("strategy_get_random\n");
|
|
#endif
|
|
|
|
gint i, rndom =
|
|
math_rndi(1, g_array_index(strategies, Strategy, strategies->len - 1).priority);
|
|
|
|
if(rndom <= g_array_index(strategies, Strategy, 0).priority)
|
|
return g_strdup(g_array_index(strategies, Strategy, 0).sid);
|
|
|
|
for(i=1;i<strategies->len;i++)
|
|
if(rndom <= g_array_index(strategies, Strategy, i).priority)
|
|
return g_strdup(g_array_index(strategies, Strategy, i).sid);
|
|
|
|
main_exit_program(EXIT_STRATEGY_ERROR, "team_strategy_get_random: no strategy found.");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** Compare function for sorting the players given a specific
|
|
strategy. */
|
|
gint
|
|
strategy_compare_players(gconstpointer a,
|
|
gconstpointer b,
|
|
gpointer user_data)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_compare_players\n");
|
|
#endif
|
|
|
|
const Player *pl1 = *(const Player**)a;
|
|
const Player *pl2 = *(const Player**)b;
|
|
const StrategyPrematch *strat = (StrategyPrematch*)user_data;
|
|
gint return_value = 0;
|
|
|
|
if(pl1->pos != pl2->pos)
|
|
return_value = misc_int_compare(pl2->pos, pl1->pos);
|
|
else if(pl1->cskill == 0 && pl2->cskill > 0)
|
|
return_value = 1;
|
|
else if(pl2->cskill == 0 && pl1->cskill > 0)
|
|
return_value = -1;
|
|
else if(strat->min_fitness != 0 &&
|
|
pl1->fitness < strat->min_fitness &&
|
|
pl2->fitness >= strat->min_fitness)
|
|
return_value = 1;
|
|
else if(strat->min_fitness != 0 &&
|
|
pl1->fitness >= strat->min_fitness &&
|
|
pl2->fitness < strat->min_fitness)
|
|
return_value = -1;
|
|
else
|
|
{
|
|
gfloat skill1 = player_get_game_skill(pl1, TRUE, TRUE),
|
|
skill2 = player_get_game_skill(pl2, TRUE, TRUE);
|
|
|
|
if(strat->lineup == STRAT_LINEUP_BEST)
|
|
return_value = misc_float_compare(skill1, skill2);
|
|
else if(strat->lineup == STRAT_LINEUP_WEAKEST)
|
|
return_value = misc_float_compare(skill2, skill1);
|
|
else if(strat->lineup == STRAT_LINEUP_FITTEST)
|
|
{
|
|
return_value = misc_float_compare(pl1->fitness, pl2->fitness);
|
|
if(pl1->fitness == pl2->fitness)
|
|
return_value = misc_float_compare(skill1, skill2);
|
|
}
|
|
else
|
|
g_warning("strategy_compare_players: unknown lineup type %d\n", strat->lineup);
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
/** Check whether a lineup described in the prematch using the given
|
|
formation can be made with the players. */
|
|
gboolean
|
|
query_strategy_formation_possible(const GPtrArray *players,
|
|
const StrategyPrematch *prematch,
|
|
gint formation)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("query_strategy_formation_possible\n");
|
|
#endif
|
|
|
|
gint i, pos[3] = {0, 0, 0};
|
|
|
|
for(i=0;i<players->len;i++)
|
|
if(((Player*)g_ptr_array_index(players, i))->pos > 0 &&
|
|
((Player*)g_ptr_array_index(players, i))->cskill > 0 &&
|
|
((Player*)g_ptr_array_index(players, i))->fitness >=
|
|
prematch->min_fitness)
|
|
pos[((Player*)g_ptr_array_index(players, i))->pos - 1]++;
|
|
|
|
if(pos[2] >= math_get_place(formation, 1) &&
|
|
pos[1] >= math_get_place(formation, 2) &&
|
|
pos[0] >= math_get_place(formation, 3))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/** Make the necessary substitutions to satisfy the given prematch
|
|
and formation requirements. */
|
|
void
|
|
strategy_update_lineup(Team *tm, const GPtrArray *players,
|
|
const StrategyPrematch *prematch, gint formation)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_update_lineup\n");
|
|
#endif
|
|
|
|
gint i;
|
|
GArray *ids = g_array_new(FALSE, FALSE, sizeof(gint));
|
|
GArray *new_players = g_array_new(FALSE, FALSE, sizeof(Player));
|
|
gint form[3] = {math_get_place(formation, 3),
|
|
math_get_place(formation, 2),
|
|
math_get_place(formation, 1)},
|
|
pos[3] = {0, 0, 0};
|
|
|
|
/* Repair goalie if necessary. */
|
|
if(((Player*)g_ptr_array_index(players, 0))->cskill == 0)
|
|
strategy_repair_player((Player*)g_ptr_array_index(players, 0));
|
|
|
|
g_array_append_val(ids, ((Player*)g_ptr_array_index(players, 0))->id);
|
|
|
|
for(i=0;i<players->len;i++)
|
|
if(((Player*)g_ptr_array_index(players, i))->pos > 0 &&
|
|
pos[((Player*)g_ptr_array_index(players, i))->pos - 1] <
|
|
form[((Player*)g_ptr_array_index(players, i))->pos - 1])
|
|
{
|
|
g_array_append_val(ids, ((Player*)g_ptr_array_index(players, i))->id);
|
|
pos[((Player*)g_ptr_array_index(players, i))->pos - 1]++;
|
|
}
|
|
|
|
for(i=0;i<ids->len;i++)
|
|
g_array_append_val(new_players,
|
|
*(player_of_id_team(tm, g_array_index(ids, gint, i))));
|
|
|
|
for(i=0;i<tm->players->len;i++)
|
|
if(!query_misc_integer_is_in_g_array(
|
|
g_array_index(tm->players, Player, i).id, ids))
|
|
g_array_append_val(new_players, g_array_index(tm->players, Player, i));
|
|
|
|
g_array_free(tm->players, TRUE);
|
|
tm->players = new_players;
|
|
g_array_free(ids, TRUE);
|
|
|
|
tm->structure = formation;
|
|
team_rearrange(tm);
|
|
}
|
|
|
|
/** Delete red cards, cure injuries etc. Used to
|
|
make sure a CPU team doesn't break. */
|
|
void
|
|
strategy_repair_player(Player *pl)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_repair_player\n");
|
|
#endif
|
|
|
|
gint i;
|
|
|
|
for(i=0;i<pl->cards->len;i++)
|
|
g_array_index(pl->cards, PlayerCard, i).red = 0;
|
|
|
|
pl->health =
|
|
pl->recovery = 0;
|
|
pl->cskill =
|
|
player_get_cskill(pl, pl->pos, FALSE);
|
|
|
|
pl->fitness =
|
|
math_rnd(const_float("float_player_fitness_lower"),
|
|
const_float("float_player_fitness_upper"));
|
|
}
|
|
|
|
/** 'Repair' exactly as many players as are required to be able
|
|
to make a lineup of healthy players with the primary formation
|
|
of the given prematch. */
|
|
void
|
|
strategy_repair_players(GPtrArray *players,
|
|
const StrategyPrematch *prematch)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_repair_players\n");
|
|
#endif
|
|
|
|
gint i, j;
|
|
gint form[3] =
|
|
{math_get_place(g_array_index(prematch->formations, gint, 0), 3),
|
|
math_get_place(g_array_index(prematch->formations, gint, 0), 2),
|
|
math_get_place(g_array_index(prematch->formations, gint, 0), 1)};
|
|
gint pos[3] = {0, 0, 0};
|
|
|
|
for(i=0;i<players->len;i++)
|
|
if(((Player*)g_ptr_array_index(players, i))->pos > 0 &&
|
|
((Player*)g_ptr_array_index(players, i))->cskill > 0)
|
|
pos[((Player*)g_ptr_array_index(players, i))->pos - 1]++;
|
|
|
|
for(i=0;i<3;i++)
|
|
{
|
|
while(pos[i] < form[i])
|
|
for(j=0;j<players->len;j++)
|
|
if(((Player*)g_ptr_array_index(players, j))->pos == i + 1 &&
|
|
((Player*)g_ptr_array_index(players, j))->cskill == 0)
|
|
{
|
|
strategy_repair_player((Player*)g_ptr_array_index(players, j));
|
|
pos[i]++;
|
|
}
|
|
}
|
|
|
|
g_ptr_array_sort_with_data(players, (GCompareDataFunc)strategy_compare_players,
|
|
(gpointer)prematch);
|
|
}
|
|
|
|
/** Make team changes according to the rules in the prematch. */
|
|
void
|
|
strategy_apply_prematch(Team *tm, const StrategyPrematch *prematch)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_apply_prematch\n");
|
|
#endif
|
|
|
|
gint i;
|
|
GPtrArray *players = player_get_pointers_from_array(tm->players);
|
|
|
|
tm->style = prematch->style;
|
|
tm->boost = prematch->boost;
|
|
|
|
g_ptr_array_sort_with_data(players, (GCompareDataFunc)strategy_compare_players,
|
|
(gpointer)prematch);
|
|
|
|
for(i=0;i<prematch->formations->len;i++)
|
|
if(query_strategy_formation_possible(
|
|
players, prematch,
|
|
g_array_index(prematch->formations, gint, i)))
|
|
{
|
|
strategy_update_lineup(
|
|
tm, players,prematch,
|
|
g_array_index(prematch->formations, gint, i));
|
|
break;
|
|
}
|
|
|
|
/* We have to repair players to be able to satisfy
|
|
a formation. */
|
|
if(i == prematch->formations->len)
|
|
{
|
|
strategy_repair_players(players, prematch);
|
|
strategy_update_lineup(tm, players, prematch,
|
|
g_array_index(prematch->formations, gint, 0));
|
|
}
|
|
|
|
g_ptr_array_free(players, TRUE);
|
|
}
|
|
|
|
/** Make necessary subs etc. for a CPU team. */
|
|
void
|
|
strategy_update_team_pre_match(Team *tm)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_update_team_pre_match\n");
|
|
#endif
|
|
|
|
gint i;
|
|
const GArray *prematches =
|
|
strategy_from_sid(tm->strategy_sid)->prematch;
|
|
|
|
strategy_set_tokens(tm, NULL);
|
|
|
|
for(i=prematches->len - 1; i >= 0; i--)
|
|
if(g_array_index(prematches, StrategyPrematch, i).condition == NULL ||
|
|
misc_parse_condition(g_array_index(prematches, StrategyPrematch, i).condition,
|
|
token_strat))
|
|
{
|
|
strategy_apply_prematch(tm, &g_array_index(prematches, StrategyPrematch, i));
|
|
break;
|
|
}
|
|
|
|
strategy_free_tokens();
|
|
|
|
if(i == -1)
|
|
main_exit_program(EXIT_STRATEGY_ERROR,
|
|
"strategy_update_team_pre_match: none of the prematch conditions of strategy %s for team %s are fulfilled. remember that a strategy should contain an unconditional prematch.",
|
|
tm->strategy_sid, tm->name);
|
|
}
|
|
|
|
/** Get the strategy going with the sid. */
|
|
Strategy*
|
|
strategy_from_sid(const gchar *sid)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_from_sid\n");
|
|
#endif
|
|
|
|
gint i;
|
|
|
|
for(i=0;i<strategies->len;i++)
|
|
if(strcmp(g_array_index(strategies, Strategy, i).sid, sid) == 0)
|
|
return &g_array_index(strategies, Strategy, i);
|
|
|
|
main_exit_program(EXIT_STRATEGY_ERROR,
|
|
"strategy_from_sid: strategy '%s' not found.", sid);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** Add tokens that will be evaluated when checking
|
|
strategy conditions. */
|
|
void
|
|
strategy_set_tokens(const Team *tm, const Fixture *fixture)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_set_tokens\n");
|
|
#endif
|
|
|
|
const Fixture *fix = (fixture == NULL) ?
|
|
team_get_fixture(tm, FALSE) : fixture;
|
|
const Team *opp = (fix == NULL) ? NULL :
|
|
fix->teams[fix->teams[0] == tm];
|
|
|
|
token_strat[0] = g_ptr_array_new();
|
|
token_strat[1] = g_ptr_array_new();
|
|
|
|
if(opp == NULL)
|
|
return;
|
|
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_homeadv", &tokens),
|
|
misc_int_to_char(((fix->teams[0] == tm) ? 1 : -1) *
|
|
fix->home_advantage));
|
|
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_cup", &tokens),
|
|
misc_int_to_char(fix->clid >= ID_CUP_START));
|
|
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_avskilldiff", &tokens),
|
|
misc_int_to_char((gint)rint(team_get_average_skill(tm, FALSE) -
|
|
team_get_average_skill(opp, FALSE))));
|
|
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_opponent_skill", &tokens),
|
|
misc_int_to_char((gint)rint(team_get_average_skill(opp, FALSE))));
|
|
|
|
if(tm->clid < ID_CUP_START &&
|
|
opp->clid < ID_CUP_START)
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_team_layerdiff", &tokens),
|
|
misc_int_to_char(league_from_clid(tm->clid)->layer -
|
|
league_from_clid(opp->clid)->layer));
|
|
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_goals_to_win", &tokens),
|
|
misc_int_to_char(fixture_get_goals_to_win(fix, tm)));
|
|
}
|
|
|
|
/** Free the token arrays. */
|
|
void
|
|
strategy_free_tokens(void)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_free_tokens\n");
|
|
#endif
|
|
|
|
gint i;
|
|
|
|
for(i=0;i<token_strat[0]->len;i++)
|
|
{
|
|
g_free(g_ptr_array_index(token_strat[0], i));
|
|
g_free(g_ptr_array_index(token_strat[1], i));
|
|
}
|
|
|
|
g_ptr_array_free(token_strat[0], TRUE);
|
|
g_ptr_array_free(token_strat[1], TRUE);
|
|
}
|
|
|
|
/** Fill the necessary tokens during a live game. */
|
|
void
|
|
strategy_live_game_set_tokens(const LiveGame *match, gint team_idx)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_live_game_set_tokens\n");
|
|
#endif
|
|
|
|
gint tmp_int,
|
|
current_min = live_game_unit_get_minute(
|
|
&g_array_index(match->units, LiveGameUnit, match->units->len - 1));
|
|
const Team *tm = match->fix->teams[team_idx];
|
|
|
|
strategy_set_tokens(tm, match->fix);
|
|
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_subs_left", &tokens),
|
|
misc_int_to_char(match->subs_left[team_idx]));
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_num_def", &tokens),
|
|
misc_int_to_char(math_get_place(tm->structure, 3)));
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_num_mid", &tokens),
|
|
misc_int_to_char(math_get_place(tm->structure, 2)));
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_num_att", &tokens),
|
|
misc_int_to_char(math_get_place(tm->structure, 1)));
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_form", &tokens),
|
|
misc_int_to_char(tm->structure));
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_time", &tokens),
|
|
misc_int_to_char(
|
|
g_array_index(match->units, LiveGameUnit, match->units->len - 1).time));
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_minute", &tokens),
|
|
misc_int_to_char(current_min));
|
|
|
|
tmp_int = live_game_get_minutes_remaining(
|
|
&g_array_index(match->units, LiveGameUnit, match->units->len - 1));
|
|
|
|
if(tmp_int > 0)
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_minute_remaining", &tokens),
|
|
misc_int_to_char(tmp_int));
|
|
|
|
if(query_fixture_is_draw(match->fix))
|
|
tmp_int = 120 - current_min;
|
|
else
|
|
tmp_int = 90 - current_min;
|
|
|
|
if(tmp_int > 0)
|
|
misc_token_add(token_strat,
|
|
option_int("string_token_minute_total", &tokens),
|
|
misc_int_to_char(tmp_int));
|
|
}
|
|
|
|
/** Compare function for sorting the players when
|
|
looking for substitutes. */
|
|
gint
|
|
strategy_compare_players_sub(gconstpointer a,
|
|
gconstpointer b,
|
|
gpointer user_data)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_compare_players_sub\n");
|
|
#endif
|
|
|
|
gfloat skill1, skill2;
|
|
const Player *pl1 = *(const Player**)a;
|
|
const Player *pl2 = *(const Player**)b;
|
|
gint position = GPOINTER_TO_INT(user_data) % 10;
|
|
gint property = (GPOINTER_TO_INT(user_data) - position) / 10;
|
|
gint return_value = 0;
|
|
|
|
if(pl1->pos != pl2->pos &&
|
|
(pl1->pos == position || pl2->pos == position))
|
|
return_value = (pl1->pos == position) ? -1 : 1;
|
|
else
|
|
switch(property)
|
|
{
|
|
default:
|
|
g_warning("strategy_compare_players_sub: unknown property %d\n",
|
|
property);
|
|
return_value = 0;
|
|
break;
|
|
case STRAT_LINEUP_FITTEST:
|
|
return_value = misc_float_compare(pl1->fitness,
|
|
pl2->fitness);
|
|
break;
|
|
case STRAT_LINEUP_UNFITTEST:
|
|
return_value = misc_float_compare(pl2->fitness,
|
|
pl1->fitness);
|
|
break;
|
|
case STRAT_LINEUP_BEST:
|
|
skill1 = player_get_game_skill(pl1, TRUE, TRUE);
|
|
skill2 = player_get_game_skill(pl2, TRUE, TRUE);
|
|
return_value = misc_float_compare(skill1, skill2);
|
|
break;
|
|
case STRAT_LINEUP_WEAKEST:
|
|
skill1 = player_get_game_skill(pl1, TRUE, TRUE);
|
|
skill2 = player_get_game_skill(pl2, TRUE, TRUE);
|
|
return_value = misc_float_compare(skill2, skill1);
|
|
break;
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
/** Compare two player positions, taking into account the number
|
|
of players playing the position in the team. */
|
|
gint
|
|
strategy_compare_positions(gconstpointer a,
|
|
gconstpointer b,
|
|
gpointer user_data)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_compare_positions\n");
|
|
#endif
|
|
|
|
gint i, pos[4] = {0, 0, 0, 0};
|
|
gint pos1 = *(gint*)a,
|
|
pos2 = *(gint*)b;
|
|
const Team *tm = (const Team*)user_data;
|
|
|
|
for(i=0;i<11;i++)
|
|
if(player_of_idx_team(tm, i)->cskill > 0 &&
|
|
player_is_banned(player_of_idx_team(tm, i)) <= 0)
|
|
pos[player_of_idx_team(tm, i)->pos]++;
|
|
|
|
return misc_int_compare(pos[pos1], pos[pos2]);
|
|
}
|
|
|
|
/** Find an appropriate player to send out or in.
|
|
@param tm The team we work with.
|
|
@param position The position of the player we seek.
|
|
@param property According to which property to sort players.
|
|
@param sub_in Whether we look for a player to send in or out. */
|
|
gint
|
|
strategy_get_sub(const Team *tm, gint position,
|
|
gint property, gboolean sub_in)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_get_sub\n");
|
|
#endif
|
|
|
|
gint i, start = (sub_in) ? 11 : 0,
|
|
stop = (sub_in) ? tm->players->len : 11;
|
|
GPtrArray *players = g_ptr_array_new();
|
|
gint return_value = -1;
|
|
GArray *positions = g_array_new(FALSE, FALSE, sizeof(gint));
|
|
|
|
if(position < 90)
|
|
g_array_append_val(positions, position);
|
|
else
|
|
{
|
|
while(position >= 90)
|
|
{
|
|
i = math_get_place(position, 1);
|
|
g_array_append_val(positions, i);
|
|
position = (position - position % 10) / 10;
|
|
}
|
|
|
|
g_array_sort_with_data(positions,
|
|
(GCompareDataFunc)strategy_compare_positions,
|
|
(gpointer)tm);
|
|
}
|
|
|
|
for(i=start;i<stop;i++)
|
|
if(player_of_idx_team(tm, i)->cskill > 0 &&
|
|
query_misc_integer_is_in_g_array(
|
|
player_of_idx_team(tm, i)->pos, positions) &&
|
|
(i > 10 || player_is_banned(player_of_idx_team(tm, i)) <= 0))
|
|
g_ptr_array_add(players, (gpointer)player_of_idx_team(tm, i));
|
|
|
|
if(players->len == 0)
|
|
{
|
|
g_ptr_array_free(players, TRUE);
|
|
return -1;
|
|
}
|
|
|
|
g_ptr_array_sort_with_data(
|
|
players,
|
|
(GCompareDataFunc)strategy_compare_players_sub,
|
|
GINT_TO_POINTER(property * 10 + g_array_index(positions, gint, 0)));
|
|
|
|
return_value = ((Player*)g_ptr_array_index(players, 0))->id;
|
|
|
|
g_ptr_array_free(players, TRUE);
|
|
|
|
return return_value;
|
|
}
|
|
|
|
/** Apply the strategy actions specified to the given team. */
|
|
void
|
|
strategy_live_game_apply_action(LiveGame *match, gint team_idx,
|
|
const StrategyMatchAction *action)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_live_game_apply_action\n");
|
|
#endif
|
|
|
|
gint sub_in_id = -1, sub_out_id = -1;
|
|
Team *tm = match->fix->teams[team_idx];
|
|
gint old_form = tm->structure;
|
|
|
|
g_array_append_val(match->action_ids[team_idx], action->id);
|
|
|
|
if(action->style != -100 && tm->style != action->style)
|
|
{
|
|
tm->style = action->style;
|
|
live_game_event_team_change(team_idx,
|
|
LIVE_GAME_EVENT_STYLE_CHANGE_ALL_OUT_DEFEND +
|
|
tm->style + 2);
|
|
}
|
|
|
|
if((action->boost != -100 && tm->boost != action->boost) &&
|
|
(action->boost != 1 || !sett_int("int_opt_disable_boost_on")))
|
|
{
|
|
tm->boost = action->boost;
|
|
live_game_event_team_change(team_idx,
|
|
LIVE_GAME_EVENT_BOOST_CHANGE_ANTI +
|
|
tm->boost + 1);
|
|
}
|
|
|
|
if(action->sub_in_pos != -1 && match->subs_left[team_idx] > 0 &&
|
|
(action->sub_condition == NULL ||
|
|
misc_parse_condition(action->sub_condition, token_strat)))
|
|
{
|
|
sub_in_id = strategy_get_sub(tm, action->sub_in_pos,
|
|
action->sub_in_prop, TRUE);
|
|
sub_out_id = strategy_get_sub(tm, action->sub_out_pos,
|
|
action->sub_in_prop, FALSE);
|
|
|
|
if(sub_in_id > 0 && sub_out_id > 0)
|
|
{
|
|
player_swap(tm, player_id_index(tm, sub_out_id),
|
|
tm, player_id_index(tm, sub_in_id));
|
|
|
|
team_change_structure(tm, team_find_appropriate_structure(tm));
|
|
team_rearrange(tm);
|
|
|
|
live_game_event_substitution(team_idx, sub_in_id, sub_out_id);
|
|
|
|
if(tm->structure != old_form)
|
|
live_game_event_team_change(team_idx,
|
|
LIVE_GAME_EVENT_STRUCTURE_CHANGE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Take match actions specified in the team's strategy
|
|
if necessary. */
|
|
void
|
|
strategy_live_game_check(LiveGame *match, gint team_idx)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("strategy_live_game_check\n");
|
|
#endif
|
|
|
|
gint i;
|
|
Team *tm = match->fix->teams[team_idx];
|
|
const Strategy *strat = strategy_from_sid(tm->strategy_sid);
|
|
|
|
strategy_live_game_set_tokens(match, team_idx);
|
|
|
|
for(i=strat->match_action->len - 1; i >= 0; i--)
|
|
{
|
|
if((match->subs_left[team_idx] > 0 ||
|
|
g_array_index(strat->match_action,
|
|
StrategyMatchAction, i).sub_in_pos == -1) &&
|
|
!query_misc_integer_is_in_g_array(
|
|
g_array_index(strat->match_action, StrategyMatchAction, i).id,
|
|
match->action_ids[team_idx]) &&
|
|
(g_array_index(strat->match_action, StrategyMatchAction, i).condition == NULL ||
|
|
misc_parse_condition(
|
|
g_array_index(strat->match_action, StrategyMatchAction, i).condition,
|
|
token_strat)))
|
|
{
|
|
strategy_live_game_apply_action(
|
|
match, team_idx,
|
|
&g_array_index(strat->match_action, StrategyMatchAction, i));
|
|
break;
|
|
}
|
|
}
|
|
|
|
strategy_free_tokens();
|
|
}
|