2005-03-03 13:46:48 +01:00
|
|
|
#include "cup.h"
|
2005-04-13 15:01:59 +02:00
|
|
|
#include "fixture.h"
|
2004-12-30 17:48:19 +01:00
|
|
|
#include "free.h"
|
2005-03-09 14:10:28 +01:00
|
|
|
#include "game_gui.h"
|
2004-12-30 17:48:19 +01:00
|
|
|
#include "league.h"
|
|
|
|
#include "maths.h"
|
2005-03-08 09:25:46 +01:00
|
|
|
#include "misc.h"
|
2005-03-03 13:46:48 +01:00
|
|
|
#include "option.h"
|
2004-12-23 13:58:39 +01:00
|
|
|
#include "player.h"
|
2004-12-30 17:48:19 +01:00
|
|
|
#include "team.h"
|
2005-03-14 18:47:27 +01:00
|
|
|
#include "user.h"
|
2004-12-23 13:58:39 +01:00
|
|
|
|
2004-12-30 17:48:19 +01:00
|
|
|
/** Create and return a new player.
|
|
|
|
@param tm The team the player will belong to.
|
|
|
|
@param average_skill The average skill of the team.
|
|
|
|
The player's skill can deviate from this value by #CONSTANT_PLAYER_AVERAGE_SKILL_VARIANCE %
|
|
|
|
@return A newly created player. */
|
|
|
|
Player
|
2005-04-14 21:07:25 +02:00
|
|
|
player_new(Team *tm, gfloat average_skill, gboolean new_id)
|
2004-12-30 17:48:19 +01:00
|
|
|
{
|
|
|
|
gfloat skill_factor =
|
2005-03-03 13:46:48 +01:00
|
|
|
math_rnd(1 - const_float("float_player_average_skill_variance"),
|
|
|
|
1 + const_float("float_player_average_skill_variance"));
|
2005-03-25 21:18:35 +01:00
|
|
|
Player new;
|
2004-12-30 17:48:19 +01:00
|
|
|
|
|
|
|
new.name =
|
|
|
|
g_string_new(((GString*)g_ptr_array_index(player_names, math_rndi(0, player_names->len - 1)))->str);
|
2005-04-14 21:07:25 +02:00
|
|
|
new.id = (new_id) ? player_id_new : -1;
|
2004-12-30 17:48:19 +01:00
|
|
|
new.pos = player_get_position_from_structure(tm->structure, tm->players->len);
|
|
|
|
new.cpos = new.pos;
|
2005-03-13 16:46:15 +01:00
|
|
|
new.age = math_gauss_dist(const_float("float_player_age_lower"),
|
|
|
|
const_float("float_player_age_upper"));
|
2004-12-30 17:48:19 +01:00
|
|
|
new.peak_age =
|
2005-03-13 16:46:15 +01:00
|
|
|
math_rnd(const_float("float_player_peak_age_lower") +
|
|
|
|
(new.pos == PLAYER_POS_GOALIE) *
|
|
|
|
const_float("float_player_peak_age_goalie_addition"),
|
|
|
|
const_float("float_player_peak_age_upper") +
|
|
|
|
(new.pos == PLAYER_POS_GOALIE) *
|
|
|
|
const_float("float_player_peak_age_goalie_addition"));
|
|
|
|
|
|
|
|
new.skill = CLAMP(average_skill * skill_factor, 0,
|
|
|
|
const_float("float_player_max_skill"));
|
2004-12-30 17:48:19 +01:00
|
|
|
new.talent = player_new_talent(new.skill);
|
2005-03-03 13:46:48 +01:00
|
|
|
player_estimate_talent(&new);
|
2005-03-13 16:46:15 +01:00
|
|
|
|
|
|
|
if(new.peak_age - new.age > const_float("float_player_peak_age_diff_younger1") ||
|
|
|
|
new.peak_age - new.age < const_float("float_player_peak_age_diff_older1"))
|
2005-03-25 21:18:35 +01:00
|
|
|
new.skill = new.skill * (1 - const_float("float_player_skill_reduction1"));
|
2005-03-13 16:46:15 +01:00
|
|
|
else if(new.peak_age - new.age > const_float("float_player_peak_age_diff_younger2") ||
|
|
|
|
new.peak_age - new.age < const_float("float_player_peak_age_diff_peak_older"))
|
2005-03-25 21:18:35 +01:00
|
|
|
new.skill = new.skill * (1 - const_float("float_player_skill_reduction2"));
|
2005-03-13 16:46:15 +01:00
|
|
|
|
|
|
|
new.cskill = new.skill;
|
|
|
|
|
|
|
|
new.fitness = math_rnd(const_float("float_player_fitness_lower"),
|
|
|
|
const_float("float_player_fitness_upper"));
|
2005-01-09 21:21:22 +01:00
|
|
|
new.health = new.recovery = 0;
|
2004-12-30 17:48:19 +01:00
|
|
|
new.value = player_assign_value(&new);
|
|
|
|
new.wage = player_assign_wage(&new);
|
2005-03-13 16:46:15 +01:00
|
|
|
new.contract = math_rnd(const_float("float_player_contract_lower"),
|
|
|
|
const_float("float_player_contract_upper"));
|
|
|
|
new.lsu = math_rnd(const_float("float_player_lsu_lower"),
|
|
|
|
const_float("float_player_lsu_upper"));
|
2004-12-30 17:48:19 +01:00
|
|
|
new.cards = g_array_new(FALSE, FALSE, sizeof(PlayerCard));
|
2005-04-04 12:36:04 +02:00
|
|
|
new.games_goals = g_array_new(FALSE, FALSE, sizeof(PlayerGamesGoals));
|
2005-03-03 13:46:48 +01:00
|
|
|
|
2005-01-09 21:21:22 +01:00
|
|
|
new.team = tm;
|
2005-03-13 16:46:15 +01:00
|
|
|
new.participation = FALSE;
|
2005-03-25 11:54:54 +01:00
|
|
|
new.offers = 0;
|
2004-12-30 17:48:19 +01:00
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the appropriate position for the player with the given number.
|
|
|
|
The position depends on the team structure if the player number is < 11
|
|
|
|
and on some constants otherwise.
|
|
|
|
@param structure The team structure, something like 442 or 352.
|
|
|
|
@param player_number The number of the player within the team.
|
|
|
|
@return A new position for the player. */
|
|
|
|
gint
|
|
|
|
player_get_position_from_structure(gint structure, gint player_number)
|
|
|
|
{
|
|
|
|
gint position = -1;
|
|
|
|
gint bound[2] =
|
|
|
|
{math_get_place(structure, 3) + 1,
|
|
|
|
math_get_place(structure, 3) +
|
|
|
|
math_get_place(structure, 2) + 1};
|
|
|
|
|
|
|
|
if(player_number % 11 == 0)
|
|
|
|
position = PLAYER_POS_GOALIE;
|
|
|
|
else if(player_number < bound[0] ||
|
2005-03-03 13:46:48 +01:00
|
|
|
(player_number > 10 && player_number < const_int("int_player_pos_bound1")))
|
2004-12-30 17:48:19 +01:00
|
|
|
position = PLAYER_POS_DEFENDER;
|
|
|
|
else if(player_number < bound[1] ||
|
2005-03-03 13:46:48 +01:00
|
|
|
(player_number > 10 && player_number < const_int("int_player_pos_bound2")))
|
2004-12-30 17:48:19 +01:00
|
|
|
position = PLAYER_POS_MIDFIELDER;
|
|
|
|
else
|
|
|
|
position = PLAYER_POS_FORWARD;
|
|
|
|
|
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Calculate the talent value of the player based on his skill.
|
|
|
|
@param skill The player's skill.
|
|
|
|
@return The new talent value. */
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat
|
|
|
|
player_new_talent(gfloat skill)
|
2004-12-30 17:48:19 +01:00
|
|
|
{
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat talent = math_gauss_dist(2 * skill - const_float("float_player_max_skill"),
|
|
|
|
const_float("float_player_max_skill"));
|
2004-12-30 17:48:19 +01:00
|
|
|
if(talent < skill)
|
|
|
|
talent = 2 * skill - talent;
|
|
|
|
|
|
|
|
return talent;
|
|
|
|
}
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
/** Estimate a player's talent.
|
|
|
|
@param pl The player of which we'd like to estimate the talent. */
|
|
|
|
void
|
|
|
|
player_estimate_talent(Player *pl)
|
2004-12-30 17:48:19 +01:00
|
|
|
{
|
2005-03-03 13:46:48 +01:00
|
|
|
gint i, j;
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat scout_deviance[QUALITY_END];
|
2004-12-30 17:48:19 +01:00
|
|
|
|
|
|
|
/* the maximal deviance in both directions */
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat deviance_bound[2] =
|
|
|
|
{pl->talent - pl->skill, const_float("float_player_max_skill") - pl->talent};
|
2004-12-30 17:48:19 +01:00
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
for(i=0;i<QUALITY_END;i++)
|
|
|
|
{
|
2005-03-19 21:04:08 +01:00
|
|
|
scout_deviance[i] = (i + 1) * const_float("float_player_max_skill") *
|
|
|
|
(const_float("float_player_etal_scout_factor") / 100);
|
2005-03-03 13:46:48 +01:00
|
|
|
/* adjust deviance_bounds with regard to the scout's
|
|
|
|
deviance */
|
|
|
|
for(j=0;j<2;j++)
|
|
|
|
deviance_bound[j] = MIN(deviance_bound[j], scout_deviance[i]);
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
pl->etal[i] = math_rnd(pl->talent - deviance_bound[0],
|
|
|
|
pl->talent + deviance_bound[1]);
|
2005-03-03 13:46:48 +01:00
|
|
|
}
|
2004-12-30 17:48:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Assign a (transfer) value to a player. The value depends on skill,
|
|
|
|
talent and age.
|
|
|
|
@param pl The player we examine.
|
|
|
|
@return The value of the player. */
|
|
|
|
gint
|
|
|
|
player_assign_value(const Player *pl)
|
|
|
|
{
|
|
|
|
gint value;
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat diff = pl->peak_age - pl->age;
|
2004-12-30 17:48:19 +01:00
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
value = (gint)powf((const_float("float_player_value_skill_weight") * pl->skill +
|
|
|
|
(1 - const_float("float_player_value_skill_weight")) * pl->talent * 0.7),
|
2005-03-03 13:46:48 +01:00
|
|
|
const_float("float_player_value_power"));
|
2005-03-13 16:46:15 +01:00
|
|
|
|
|
|
|
if(diff > const_float("float_player_peak_age_diff_older1"))
|
|
|
|
value = (gint)rint((gfloat)value * (1 - const_float("float_player_value_scale1")));
|
|
|
|
else if(diff > const_float("float_player_peak_age_diff_peak_older"))
|
|
|
|
value = (gint)rint((gfloat)value * (1 - const_float("float_player_value_scale2")));
|
|
|
|
else if(diff < const_float("float_player_peak_age_diff_younger1"))
|
|
|
|
value = (gint)rint((gfloat)value * (1 + const_float("float_player_value_scale1")));
|
|
|
|
else if(diff < const_float("float_player_peak_age_diff_younger2"))
|
|
|
|
value = (gint)rint((gfloat)value * (1 + const_float("float_player_value_scale2")));
|
2004-12-30 17:48:19 +01:00
|
|
|
|
|
|
|
value = math_round_integer(value, 2);
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2005-03-14 10:29:39 +01:00
|
|
|
/** Assign a wage to a player. The wage depends mainly on
|
|
|
|
the value.
|
2004-12-30 17:48:19 +01:00
|
|
|
@param pl The player we examine.
|
|
|
|
@return The wage of the player. */
|
|
|
|
gint
|
|
|
|
player_assign_wage(const Player *pl)
|
|
|
|
{
|
|
|
|
gfloat wage;
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
wage = rint(((gfloat)pl->value * const_float("float_player_wage_value_factor")) *
|
|
|
|
math_rnd(1 - const_float("float_player_wage_random_dev"),
|
|
|
|
1 + const_float("float_player_wage_random_dev") ));
|
2004-12-30 17:48:19 +01:00
|
|
|
|
|
|
|
return math_round_integer((gint)wage, 1);
|
|
|
|
}
|
|
|
|
|
2005-03-08 09:25:46 +01:00
|
|
|
/** Get a player's index in the players array from
|
|
|
|
his id.
|
|
|
|
@param tm The team.
|
|
|
|
@param player_id The player's id.
|
|
|
|
@return The array index or -1. */
|
2005-01-09 21:21:22 +01:00
|
|
|
gint
|
2005-03-08 09:25:46 +01:00
|
|
|
player_id_index(const Team *tm, gint player_id)
|
2005-01-09 21:21:22 +01:00
|
|
|
{
|
2005-03-08 09:25:46 +01:00
|
|
|
gint i;
|
2005-01-09 21:21:22 +01:00
|
|
|
|
2005-03-08 09:25:46 +01:00
|
|
|
for(i=0;i<tm->players->len;i++)
|
2005-04-13 15:01:59 +02:00
|
|
|
if(g_array_index(tm->players, Player, i).id == player_id)
|
2005-03-08 09:25:46 +01:00
|
|
|
return i;
|
|
|
|
|
|
|
|
g_warning("player_id_index: didn't find player with id %d of team %s\n", player_id, tm->name->str);
|
|
|
|
|
|
|
|
return -1;
|
2005-01-09 21:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a pointer to the number'th player of the team.
|
|
|
|
@param tm The team.
|
|
|
|
@param number The player number.
|
|
|
|
@return A pointer to the player or NULL. */
|
|
|
|
Player*
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(const Team *tm, gint number)
|
2005-01-09 21:21:22 +01:00
|
|
|
{
|
|
|
|
if(tm->players->len <= number)
|
|
|
|
{
|
2005-04-13 15:01:59 +02:00
|
|
|
g_warning("player_of_idx_team: Player list of team %s too short for number %d.\n",
|
2005-01-09 21:21:22 +01:00
|
|
|
tm->name->str, number);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &g_array_index(tm->players, Player, number);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Return a pointer to the player with specified id of the team.
|
|
|
|
@param tm The team.
|
|
|
|
@param id The player's id.
|
|
|
|
@return A pointer to the player or NULL. */
|
|
|
|
Player*
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_id_team(const Team *tm, gint id)
|
2005-01-09 21:21:22 +01:00
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
for(i=0;i<tm->players->len;i++)
|
|
|
|
if(g_array_index(tm->players, Player, i).id == id)
|
|
|
|
return &g_array_index(tm->players, Player, i);
|
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
g_warning("player_of_id_team: didn't find player with id %d of team %s\n", id, tm->name->str);
|
2005-01-09 21:21:22 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-03-03 13:46:48 +01:00
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
/** Return the team the player with specified id is in. */
|
|
|
|
Team*
|
|
|
|
player_id_team(gint player_id)
|
|
|
|
{
|
|
|
|
gint i, j, k;
|
|
|
|
|
|
|
|
for(i=0;i<ligs->len;i++)
|
|
|
|
for(j=0;j<lig(i).teams->len;j++)
|
|
|
|
for(k=0;k<g_array_index(lig(i).teams, Team, j).players->len;k++)
|
|
|
|
if(g_array_index(g_array_index(lig(i).teams, Team, j).players,
|
|
|
|
Player, k).id == player_id)
|
|
|
|
return &g_array_index(lig(i).teams, Team, j);
|
|
|
|
|
|
|
|
for(i=0;i<cps->len;i++)
|
|
|
|
for(j=0;j<cp(i).teams->len;j++)
|
|
|
|
for(k=0;k<g_array_index(cp(i).teams, Team, j).players->len;k++)
|
|
|
|
if(g_array_index(g_array_index(cp(i).teams, Team, j).players,
|
|
|
|
Player, k).id == player_id)
|
|
|
|
return &g_array_index(cp(i).teams, Team, j);
|
|
|
|
|
|
|
|
g_warning("player_id_team: player with id %d not found.\n", player_id);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-08 09:25:46 +01:00
|
|
|
/** Return the number of all games or goals the player's
|
|
|
|
participated in / scored in all cups and leagues.
|
|
|
|
@param pl The player we examine.
|
|
|
|
@param goals Whether we sum up the goals.
|
|
|
|
@return The number of goals. */
|
|
|
|
gint
|
|
|
|
player_all_games_goals(const Player *pl, gint type)
|
|
|
|
{
|
|
|
|
gint i, sum = 0;
|
|
|
|
|
|
|
|
for(i=0;i<pl->games_goals->len;i++)
|
2005-03-13 16:46:15 +01:00
|
|
|
if(type == PLAYER_VALUE_GOALS)
|
2005-03-08 09:25:46 +01:00
|
|
|
sum += g_array_index(pl->games_goals, PlayerGamesGoals, i).goals;
|
2005-03-13 16:46:15 +01:00
|
|
|
else if(type == PLAYER_VALUE_GAMES)
|
2005-03-08 09:25:46 +01:00
|
|
|
sum += g_array_index(pl->games_goals, PlayerGamesGoals, i).games;
|
2005-03-13 16:46:15 +01:00
|
|
|
else if(type == PLAYER_VALUE_SHOTS)
|
2005-03-08 09:25:46 +01:00
|
|
|
sum += g_array_index(pl->games_goals, PlayerGamesGoals, i).shots;
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the sum of all the yellow cards in all
|
|
|
|
leagues and cups for the player.
|
|
|
|
@param pl The player we examine.
|
|
|
|
@return The number of all cards.*/
|
|
|
|
gint
|
|
|
|
player_all_cards(const Player *pl)
|
|
|
|
{
|
|
|
|
gint i, sum = 0;
|
|
|
|
|
|
|
|
for(i=0;i<pl->cards->len;i++)
|
|
|
|
sum += g_array_index(pl->cards, PlayerCard, i).yellow;
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
2005-03-18 23:03:23 +01:00
|
|
|
/** Compare two players in a (pointer) array.
|
2005-03-03 13:46:48 +01:00
|
|
|
@param pl1 Pointer to the pointer to the first player.
|
|
|
|
@param pl2 Pointer to the pointer to the second player.
|
2005-03-08 09:25:46 +01:00
|
|
|
@param data Coded integer that tells us which attribute to compare.
|
|
|
|
@return 1, 0 or -1 (see the C qsort() function). */
|
2005-03-03 13:46:48 +01:00
|
|
|
gint
|
|
|
|
player_compare_func(gconstpointer a, gconstpointer b, gpointer data)
|
|
|
|
{
|
2005-03-09 14:10:28 +01:00
|
|
|
gint type = GPOINTER_TO_INT(data) % 100;
|
|
|
|
const Player *pl1 = (GPOINTER_TO_INT(data) < 100) ?
|
|
|
|
*(const Player**)a : (const Player*)a;
|
|
|
|
const Player *pl2 = (GPOINTER_TO_INT(data) < 100) ?
|
|
|
|
*(const Player**)b : (const Player*)b;
|
2005-03-03 13:46:48 +01:00
|
|
|
gint return_value = 0;
|
|
|
|
|
|
|
|
if(type == PLAYER_COMPARE_ATTRIBUTE_GAME_SKILL)
|
2005-03-08 09:25:46 +01:00
|
|
|
return_value =
|
2005-03-09 14:10:28 +01:00
|
|
|
misc_float_compare(player_get_game_skill(pl1, FALSE),
|
|
|
|
player_get_game_skill(pl2, FALSE));
|
|
|
|
else if(type == PLAYER_COMPARE_ATTRIBUTE_POS)
|
|
|
|
{
|
|
|
|
if(MIN(player_id_index(pl1->team, pl1->id), player_id_index(pl2->team, pl2->id)) < 11 &&
|
|
|
|
MAX(player_id_index(pl1->team, pl1->id), player_id_index(pl2->team, pl2->id)) >= 11)
|
|
|
|
return_value =
|
|
|
|
(player_id_index(pl1->team, pl1->id) > player_id_index(pl2->team, pl2->id)) ?
|
|
|
|
1 : -1;
|
|
|
|
else if(pl1->cskill == 0)
|
|
|
|
return_value = (pl2->cskill == 0) ? 0 : 1;
|
|
|
|
else if(pl2->cskill == 0)
|
|
|
|
return_value = (pl1->cskill == 0) ? 0 : -1;
|
|
|
|
else if(pl2->pos != pl1->pos)
|
|
|
|
return_value = misc_int_compare(pl2->pos, pl1->pos);
|
|
|
|
else
|
2005-03-13 16:46:15 +01:00
|
|
|
return_value = 0;
|
|
|
|
/* return_value = */
|
|
|
|
/* misc_float_compare(player_get_game_skill(pl1, TRUE), */
|
|
|
|
/* player_get_game_skill(pl2, TRUE)); */
|
2005-03-09 14:10:28 +01:00
|
|
|
}
|
2005-03-08 09:25:46 +01:00
|
|
|
|
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Compare two players in a pointer array.
|
|
|
|
@param pl1 Pointer to the pointer to the first player.
|
|
|
|
@param pl2 Pointer to the pointer to the second player.
|
|
|
|
@param data Coded integer that tells us which position we
|
|
|
|
would like to substitute.
|
|
|
|
@return 1, 0 or -1 (see the C qsort() function). */
|
|
|
|
gint
|
|
|
|
player_compare_substitute_func(gconstpointer a, gconstpointer b, gpointer data)
|
|
|
|
{
|
|
|
|
const Player *pl1 = *(const Player**)a;
|
|
|
|
const Player *pl2 = *(const Player**)b;
|
|
|
|
gint position = GPOINTER_TO_INT(data);
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat skill_for_pos1 = player_get_cskill(pl1, position) *
|
|
|
|
powf(pl1->fitness, const_float("float_player_fitness_exponent")),
|
|
|
|
skill_for_pos2 = player_get_cskill(pl2, position) *
|
|
|
|
powf(pl2->fitness, const_float("float_player_fitness_exponent"));
|
|
|
|
gfloat game_skill1 = player_get_game_skill(pl1, FALSE),
|
|
|
|
game_skill2 = player_get_game_skill(pl2, FALSE);
|
2005-03-08 09:25:46 +01:00
|
|
|
gboolean good_structure1 =
|
|
|
|
player_substitution_good_structure(pl1->team->structure, position, pl1->pos),
|
|
|
|
good_structure2 =
|
|
|
|
player_substitution_good_structure(pl2->team->structure, position, pl2->pos);
|
|
|
|
gint return_value = 0;
|
|
|
|
|
|
|
|
if(pl1->pos == position && pl2->pos == position)
|
|
|
|
return_value =
|
2005-03-13 16:46:15 +01:00
|
|
|
misc_float_compare(game_skill1, game_skill2);
|
2005-03-08 09:25:46 +01:00
|
|
|
else if(pl1->pos == position)
|
|
|
|
return_value = -1;
|
|
|
|
else if(pl2->pos == position)
|
|
|
|
return_value = 1;
|
|
|
|
else if(position != PLAYER_POS_GOALIE)
|
2005-03-03 13:46:48 +01:00
|
|
|
{
|
2005-03-08 09:25:46 +01:00
|
|
|
if(good_structure1 && good_structure2)
|
|
|
|
return_value =
|
2005-03-13 16:46:15 +01:00
|
|
|
misc_float_compare(game_skill1, game_skill2);
|
2005-03-08 09:25:46 +01:00
|
|
|
else if(good_structure1)
|
|
|
|
return_value =
|
2005-03-13 16:46:15 +01:00
|
|
|
misc_float_compare(game_skill1, skill_for_pos2);
|
2005-03-08 09:25:46 +01:00
|
|
|
else if(good_structure2)
|
|
|
|
return_value =
|
2005-03-13 16:46:15 +01:00
|
|
|
misc_float_compare(skill_for_pos1, game_skill2);
|
2005-03-03 13:46:48 +01:00
|
|
|
else
|
2005-03-08 09:25:46 +01:00
|
|
|
return_value =
|
2005-03-13 16:46:15 +01:00
|
|
|
misc_float_compare(skill_for_pos1, skill_for_pos2);
|
2005-03-03 13:46:48 +01:00
|
|
|
}
|
2005-03-08 09:25:46 +01:00
|
|
|
else
|
|
|
|
return_value =
|
2005-03-13 16:46:15 +01:00
|
|
|
misc_float_compare(skill_for_pos1, skill_for_pos2);
|
2005-03-08 09:25:46 +01:00
|
|
|
|
|
|
|
/* printf("%s %d %s %d %d\n", pl1->name->str, pl1->pos, pl2->name->str, */
|
|
|
|
/* pl2->pos, return_value); */
|
|
|
|
/* printf("\t gaski %.1f %.1f skipos %.1f %.1f struc %d %d\n", */
|
|
|
|
/* (gfloat)game_skill1 / 10000, (gfloat)game_skill2 / 10000, */
|
|
|
|
/* (gfloat)skill_for_pos1 / 10000, (gfloat)skill_for_pos2 / 10000, */
|
|
|
|
/* good_structure1, good_structure2); */
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
|
2005-03-08 09:25:46 +01:00
|
|
|
/** Find out whether substituting a player into a team
|
|
|
|
and adapting the team structure results in a normal
|
|
|
|
structure.
|
|
|
|
@param old_structure The team's structure before substituting.
|
|
|
|
@param old_pos The position of the player that gets replaced.
|
|
|
|
@param player_pos The position of the player that comes into the game.
|
|
|
|
@return TRUE or FALSE. */
|
|
|
|
gboolean
|
|
|
|
player_substitution_good_structure(gint old_structure, gint old_pos, gint player_pos)
|
|
|
|
{
|
|
|
|
gint accepted_structures[5] = {532, 442, 352, 433, 343};
|
|
|
|
gint new_structure =
|
|
|
|
old_structure - (gint)rint(powf(10, PLAYER_POS_FORWARD - old_pos)) +
|
|
|
|
(gint)rint(powf(10, PLAYER_POS_FORWARD - player_pos));
|
|
|
|
|
|
|
|
return query_integer_is_in_array(new_structure, accepted_structures, 0, 5);
|
|
|
|
}
|
|
|
|
|
2005-03-20 21:49:55 +01:00
|
|
|
/** Copy a player into a team.
|
|
|
|
@param pl The player.
|
|
|
|
@param tm The dest team.
|
|
|
|
@param insert_at The new index of the player in the players array. */
|
|
|
|
void
|
|
|
|
player_copy(Player *pl, Team *tm, gint insert_at)
|
|
|
|
{
|
|
|
|
Player new = *pl;
|
|
|
|
|
|
|
|
new.team = tm;
|
|
|
|
|
|
|
|
g_array_insert_val(tm->players, insert_at, new);
|
|
|
|
|
|
|
|
if(insert_at < 11)
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm, insert_at)->cpos =
|
2005-03-20 21:49:55 +01:00
|
|
|
player_get_position_from_structure(tm->structure, insert_at);
|
|
|
|
else
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm, insert_at)->cpos = player_of_idx_team(tm, insert_at)->pos;
|
2005-03-20 21:49:55 +01:00
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm, insert_at)->cskill =
|
|
|
|
player_get_cskill(player_of_idx_team(tm, insert_at),
|
|
|
|
player_of_idx_team(tm, insert_at)->cpos);
|
2005-03-20 21:49:55 +01:00
|
|
|
}
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
/** Move a player from one player array to another one.
|
|
|
|
@param tm1 The source team.
|
|
|
|
@param player_number The index of the player in the players array.
|
|
|
|
@param tm2 The dest team.
|
|
|
|
@param insert_at The new index of the player in the players array. */
|
|
|
|
void
|
|
|
|
player_move(Team *tm1, gint player_number, Team *tm2, gint insert_at)
|
|
|
|
{
|
2005-04-13 15:01:59 +02:00
|
|
|
Player pl = *player_of_idx_team(tm1, player_number);
|
2005-03-03 13:46:48 +01:00
|
|
|
|
|
|
|
pl.team = tm2;
|
|
|
|
|
|
|
|
g_array_remove_index(tm1->players, player_number);
|
|
|
|
|
|
|
|
g_array_insert_val(tm2->players, insert_at, pl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Swap two players. */
|
|
|
|
void
|
|
|
|
player_swap(Team *tm1, gint player_number1, Team *tm2, gint player_number2)
|
|
|
|
{
|
|
|
|
gint move = (tm1 == tm2 && player_number1 < player_number2) ?
|
|
|
|
-1 : 1;
|
|
|
|
|
2005-03-09 14:10:28 +01:00
|
|
|
if(stat0 == STATUS_LIVE_GAME_PAUSE)
|
|
|
|
{
|
2005-04-23 12:39:46 +02:00
|
|
|
if((player_number1 < 11 && player_is_banned(player_of_idx_team(tm1, player_number1)) > 0) ||
|
|
|
|
(player_number2 < 11 && player_is_banned(player_of_idx_team(tm1, player_number2)) > 0))
|
2005-03-09 14:10:28 +01:00
|
|
|
{
|
|
|
|
game_gui_show_warning("You can't replace a banned player.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
player_move(tm1, player_number1, tm2, player_number2);
|
|
|
|
if(player_number2 < 11)
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm2, player_number2)->cpos =
|
2005-03-03 13:46:48 +01:00
|
|
|
player_get_position_from_structure(tm2->structure, player_number2);
|
|
|
|
else
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm2, player_number2)->cpos = player_of_idx_team(tm2, player_number2)->pos;
|
2005-03-08 09:25:46 +01:00
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm2, player_number2)->cskill =
|
|
|
|
player_get_cskill(player_of_idx_team(tm2, player_number2), player_of_idx_team(tm2, player_number2)->cpos);
|
2005-03-03 13:46:48 +01:00
|
|
|
|
|
|
|
player_move(tm2, player_number2 + move,
|
|
|
|
tm1, player_number1);
|
|
|
|
if(player_number1 < 11)
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm1, player_number1)->cpos =
|
2005-03-03 13:46:48 +01:00
|
|
|
player_get_position_from_structure(tm1->structure, player_number1);
|
|
|
|
else
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm1, player_number1)->cpos = player_of_idx_team(tm1, player_number1)->pos;
|
2005-03-08 09:25:46 +01:00
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm1, player_number1)->cskill =
|
|
|
|
player_get_cskill(player_of_idx_team(tm1, player_number1), player_of_idx_team(tm1, player_number1)->cpos);
|
2005-03-03 13:46:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the player's cskill depending on
|
|
|
|
whether he's on his normal position or not.
|
|
|
|
@param pl The player we examine.
|
2005-03-08 09:25:46 +01:00
|
|
|
@param position The position we's like to put the player.
|
2005-03-03 13:46:48 +01:00
|
|
|
@return A new cskill. */
|
2005-03-13 16:46:15 +01:00
|
|
|
gfloat
|
2005-03-08 09:25:46 +01:00
|
|
|
player_get_cskill(const Player *pl, gint position)
|
2005-03-03 13:46:48 +01:00
|
|
|
{
|
|
|
|
gfloat cskill_factor;
|
|
|
|
|
|
|
|
if(pl->health != PLAYER_INJURY_NONE ||
|
|
|
|
player_is_banned(pl) > 0)
|
2005-03-08 09:25:46 +01:00
|
|
|
return 0;
|
2005-03-03 13:46:48 +01:00
|
|
|
|
2005-03-08 09:25:46 +01:00
|
|
|
if(pl->pos != position)
|
|
|
|
{
|
|
|
|
if(position == PLAYER_POS_GOALIE ||
|
|
|
|
pl->pos == PLAYER_POS_GOALIE)
|
|
|
|
cskill_factor = 0.5;
|
|
|
|
else if(abs(position - pl->pos) == 2)
|
|
|
|
cskill_factor = 0.65;
|
|
|
|
else
|
|
|
|
cskill_factor = 0.75;
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
return MIN(pl->talent * cskill_factor, pl->skill);
|
2005-03-08 09:25:46 +01:00
|
|
|
}
|
2005-03-03 13:46:48 +01:00
|
|
|
else
|
2005-03-08 09:25:46 +01:00
|
|
|
return pl->skill;
|
2005-03-03 13:46:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Find out whether the player is banned in
|
|
|
|
the next match or whether he will be if he
|
|
|
|
gets a yellow card.
|
|
|
|
@param pl The player we examine.
|
|
|
|
@return Number of games banned, or 0 if not banned, or -1
|
|
|
|
if yellow. */
|
|
|
|
gint
|
|
|
|
player_is_banned(const Player *pl)
|
|
|
|
{
|
2005-03-14 18:47:27 +01:00
|
|
|
Fixture *fix = team_get_fixture(pl->team, FALSE);
|
2005-03-13 16:46:15 +01:00
|
|
|
gint yellow_red = -1, yellow, red;
|
2005-03-03 13:46:48 +01:00
|
|
|
|
|
|
|
if(fix == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(fix->clid < ID_CUP_START)
|
|
|
|
yellow_red = league_from_clid(fix->clid)->yellow_red;
|
|
|
|
else
|
|
|
|
yellow_red = cup_from_clid(fix->clid)->yellow_red;
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
yellow = player_card_get(pl, fix->clid, PLAYER_VALUE_CARD_YELLOW);
|
|
|
|
red = player_card_get(pl, fix->clid, PLAYER_VALUE_CARD_RED);
|
2005-03-03 13:46:48 +01:00
|
|
|
|
2005-03-10 21:59:39 +01:00
|
|
|
if(red > 0)
|
|
|
|
return red;
|
|
|
|
|
|
|
|
if(yellow == yellow_red - 1)
|
|
|
|
return -1;
|
2005-03-03 13:46:48 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2005-03-09 14:10:28 +01:00
|
|
|
|
|
|
|
/** Return the player's skill contribution to his team.
|
|
|
|
@param pl The player.
|
|
|
|
@param skill Whether to take his skill or current skill into account.
|
|
|
|
@return A float value representing the player's contribution. */
|
|
|
|
gfloat
|
|
|
|
player_get_game_skill(const Player *pl, gboolean skill)
|
|
|
|
{
|
|
|
|
if(skill)
|
2005-03-13 16:46:15 +01:00
|
|
|
return pl->skill * powf(pl->fitness, const_float("float_player_fitness_exponent"));
|
2005-03-09 14:10:28 +01:00
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
return pl->cskill * powf(pl->fitness, const_float("float_player_fitness_exponent"));
|
2005-03-09 14:10:28 +01:00
|
|
|
}
|
2005-03-09 15:02:49 +01:00
|
|
|
|
|
|
|
/** Decrease a player's fitness during a match.
|
|
|
|
@param pl The player. */
|
|
|
|
void
|
|
|
|
player_decrease_fitness(Player *pl)
|
|
|
|
{
|
2005-03-13 16:46:15 +01:00
|
|
|
gint i;
|
|
|
|
gint age_limits[7] = {const_float("float_player_peak_age_diff_younger1"),
|
|
|
|
const_float("float_player_peak_age_diff_younger2"),
|
|
|
|
const_float("float_player_peak_age_diff_younger3"),
|
|
|
|
const_float("float_player_peak_age_diff_peak_younger"),
|
|
|
|
const_float("float_player_peak_age_diff_peak_older"),
|
|
|
|
const_float("float_player_peak_age_diff_older1"),
|
|
|
|
const_float("float_player_peak_age_diff_older2")};
|
|
|
|
gfloat reduce[8] =
|
|
|
|
{const_float("float_player_fitness_decrease_younger1"),
|
|
|
|
const_float("float_player_fitness_decrease_younger2"),
|
|
|
|
const_float("float_player_fitness_decrease_younger3"),
|
|
|
|
const_float("float_player_fitness_decrease_peak_younger"),
|
|
|
|
const_float("float_player_fitness_decrease_peak_older"),
|
|
|
|
const_float("float_player_fitness_decrease_older1"),
|
|
|
|
const_float("float_player_fitness_decrease_older2"),
|
|
|
|
const_float("float_player_fitness_decrease_else")};
|
|
|
|
|
|
|
|
gfloat diff = pl->peak_age - pl->age;
|
|
|
|
gfloat reduction;
|
2005-03-09 15:02:49 +01:00
|
|
|
|
|
|
|
for(i=0;i<7;i++)
|
|
|
|
if(diff > age_limits[i])
|
|
|
|
break;
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
reduction = reduce[i] * (1 + (gfloat)pl->team->boost * const_float("float_player_boost_fitness_effect")) *
|
|
|
|
(1 - (pl->cpos == 0) * const_float("float_player_fitness_decrease_factor_goalie"));
|
2005-03-10 21:59:39 +01:00
|
|
|
|
|
|
|
pl->fitness = MAX(0, pl->fitness - reduction);
|
|
|
|
}
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
|
|
|
|
/** Increase of player fitness after a match.
|
|
|
|
Depends on the decrease values and the
|
|
|
|
percentage values that determine how much of the
|
|
|
|
decrease a player gains.
|
|
|
|
@param pl The player we edit. */
|
|
|
|
void
|
|
|
|
player_update_fitness(Player *pl)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
gint age_limits[7] = {const_float("float_player_peak_age_diff_younger1"),
|
|
|
|
const_float("float_player_peak_age_diff_younger2"),
|
|
|
|
const_float("float_player_peak_age_diff_younger3"),
|
|
|
|
const_float("float_player_peak_age_diff_peak_younger"),
|
|
|
|
const_float("float_player_peak_age_diff_peak_older"),
|
|
|
|
const_float("float_player_peak_age_diff_older1"),
|
|
|
|
const_float("float_player_peak_age_diff_older2")};
|
|
|
|
gfloat increase_base[8] =
|
|
|
|
{const_float("float_player_fitness_increase_younger1"),
|
|
|
|
const_float("float_player_fitness_increase_younger2"),
|
|
|
|
const_float("float_player_fitness_increase_younger3"),
|
|
|
|
const_float("float_player_fitness_increase_peak_younger"),
|
|
|
|
const_float("float_player_fitness_increase_peak_older"),
|
|
|
|
const_float("float_player_fitness_increase_older1"),
|
|
|
|
const_float("float_player_fitness_increase_older2"),
|
|
|
|
const_float("float_player_fitness_increase_else")};
|
|
|
|
|
|
|
|
gfloat diff = pl->peak_age - pl->age;
|
|
|
|
gfloat increase = -1;
|
|
|
|
|
|
|
|
if(pl->participation)
|
2005-04-09 21:18:28 +02:00
|
|
|
{
|
|
|
|
pl->participation = FALSE;
|
2005-03-13 16:46:15 +01:00
|
|
|
return;
|
2005-04-09 21:18:28 +02:00
|
|
|
}
|
2005-03-13 16:46:15 +01:00
|
|
|
|
|
|
|
for(i=0;i<7;i++)
|
|
|
|
if(diff > age_limits[i])
|
|
|
|
break;
|
|
|
|
|
|
|
|
increase = math_rnd(increase_base[i] - const_float("float_player_fitness_increase_variance"),
|
|
|
|
increase_base[i] + const_float("float_player_fitness_increase_variance"));
|
|
|
|
|
|
|
|
pl->fitness = MIN(pl->fitness + increase, 1);
|
|
|
|
}
|
|
|
|
|
2005-03-10 21:59:39 +01:00
|
|
|
/** Return the number of yellow cards of a player
|
|
|
|
or the number of weeks banned.
|
|
|
|
@param pl The player.
|
|
|
|
@param clid The cup or league id.
|
|
|
|
@param card_type Whether red or yellow cards. */
|
|
|
|
gint
|
|
|
|
player_card_get(const Player *pl, gint clid, gint card_type)
|
|
|
|
{
|
|
|
|
gint i;
|
2005-03-13 16:46:15 +01:00
|
|
|
gint return_value = 0;
|
2005-03-10 21:59:39 +01:00
|
|
|
|
|
|
|
for(i=0;i<pl->cards->len;i++)
|
|
|
|
if(g_array_index(pl->cards, PlayerCard, i).clid == clid)
|
|
|
|
{
|
2005-03-13 16:46:15 +01:00
|
|
|
if(card_type == PLAYER_VALUE_CARD_YELLOW)
|
2005-03-10 21:59:39 +01:00
|
|
|
return_value = g_array_index(pl->cards, PlayerCard, i).yellow;
|
|
|
|
else
|
|
|
|
return_value = g_array_index(pl->cards, PlayerCard, i).red;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Change a card value for the player.
|
|
|
|
@param pl The player.
|
|
|
|
@param clid The cup or league id.
|
|
|
|
@param card_type Whether red or yellow card.
|
|
|
|
@param value The new value.
|
|
|
|
@param diff Whether we add the value to the old one or
|
|
|
|
replace the old value by the new one. */
|
|
|
|
void
|
|
|
|
player_card_set(Player *pl, gint clid, gint card_type, gint value, gboolean diff)
|
|
|
|
{
|
2005-03-13 16:46:15 +01:00
|
|
|
gint i, *card_value = NULL;
|
2005-03-10 21:59:39 +01:00
|
|
|
PlayerCard new;
|
|
|
|
|
|
|
|
for(i=0;i<pl->cards->len;i++)
|
|
|
|
if(g_array_index(pl->cards, PlayerCard, i).clid == clid)
|
|
|
|
{
|
2005-03-13 16:46:15 +01:00
|
|
|
if(card_type == PLAYER_VALUE_CARD_YELLOW)
|
2005-03-10 21:59:39 +01:00
|
|
|
card_value = &g_array_index(pl->cards, PlayerCard, i).yellow;
|
2005-03-13 16:46:15 +01:00
|
|
|
else if(card_type == PLAYER_VALUE_CARD_RED)
|
2005-03-10 21:59:39 +01:00
|
|
|
card_value = &g_array_index(pl->cards, PlayerCard, i).red;
|
|
|
|
|
|
|
|
if(diff)
|
|
|
|
*card_value += value;
|
|
|
|
else
|
|
|
|
*card_value = value;
|
|
|
|
|
|
|
|
if(*card_value < 0)
|
|
|
|
{
|
|
|
|
g_warning("player_card_set: negative card value; setting to 0\n");
|
|
|
|
*card_value = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new.clid = clid;
|
|
|
|
new.yellow = new.red = 0;
|
|
|
|
|
|
|
|
g_array_append_val(pl->cards, new);
|
|
|
|
|
|
|
|
player_card_set(pl, clid, card_type, value, diff);
|
2005-03-09 15:02:49 +01:00
|
|
|
}
|
2005-03-13 16:46:15 +01:00
|
|
|
|
|
|
|
/** Return the number of games or goals.
|
|
|
|
@param pl The player.
|
|
|
|
@param clid The cup or league id.
|
|
|
|
@param card_type Whether games or goals cards. */
|
|
|
|
gint
|
|
|
|
player_games_goals_get(const Player *pl, gint clid, gint type)
|
|
|
|
{
|
|
|
|
gint i, return_value = 0;
|
|
|
|
|
|
|
|
for(i=0;i<pl->games_goals->len;i++)
|
|
|
|
if(g_array_index(pl->games_goals, PlayerGamesGoals, i).clid == clid)
|
|
|
|
{
|
|
|
|
if(type == PLAYER_VALUE_GAMES)
|
|
|
|
return_value = g_array_index(pl->games_goals, PlayerGamesGoals, i).games;
|
|
|
|
else if(type == PLAYER_VALUE_GOALS)
|
|
|
|
return_value = g_array_index(pl->games_goals, PlayerGamesGoals, i).goals;
|
|
|
|
else if(type == PLAYER_VALUE_SHOTS)
|
|
|
|
return_value = g_array_index(pl->games_goals, PlayerGamesGoals, i).shots;
|
2005-03-18 23:03:23 +01:00
|
|
|
else
|
|
|
|
g_warning("player_games_goals_get: unknown type %d.\n", type);
|
2005-03-13 16:46:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Change a card value for the player.
|
|
|
|
@param pl The player.
|
|
|
|
@param clid The cup or league id.
|
|
|
|
@param type Whether games or goals or shots.
|
|
|
|
@param value The new value.
|
|
|
|
@param diff Whether we add the value to the old one or
|
|
|
|
replace the old value by the new one. */
|
|
|
|
void
|
|
|
|
player_games_goals_set(Player *pl, gint clid, gint type, gint value, gboolean diff)
|
|
|
|
{
|
|
|
|
gint i, *games_goals_value = NULL;
|
|
|
|
PlayerGamesGoals new;
|
|
|
|
|
|
|
|
for(i=0;i<pl->games_goals->len;i++)
|
|
|
|
if(g_array_index(pl->games_goals, PlayerGamesGoals, i).clid == clid)
|
|
|
|
{
|
|
|
|
if(type == PLAYER_VALUE_GAMES)
|
|
|
|
games_goals_value = &g_array_index(pl->games_goals, PlayerGamesGoals, i).games;
|
|
|
|
else if(type == PLAYER_VALUE_GOALS)
|
|
|
|
games_goals_value = &g_array_index(pl->games_goals, PlayerGamesGoals, i).goals;
|
|
|
|
else if(type == PLAYER_VALUE_SHOTS)
|
|
|
|
games_goals_value = &g_array_index(pl->games_goals, PlayerGamesGoals, i).shots;
|
|
|
|
|
|
|
|
if(diff)
|
|
|
|
*games_goals_value += value;
|
|
|
|
else
|
|
|
|
*games_goals_value = value;
|
|
|
|
|
|
|
|
if(*games_goals_value < 0)
|
|
|
|
{
|
|
|
|
g_warning("player_games_goals_set: negative value; setting to 0\n");
|
|
|
|
*games_goals_value = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new.clid = clid;
|
|
|
|
new.games = new.goals = new.shots = 0;
|
|
|
|
|
|
|
|
g_array_append_val(pl->games_goals, new);
|
|
|
|
|
|
|
|
player_games_goals_set(pl, clid, type, value, diff);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Update skill and lsu of a user player.
|
|
|
|
@param pl The player we update. */
|
|
|
|
void
|
|
|
|
player_update_skill(Player *pl)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
gint age_limits[7] =
|
|
|
|
{const_float("float_player_peak_age_diff_younger1"),
|
|
|
|
const_float("float_player_peak_age_diff_younger2"),
|
|
|
|
const_float("float_player_peak_age_diff_younger3"),
|
|
|
|
const_float("float_player_peak_age_diff_peak_younger"),
|
|
|
|
const_float("float_player_peak_age_diff_peak_older"),
|
|
|
|
const_float("float_player_peak_age_diff_older1"),
|
|
|
|
const_float("float_player_peak_age_diff_older2")};
|
|
|
|
gfloat factor_limits[3][2] =
|
|
|
|
{{const_float("float_player_skill_devel_younger1_lower"),
|
|
|
|
const_float("float_player_skill_devel_younger1_upper")},
|
|
|
|
{const_float("float_player_skill_devel_younger2_lower"),
|
|
|
|
const_float("float_player_skill_devel_younger2_upper")},
|
|
|
|
{const_float("float_player_skill_devel_younger3_lower"),
|
|
|
|
const_float("float_player_skill_devel_younger3_upper")}};
|
|
|
|
gint increase_decrease[4][2] =
|
|
|
|
{{const_float("float_player_skill_devel_peak_lower"),
|
|
|
|
const_float("float_player_skill_devel_peak_upper")},
|
|
|
|
{const_float("float_player_skill_devel_older1_lower"),
|
|
|
|
const_float("float_player_skill_devel_older1_upper")},
|
|
|
|
{const_float("float_player_skill_devel_older2_lower"),
|
|
|
|
const_float("float_player_skill_devel_older2_upper")},
|
|
|
|
{const_float("float_player_skill_devel_else_lower"),
|
|
|
|
const_float("float_player_skill_devel_else_upper")}};
|
|
|
|
gfloat diff;
|
|
|
|
|
|
|
|
if(pl->age > pl->peak_age)
|
|
|
|
pl->lsu += (pl->health == 0) ? 1 : const_float("float_player_lsu_injured_old");
|
|
|
|
else if(pl->health == 0 &&
|
|
|
|
((gfloat)player_games_goals_get(pl, pl->team->clid, PLAYER_VALUE_GAMES) / (gfloat)week >=
|
|
|
|
const_float("float_player_lsu_games_percentage") ||
|
|
|
|
math_rnd(0, 1) <= const_float("float_player_lsu_increase_prob")))
|
|
|
|
pl->lsu++;
|
|
|
|
|
|
|
|
if(pl->lsu < const_float("float_player_lsu_update_limit") ||
|
|
|
|
math_rnd(0, 1) < powf(const_float("float_player_lsu_update_base_prob"),
|
|
|
|
pl->lsu - const_float("float_player_lsu_update_limit")))
|
|
|
|
return;
|
|
|
|
|
|
|
|
pl->lsu = 0;
|
|
|
|
|
|
|
|
diff = pl->peak_age - pl->age;
|
|
|
|
|
|
|
|
for(i=0;i<7;i++)
|
|
|
|
if(diff > age_limits[i])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(i < 3)
|
|
|
|
pl->skill += (pl->talent - pl->skill) * math_rnd(factor_limits[i][0], factor_limits[i][1]);
|
|
|
|
else if(i < 5)
|
|
|
|
pl->skill += math_rnd(increase_decrease[0][0], increase_decrease[0][1]);
|
|
|
|
else if(i < 7)
|
|
|
|
pl->skill += math_rnd(increase_decrease[i - 4][0], increase_decrease[i - 4][1]);
|
|
|
|
else
|
|
|
|
pl->skill += math_rnd(increase_decrease[3][0], increase_decrease[3][1]);
|
|
|
|
|
|
|
|
pl->skill = CLAMP(pl->skill, 0, pl->talent);
|
|
|
|
pl->cskill = player_get_cskill(pl, pl->cpos);
|
2005-03-14 10:29:39 +01:00
|
|
|
pl->value = player_assign_value(pl);
|
2005-03-13 22:10:19 +01:00
|
|
|
|
|
|
|
for(i=0;i<QUALITY_END;i++)
|
|
|
|
if(pl->skill > pl->etal[i])
|
|
|
|
{
|
|
|
|
player_estimate_talent(pl);
|
|
|
|
break;
|
|
|
|
}
|
2005-03-13 16:46:15 +01:00
|
|
|
}
|
|
|
|
|
2005-03-14 18:47:27 +01:00
|
|
|
/** Decrement the number of weeks until
|
|
|
|
recovery depending on the user's physio.
|
|
|
|
@param pl An injured player. */
|
|
|
|
void
|
|
|
|
player_update_injury(Player *pl)
|
|
|
|
{
|
|
|
|
gint i, j;
|
|
|
|
gfloat rndom;
|
|
|
|
gint physio = user_from_team(pl->team)->physio;
|
|
|
|
gfloat injury_decrease_probs[4][3] =
|
|
|
|
{{const_float("float_player_injury_recovery_best0"),
|
|
|
|
const_float("float_player_injury_recovery_best1"),
|
|
|
|
const_float("float_player_injury_recovery_best2")},
|
|
|
|
{const_float("float_player_injury_recovery_good0"),
|
|
|
|
const_float("float_player_injury_recovery_good1"),
|
|
|
|
const_float("float_player_injury_recovery_good2")},
|
|
|
|
{const_float("float_player_injury_recovery_good2"),
|
|
|
|
const_float("float_player_injury_recovery_good1"),
|
|
|
|
const_float("float_player_injury_recovery_good0")},
|
|
|
|
{const_float("float_player_injury_recovery_best2"),
|
|
|
|
const_float("float_player_injury_recovery_best1"),
|
|
|
|
const_float("float_player_injury_recovery_best0")}};
|
|
|
|
|
|
|
|
for(j=1;j<3;j++)
|
|
|
|
injury_decrease_probs[physio][j] += injury_decrease_probs[physio][j - 1];
|
|
|
|
|
|
|
|
rndom = math_rnd(0, 1);
|
|
|
|
|
|
|
|
for(i=0;i<3;i++)
|
|
|
|
if(rndom <= injury_decrease_probs[physio][i])
|
|
|
|
{
|
|
|
|
pl->recovery = MAX(pl->recovery - i, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pl->recovery == 0)
|
|
|
|
{
|
|
|
|
pl->health = 0;
|
|
|
|
pl->fitness = math_rnd(const_float("float_player_injury_recovery_fitness_lower"),
|
|
|
|
const_float("float_player_injury_recovery_fitness_upper"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
/** Update players in user teams (age, skill, fitness etc.)
|
|
|
|
@param tm The team of the player.
|
|
|
|
@param idx The index in the players array. */
|
|
|
|
void
|
|
|
|
player_update_weekly(Team *tm, gint idx)
|
|
|
|
{
|
2005-04-15 15:55:59 +02:00
|
|
|
gchar buf[SMALL];
|
2005-04-13 15:01:59 +02:00
|
|
|
Player *pl = player_of_idx_team(tm, idx);
|
2005-03-13 16:46:15 +01:00
|
|
|
|
2005-04-14 21:07:25 +02:00
|
|
|
if(debug < 50)
|
|
|
|
{
|
|
|
|
pl->age += 0.0192;
|
|
|
|
pl->contract -= 0.0192;
|
|
|
|
}
|
2005-03-13 16:46:15 +01:00
|
|
|
|
2005-04-15 15:55:59 +02:00
|
|
|
if(pl->contract * 12 <= opt_user_int("int_opt_user_contract_limit") &&
|
|
|
|
(pl->contract + 0.0192) * 12 > opt_user_int("int_opt_user_contract_limit"))
|
|
|
|
{
|
|
|
|
sprintf(buf, _("%s's contract expires in %.1f years."),
|
|
|
|
pl->name->str, pl->contract);
|
|
|
|
|
|
|
|
user_event_add(&usr(team_is_user(tm)), EVENT_TYPE_WARNING,
|
|
|
|
-1, -1, NULL, buf);
|
|
|
|
}
|
|
|
|
|
2005-03-13 16:46:15 +01:00
|
|
|
if(pl->contract <= 0)
|
|
|
|
player_remove_contract(tm, idx);
|
|
|
|
|
|
|
|
player_update_skill(pl);
|
2005-03-14 18:47:27 +01:00
|
|
|
if(pl->health > 0)
|
2005-04-13 15:01:59 +02:00
|
|
|
player_update_injury(pl);
|
2005-03-13 16:46:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Remove a player from a user team after the contract expired.
|
|
|
|
@param tm The user team.
|
|
|
|
@param idx The player index. */
|
|
|
|
void
|
|
|
|
player_remove_contract(Team *tm, gint idx)
|
|
|
|
{
|
2005-03-18 23:03:23 +01:00
|
|
|
user_event_add(user_from_team(tm), EVENT_TYPE_PLAYER_LEFT, -1, -1, NULL,
|
2005-04-13 15:01:59 +02:00
|
|
|
player_of_idx_team(tm, idx)->name->str);
|
2005-03-13 22:10:19 +01:00
|
|
|
player_remove_from_team(tm, idx);
|
|
|
|
}
|
2005-03-13 16:46:15 +01:00
|
|
|
|
2005-03-13 22:10:19 +01:00
|
|
|
/** Remove a player from a team.
|
|
|
|
@param idx The player index in the players array. */
|
|
|
|
void
|
|
|
|
player_remove_from_team(Team *tm, gint idx)
|
|
|
|
{
|
2005-04-13 15:01:59 +02:00
|
|
|
free_player(player_of_idx_team(tm, idx));
|
2005-03-13 22:10:19 +01:00
|
|
|
g_array_remove_index(tm->players, idx);
|
2005-03-13 16:46:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Make some player updates after a match
|
|
|
|
for user players.
|
2005-03-14 10:29:39 +01:00
|
|
|
@param pl The player we update.
|
|
|
|
@param clid The fixture clid. */
|
2005-03-13 16:46:15 +01:00
|
|
|
void
|
2005-03-14 10:29:39 +01:00
|
|
|
player_update_post_match(Player *pl, gint clid)
|
2005-03-13 16:46:15 +01:00
|
|
|
{
|
2005-04-13 15:01:59 +02:00
|
|
|
gint yellow_red = league_cup_get_yellow_red(clid);
|
|
|
|
|
2005-03-14 10:29:39 +01:00
|
|
|
if(player_card_get(pl, clid, PLAYER_VALUE_CARD_RED) > 0)
|
|
|
|
player_card_set(pl, clid, PLAYER_VALUE_CARD_RED, -1, TRUE);
|
2005-04-13 15:01:59 +02:00
|
|
|
|
|
|
|
if(player_card_get(pl, clid, PLAYER_VALUE_CARD_YELLOW) >= yellow_red)
|
|
|
|
{
|
|
|
|
player_card_set(pl, clid, PLAYER_VALUE_CARD_YELLOW, 0, FALSE);
|
|
|
|
|
2005-04-25 21:39:43 +02:00
|
|
|
if(player_card_get(pl, clid, PLAYER_VALUE_CARD_RED) == 0 && opt_int("int_opt_debug") < 50)
|
2005-04-13 15:01:59 +02:00
|
|
|
player_card_set(pl, clid, PLAYER_VALUE_CARD_RED, 1, FALSE);
|
|
|
|
}
|
2005-03-13 22:10:19 +01:00
|
|
|
}
|
|
|
|
|
2005-03-19 21:04:08 +01:00
|
|
|
/** Replace a player by a new one in a cpu team.
|
|
|
|
@param free_player Whether to free the memory occupied
|
|
|
|
by the player. */
|
2005-03-13 22:10:19 +01:00
|
|
|
void
|
2005-03-19 21:04:08 +01:00
|
|
|
player_replace_by_new(Player *pl, gboolean free_player)
|
2005-03-13 22:10:19 +01:00
|
|
|
{
|
|
|
|
Team *tm = pl->team;
|
|
|
|
gint idx = player_id_index(tm, pl->id);
|
2005-04-14 21:07:25 +02:00
|
|
|
Player new = player_new(tm, team_get_average_skill(tm, FALSE), FALSE);
|
2005-03-13 22:10:19 +01:00
|
|
|
|
|
|
|
new.pos = pl->pos;
|
|
|
|
new.cpos = pl->cpos;
|
|
|
|
new.id = pl->id;
|
|
|
|
|
2005-03-19 21:04:08 +01:00
|
|
|
if(free_player)
|
|
|
|
player_remove_from_team(tm, idx);
|
|
|
|
else
|
|
|
|
g_array_remove_index(tm->players, idx);
|
2005-03-13 22:10:19 +01:00
|
|
|
g_array_insert_val(tm->players, idx, new);
|
2005-03-13 16:46:15 +01:00
|
|
|
}
|
2005-03-14 10:29:39 +01:00
|
|
|
|
|
|
|
/** Update players in user teams.
|
|
|
|
@param tm The team of the player.
|
|
|
|
@param idx The index in the players array. */
|
|
|
|
/*d maybe argument player pointer?*/
|
|
|
|
void
|
|
|
|
player_update_week_roundly(Team *tm, gint idx)
|
|
|
|
{
|
2005-04-13 15:01:59 +02:00
|
|
|
Player *pl = player_of_idx_team(tm, idx);
|
2005-03-14 10:29:39 +01:00
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
if(pl->health == 0 &&
|
|
|
|
(week_round == 1 ||
|
|
|
|
(week_round > 1 && query_team_plays(tm, week, week_round))))
|
2005-04-09 21:18:28 +02:00
|
|
|
player_update_fitness(pl);
|
|
|
|
|
2005-03-14 10:29:39 +01:00
|
|
|
pl->cskill = (pl->health > 0 || player_is_banned(pl) > 0) ?
|
2005-04-09 21:18:28 +02:00
|
|
|
0 : player_get_cskill(pl, pl->cpos);
|
2005-03-14 10:29:39 +01:00
|
|
|
}
|
2005-04-07 18:44:33 +02:00
|
|
|
|
|
|
|
/** Return injury descriptions. */
|
|
|
|
gchar*
|
|
|
|
player_injury_to_char(gint injury_type)
|
|
|
|
{
|
|
|
|
switch(injury_type)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
g_warning("player_injury_to_char: unknown type %d\n", injury_type);
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_NONE:
|
|
|
|
return _("OK");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_CONCUSSION:
|
|
|
|
return _("Concussion");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_PULLED_MUSCLE:
|
|
|
|
return _("Pulled muscle");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_HAMSTRING:
|
|
|
|
return _("Hamstring");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_GROIN:
|
|
|
|
return _("Groin injury");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_FRAC_ANKLE:
|
|
|
|
return _("Fractured ankle");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_RIB:
|
|
|
|
return _("Broken rib");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_LEG:
|
|
|
|
return _("Broken leg");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_BROK_ANKLE:
|
|
|
|
return _("Broken ankle");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_ARM:
|
|
|
|
return _("Broken arm");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_SHOULDER:
|
|
|
|
return _("Broken shoulder");
|
|
|
|
break;
|
|
|
|
case PLAYER_INJURY_LIGAMENT:
|
|
|
|
return _("Torn crucial ligament");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-04-13 15:01:59 +02:00
|
|
|
|
2005-04-15 15:55:59 +02:00
|
|
|
/** Nullify some stuff at the beginning of the season and change the skills
|
|
|
|
of cpu players.
|
|
|
|
@param skill_change Skill change of the player in percentage. */
|
2005-04-13 15:01:59 +02:00
|
|
|
void
|
2005-04-15 15:55:59 +02:00
|
|
|
player_season_start(Player *pl, gfloat skill_change)
|
2005-04-13 15:01:59 +02:00
|
|
|
{
|
2005-04-15 15:55:59 +02:00
|
|
|
gint i;
|
|
|
|
|
2005-04-13 15:01:59 +02:00
|
|
|
if(pl->games_goals->len > 0)
|
|
|
|
{
|
|
|
|
g_array_free(pl->games_goals, TRUE);
|
|
|
|
pl->games_goals = g_array_new(FALSE, FALSE, sizeof(PlayerGamesGoals));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pl->cards->len > 0)
|
|
|
|
{
|
|
|
|
g_array_free(pl->cards, TRUE);
|
|
|
|
pl->cards = g_array_new(FALSE, FALSE, sizeof(PlayerGamesGoals));
|
|
|
|
}
|
2005-04-15 15:55:59 +02:00
|
|
|
|
|
|
|
if(skill_change != 0)
|
|
|
|
{
|
|
|
|
pl->skill *= (1 + skill_change);
|
|
|
|
|
|
|
|
pl->skill = CLAMP(pl->skill, 0, pl->talent);
|
|
|
|
pl->cskill = player_get_cskill(pl, pl->cpos);
|
|
|
|
pl->value = player_assign_value(pl);
|
|
|
|
|
|
|
|
for(i=0;i<QUALITY_END;i++)
|
|
|
|
if(pl->skill > pl->etal[i])
|
|
|
|
{
|
|
|
|
player_estimate_talent(pl);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-04-13 15:01:59 +02:00
|
|
|
}
|