2007-11-25 19:42:40 +00:00
|
|
|
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
2008-01-13 11:43:43 +00:00
|
|
|
#include <string.h>
|
2007-12-15 10:24:49 +00:00
|
|
|
#include <engine/e_config.h>
|
2008-01-19 10:57:25 +00:00
|
|
|
#include <engine/e_server_interface.h>
|
2008-08-17 08:52:24 +00:00
|
|
|
#include <game/mapitems.hpp>
|
2008-08-14 18:42:47 +00:00
|
|
|
|
|
|
|
#include <game/generated/g_protocol.hpp>
|
2007-10-05 00:05:21 +00:00
|
|
|
|
2008-08-14 18:25:44 +00:00
|
|
|
#include "entities/pickup.hpp"
|
2008-08-14 18:42:47 +00:00
|
|
|
#include "gamecontroller.hpp"
|
|
|
|
#include "gamecontext.hpp"
|
2008-08-14 18:25:44 +00:00
|
|
|
|
2008-08-27 20:04:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
GAMECONTROLLER::GAMECONTROLLER()
|
|
|
|
{
|
2008-08-31 21:50:14 +00:00
|
|
|
gametype = "unknown";
|
2008-08-31 14:37:35 +00:00
|
|
|
|
2008-08-27 20:04:07 +00:00
|
|
|
//
|
|
|
|
do_warmup(config.sv_warmup);
|
|
|
|
game_over_tick = -1;
|
|
|
|
sudden_death = 0;
|
|
|
|
round_start_tick = server_tick();
|
|
|
|
round_count = 0;
|
2008-08-31 14:37:35 +00:00
|
|
|
game_flags = 0;
|
2008-08-27 20:04:07 +00:00
|
|
|
teamscore[0] = 0;
|
|
|
|
teamscore[1] = 0;
|
2008-10-22 14:31:46 +00:00
|
|
|
map_wish[0] = 0;
|
2008-08-27 20:04:07 +00:00
|
|
|
|
2008-09-07 08:10:56 +00:00
|
|
|
unbalanced_tick = -1;
|
2008-09-07 08:57:59 +00:00
|
|
|
force_balanced = false;
|
2008-09-07 08:10:56 +00:00
|
|
|
|
2008-08-27 20:04:07 +00:00
|
|
|
num_spawn_points[0] = 0;
|
|
|
|
num_spawn_points[1] = 0;
|
|
|
|
num_spawn_points[2] = 0;
|
|
|
|
}
|
|
|
|
|
2008-10-02 14:44:35 +00:00
|
|
|
GAMECONTROLLER::~GAMECONTROLLER()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
float GAMECONTROLLER::evaluate_spawn_pos(SPAWNEVAL *eval, vec2 pos)
|
|
|
|
{
|
|
|
|
float score = 0.0f;
|
|
|
|
CHARACTER *c = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
|
|
|
|
for(; c; c = (CHARACTER *)c->typenext())
|
|
|
|
{
|
|
|
|
// team mates are not as dangerous as enemies
|
|
|
|
float scoremod = 1.0f;
|
|
|
|
if(eval->friendly_team != -1 && c->team == eval->friendly_team)
|
|
|
|
scoremod = 0.5f;
|
|
|
|
|
|
|
|
float d = distance(pos, c->pos);
|
|
|
|
if(d == 0)
|
|
|
|
score += 1000000000.0f;
|
|
|
|
else
|
|
|
|
score += 1.0f/d;
|
|
|
|
}
|
|
|
|
|
|
|
|
return score;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GAMECONTROLLER::evaluate_spawn_type(SPAWNEVAL *eval, int t)
|
|
|
|
{
|
|
|
|
// get spawn point
|
|
|
|
for(int i = 0; i < num_spawn_points[t]; i++)
|
|
|
|
{
|
|
|
|
vec2 p = spawn_points[t][i];
|
|
|
|
float s = evaluate_spawn_pos(eval, p);
|
|
|
|
if(!eval->got || eval->score > s)
|
|
|
|
{
|
|
|
|
eval->got = true;
|
|
|
|
eval->score = s;
|
|
|
|
eval->pos = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GAMECONTROLLER::can_spawn(PLAYER *player, vec2 *out_pos)
|
|
|
|
{
|
|
|
|
SPAWNEVAL eval;
|
|
|
|
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
|
|
|
eval.friendly_team = player->team;
|
|
|
|
|
|
|
|
// try first try own team spawn, then normal spawn and then enemy
|
|
|
|
evaluate_spawn_type(&eval, 1+(player->team&1));
|
|
|
|
if(!eval.got)
|
|
|
|
{
|
|
|
|
evaluate_spawn_type(&eval, 0);
|
|
|
|
if(!eval.got)
|
|
|
|
evaluate_spawn_type(&eval, 1+((player->team+1)&1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
evaluate_spawn_type(&eval, 0);
|
|
|
|
evaluate_spawn_type(&eval, 1);
|
|
|
|
evaluate_spawn_type(&eval, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_pos = eval.pos;
|
2008-08-27 20:04:07 +00:00
|
|
|
return eval.got;
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 20:04:07 +00:00
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
bool GAMECONTROLLER::on_entity(int index, vec2 pos)
|
2008-01-13 11:43:43 +00:00
|
|
|
{
|
|
|
|
int type = -1;
|
|
|
|
int subtype = 0;
|
|
|
|
|
|
|
|
if(index == ENTITY_SPAWN)
|
|
|
|
spawn_points[0][num_spawn_points[0]++] = pos;
|
|
|
|
else if(index == ENTITY_SPAWN_RED)
|
|
|
|
spawn_points[1][num_spawn_points[1]++] = pos;
|
|
|
|
else if(index == ENTITY_SPAWN_BLUE)
|
|
|
|
spawn_points[2][num_spawn_points[2]++] = pos;
|
|
|
|
else if(index == ENTITY_ARMOR_1)
|
|
|
|
type = POWERUP_ARMOR;
|
|
|
|
else if(index == ENTITY_HEALTH_1)
|
|
|
|
type = POWERUP_HEALTH;
|
|
|
|
else if(index == ENTITY_WEAPON_SHOTGUN)
|
|
|
|
{
|
|
|
|
type = POWERUP_WEAPON;
|
|
|
|
subtype = WEAPON_SHOTGUN;
|
|
|
|
}
|
2008-02-02 18:05:16 +00:00
|
|
|
else if(index == ENTITY_WEAPON_GRENADE)
|
2008-01-13 11:43:43 +00:00
|
|
|
{
|
|
|
|
type = POWERUP_WEAPON;
|
2008-02-02 18:05:16 +00:00
|
|
|
subtype = WEAPON_GRENADE;
|
2008-01-13 11:43:43 +00:00
|
|
|
}
|
2008-03-21 19:05:35 +00:00
|
|
|
else if(index == ENTITY_WEAPON_RIFLE)
|
|
|
|
{
|
|
|
|
type = POWERUP_WEAPON;
|
|
|
|
subtype = WEAPON_RIFLE;
|
|
|
|
}
|
2008-03-29 12:04:14 +00:00
|
|
|
else if(index == ENTITY_POWERUP_NINJA && config.sv_powerups)
|
2008-01-13 11:43:43 +00:00
|
|
|
{
|
|
|
|
type = POWERUP_NINJA;
|
|
|
|
subtype = WEAPON_NINJA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(type != -1)
|
|
|
|
{
|
2008-06-12 10:51:48 +00:00
|
|
|
PICKUP *pickup = new PICKUP(type, subtype);
|
|
|
|
pickup->pos = pos;
|
2008-01-13 11:43:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::endround()
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2007-10-06 17:36:24 +00:00
|
|
|
if(warmup) // game can't end when we are running warmup
|
|
|
|
return;
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
game.world.paused = true;
|
2007-10-05 00:05:21 +00:00
|
|
|
game_over_tick = server_tick();
|
|
|
|
sudden_death = 0;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::resetgame()
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2008-07-06 11:21:21 +00:00
|
|
|
game.world.reset_requested = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *GAMECONTROLLER::get_team_name(int team)
|
|
|
|
{
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2008-07-06 11:21:21 +00:00
|
|
|
{
|
|
|
|
if(team == 0)
|
|
|
|
return "red team";
|
|
|
|
else if(team == 1)
|
|
|
|
return "blue team";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(team == 0)
|
|
|
|
return "game";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "spectators";
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-01-12 12:27:55 +00:00
|
|
|
static bool is_separator(char c) { return c == ';' || c == ' ' || c == ',' || c == '\t'; }
|
2007-10-05 00:05:21 +00:00
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::startround()
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
|
|
|
resetgame();
|
|
|
|
|
|
|
|
round_start_tick = server_tick();
|
|
|
|
sudden_death = 0;
|
|
|
|
game_over_tick = -1;
|
2008-07-06 11:21:21 +00:00
|
|
|
game.world.paused = false;
|
2007-10-05 00:05:21 +00:00
|
|
|
teamscore[0] = 0;
|
|
|
|
teamscore[1] = 0;
|
2008-09-07 08:10:56 +00:00
|
|
|
unbalanced_tick = -1;
|
2008-09-07 08:57:59 +00:00
|
|
|
force_balanced = false;
|
2007-10-05 00:05:21 +00:00
|
|
|
round_count++;
|
|
|
|
}
|
|
|
|
|
2008-10-22 14:31:46 +00:00
|
|
|
void GAMECONTROLLER::change_map(const char *to_map)
|
|
|
|
{
|
|
|
|
str_copy(map_wish, to_map, sizeof(map_wish));
|
|
|
|
endround();
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::cyclemap()
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2008-10-22 14:31:46 +00:00
|
|
|
if(map_wish[0] != 0)
|
|
|
|
{
|
|
|
|
dbg_msg("game", "rotating map to %s", map_wish);
|
|
|
|
str_copy(config.sv_map, map_wish, sizeof(config.sv_map));
|
|
|
|
map_wish[0] = 0;
|
|
|
|
return;
|
|
|
|
}
|
2007-10-05 00:05:21 +00:00
|
|
|
if(!strlen(config.sv_maprotation))
|
|
|
|
return;
|
2008-03-01 20:21:34 +00:00
|
|
|
|
2008-03-29 21:46:38 +00:00
|
|
|
if(round_count < config.sv_rounds_per_map-1)
|
|
|
|
return;
|
|
|
|
|
2007-10-05 00:05:21 +00:00
|
|
|
// handle maprotation
|
2008-03-01 20:21:34 +00:00
|
|
|
const char *map_rotation = config.sv_maprotation;
|
|
|
|
const char *current_map = config.sv_map;
|
|
|
|
|
|
|
|
int current_map_len = strlen(current_map);
|
|
|
|
const char *next_map = map_rotation;
|
|
|
|
while(*next_map)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2008-03-01 20:21:34 +00:00
|
|
|
int wordlen = 0;
|
|
|
|
while(next_map[wordlen] && !is_separator(next_map[wordlen]))
|
|
|
|
wordlen++;
|
2007-10-05 00:05:21 +00:00
|
|
|
|
2008-03-01 20:21:34 +00:00
|
|
|
if(wordlen == current_map_len && strncmp(next_map, current_map, current_map_len) == 0)
|
|
|
|
{
|
|
|
|
// map found
|
|
|
|
next_map += current_map_len;
|
|
|
|
while(*next_map && is_separator(*next_map))
|
|
|
|
next_map++;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_map++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// restart rotation
|
|
|
|
if(next_map[0] == 0)
|
|
|
|
next_map = map_rotation;
|
|
|
|
|
|
|
|
// cut out the next map
|
|
|
|
char buf[512];
|
|
|
|
for(int i = 0; i < 512; i++)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2008-03-01 20:21:34 +00:00
|
|
|
buf[i] = next_map[i];
|
|
|
|
if(is_separator(next_map[i]) || next_map[i] == 0)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
|
|
|
buf[i] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-01 20:21:34 +00:00
|
|
|
// skip spaces
|
|
|
|
int i = 0;
|
2007-10-05 00:05:21 +00:00
|
|
|
while(is_separator(buf[i]))
|
|
|
|
i++;
|
|
|
|
|
|
|
|
dbg_msg("game", "rotating map to %s", &buf[i]);
|
2008-02-11 21:49:26 +00:00
|
|
|
str_copy(config.sv_map, &buf[i], sizeof(config.sv_map));
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::post_reset()
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i])
|
2008-10-25 08:36:55 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
game.players[i]->respawn();
|
2008-10-25 08:36:55 +00:00
|
|
|
game.players[i]->score = 0;
|
|
|
|
}
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
}
|
2007-11-18 14:24:34 +00:00
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::on_player_info_change(class PLAYER *p)
|
2007-11-18 14:24:34 +00:00
|
|
|
{
|
2007-11-26 22:26:33 +00:00
|
|
|
const int team_colors[2] = {65387, 10223467};
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2007-11-18 14:24:34 +00:00
|
|
|
{
|
|
|
|
if(p->team >= 0 || p->team <= 1)
|
|
|
|
{
|
|
|
|
p->use_custom_color = 1;
|
|
|
|
p->color_body = team_colors[p->team];
|
|
|
|
p->color_feet = team_colors[p->team];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
int GAMECONTROLLER::on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
|
|
|
// do scoreing
|
|
|
|
if(!killer)
|
2007-11-18 23:29:34 +00:00
|
|
|
return 0;
|
2008-07-06 11:21:21 +00:00
|
|
|
if(killer == victim->player)
|
|
|
|
victim->player->score--; // suicide
|
2007-10-05 00:05:21 +00:00
|
|
|
else
|
2007-12-11 21:19:52 +00:00
|
|
|
{
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay() && victim->team == killer->team)
|
2007-12-11 21:19:52 +00:00
|
|
|
killer->score--; // teamkill
|
|
|
|
else
|
|
|
|
killer->score++; // normal kill
|
|
|
|
}
|
2007-11-18 23:29:34 +00:00
|
|
|
return 0;
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 20:04:07 +00:00
|
|
|
void GAMECONTROLLER::on_character_spawn(class CHARACTER *chr)
|
|
|
|
{
|
2008-08-27 20:17:04 +00:00
|
|
|
// default health
|
|
|
|
chr->health = 10;
|
|
|
|
|
2008-08-27 20:04:07 +00:00
|
|
|
// give default weapons
|
|
|
|
chr->weapons[WEAPON_HAMMER].got = 1;
|
|
|
|
chr->weapons[WEAPON_HAMMER].ammo = -1;
|
|
|
|
chr->weapons[WEAPON_GUN].got = 1;
|
|
|
|
chr->weapons[WEAPON_GUN].ammo = 10;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::do_warmup(int seconds)
|
2007-10-06 17:36:24 +00:00
|
|
|
{
|
2008-01-19 10:57:25 +00:00
|
|
|
warmup = seconds*server_tickspeed();
|
2007-10-06 17:36:24 +00:00
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
bool GAMECONTROLLER::is_friendly_fire(int cid1, int cid2)
|
2007-12-10 20:53:37 +00:00
|
|
|
{
|
|
|
|
if(cid1 == cid2)
|
|
|
|
return false;
|
|
|
|
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2007-12-10 20:53:37 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[cid1]->team == game.players[cid2]->team)
|
2007-12-10 20:53:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2007-10-05 00:05:21 +00:00
|
|
|
|
2008-09-07 08:57:59 +00:00
|
|
|
bool GAMECONTROLLER::is_force_balanced()
|
|
|
|
{
|
|
|
|
if(force_balanced)
|
|
|
|
{
|
|
|
|
force_balanced = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::tick()
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2007-10-06 17:36:24 +00:00
|
|
|
// do warmup
|
|
|
|
if(warmup)
|
|
|
|
{
|
|
|
|
warmup--;
|
|
|
|
if(!warmup)
|
2007-12-10 21:05:57 +00:00
|
|
|
startround();
|
2007-10-06 17:36:24 +00:00
|
|
|
}
|
|
|
|
|
2007-10-05 00:05:21 +00:00
|
|
|
if(game_over_tick != -1)
|
|
|
|
{
|
|
|
|
// game over.. wait for restart
|
|
|
|
if(server_tick() > game_over_tick+server_tickspeed()*10)
|
|
|
|
{
|
|
|
|
cyclemap();
|
|
|
|
startround();
|
|
|
|
}
|
|
|
|
}
|
2007-11-27 19:51:48 +00:00
|
|
|
|
2008-10-19 16:51:16 +00:00
|
|
|
// do team-balancing
|
2008-09-07 08:10:56 +00:00
|
|
|
if (is_teamplay() && unbalanced_tick != -1 && server_tick() > unbalanced_tick+config.sv_teambalance_time*server_tickspeed()*60)
|
|
|
|
{
|
|
|
|
dbg_msg("game", "Balancing teams");
|
|
|
|
|
|
|
|
int t[2] = {0,0};
|
2008-10-19 16:14:12 +00:00
|
|
|
int tscore[2] = {0,0};
|
2008-09-07 08:10:56 +00:00
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i] && game.players[i]->team != -1)
|
2008-10-19 16:14:12 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
t[game.players[i]->team]++;
|
2008-10-19 16:14:12 +00:00
|
|
|
tscore[game.players[i]->team]+=game.players[i]->score;
|
|
|
|
}
|
2008-09-07 08:10:56 +00:00
|
|
|
}
|
|
|
|
|
2008-10-19 18:38:23 +00:00
|
|
|
// are teams unbalanced?
|
|
|
|
if(abs(t[0]-t[1]) >= 2)
|
2008-09-07 08:10:56 +00:00
|
|
|
{
|
2008-10-19 18:38:23 +00:00
|
|
|
int m = (t[0] > t[1]) ? 0 : 1;
|
|
|
|
int num_balance = abs(t[0]-t[1]) / 2;
|
|
|
|
|
|
|
|
do
|
2008-09-07 08:10:56 +00:00
|
|
|
{
|
2008-10-19 18:38:23 +00:00
|
|
|
PLAYER *p = 0;
|
|
|
|
int pd = tscore[m];
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
2008-09-07 08:10:56 +00:00
|
|
|
{
|
2008-10-19 18:38:23 +00:00
|
|
|
if(!game.players[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// remember the player who would cause lowest score-difference
|
|
|
|
if(game.players[i]->team == m && (!p || abs((tscore[m^1]+game.players[i]->score) - (tscore[m]-game.players[i]->score)) < pd))
|
|
|
|
{
|
|
|
|
p = game.players[i];
|
|
|
|
pd = abs((tscore[m^1]+p->score) - (tscore[m]-p->score));
|
|
|
|
}
|
2008-09-07 08:10:56 +00:00
|
|
|
}
|
2008-10-19 18:38:23 +00:00
|
|
|
|
|
|
|
// move the player to other team without losing his score
|
|
|
|
// TODO: change in player::set_team needed: player won't lose score on team-change
|
|
|
|
int score_before = p->score;
|
|
|
|
p->set_team(m^1);
|
|
|
|
p->score = score_before;
|
|
|
|
|
|
|
|
p->respawn();
|
|
|
|
p->force_balanced = true;
|
|
|
|
} while (--num_balance);
|
2008-09-07 08:10:56 +00:00
|
|
|
|
2008-10-19 18:38:23 +00:00
|
|
|
force_balanced = true;
|
|
|
|
}
|
2008-09-07 08:10:56 +00:00
|
|
|
unbalanced_tick = -1;
|
|
|
|
}
|
2007-11-27 19:51:48 +00:00
|
|
|
|
|
|
|
// update browse info
|
|
|
|
int prog = -1;
|
2007-12-11 23:10:07 +00:00
|
|
|
if(config.sv_timelimit > 0)
|
|
|
|
prog = max(prog, (server_tick()-round_start_tick) * 100 / (config.sv_timelimit*server_tickspeed()*60));
|
2007-11-27 19:51:48 +00:00
|
|
|
|
2007-12-11 23:10:07 +00:00
|
|
|
if(config.sv_scorelimit)
|
2007-11-27 19:51:48 +00:00
|
|
|
{
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2007-11-27 19:51:48 +00:00
|
|
|
{
|
2007-12-11 23:10:07 +00:00
|
|
|
prog = max(prog, (teamscore[0]*100)/config.sv_scorelimit);
|
|
|
|
prog = max(prog, (teamscore[1]*100)/config.sv_scorelimit);
|
2007-11-27 19:51:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i])
|
|
|
|
prog = max(prog, (game.players[i]->score*100)/config.sv_scorelimit);
|
2007-11-27 19:51:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(warmup)
|
|
|
|
prog = -1;
|
2007-12-18 23:21:57 +00:00
|
|
|
|
2007-11-27 19:51:48 +00:00
|
|
|
server_setbrowseinfo(gametype, prog);
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-08-31 14:37:35 +00:00
|
|
|
|
|
|
|
bool GAMECONTROLLER::is_teamplay() const
|
|
|
|
{
|
|
|
|
return game_flags&GAMEFLAG_TEAMS;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::snap(int snapping_client)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2008-07-06 11:21:21 +00:00
|
|
|
NETOBJ_GAME *gameobj = (NETOBJ_GAME *)snap_new_item(NETOBJTYPE_GAME, 0, sizeof(NETOBJ_GAME));
|
|
|
|
gameobj->paused = game.world.paused;
|
|
|
|
gameobj->game_over = game_over_tick==-1?0:1;
|
|
|
|
gameobj->sudden_death = sudden_death;
|
2007-10-05 00:05:21 +00:00
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
gameobj->score_limit = config.sv_scorelimit;
|
|
|
|
gameobj->time_limit = config.sv_timelimit;
|
|
|
|
gameobj->round_start_tick = round_start_tick;
|
2008-08-31 14:37:35 +00:00
|
|
|
gameobj->flags = game_flags;
|
2007-10-05 00:05:21 +00:00
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
gameobj->warmup = warmup;
|
2007-10-06 17:36:24 +00:00
|
|
|
|
2008-09-07 15:07:08 +00:00
|
|
|
gameobj->round_num = (strlen(config.sv_maprotation) || config.sv_rounds_per_map > 1) ? config.sv_rounds_per_map : 0;
|
|
|
|
gameobj->round_current = round_count+1;
|
|
|
|
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
|
|
if(snapping_client == -1)
|
|
|
|
{
|
|
|
|
// we are recording a demo, just set the scores
|
|
|
|
gameobj->teamscore_red = teamscore[0];
|
|
|
|
gameobj->teamscore_blue = teamscore[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// TODO: this little hack should be removed
|
|
|
|
gameobj->teamscore_red = is_teamplay() ? teamscore[0] : game.players[snapping_client]->score;
|
|
|
|
gameobj->teamscore_blue = teamscore[1];
|
|
|
|
}
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
int GAMECONTROLLER::get_auto_team(int notthisid)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
|
|
|
int numplayers[2] = {0,0};
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i] && i != notthisid)
|
2007-10-05 00:05:21 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i]->team == 0 || game.players[i]->team == 1)
|
|
|
|
numplayers[game.players[i]->team]++;
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-23 14:59:58 +00:00
|
|
|
int team = 0;
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2008-03-23 14:59:58 +00:00
|
|
|
team = numplayers[0] > numplayers[1] ? 1 : 0;
|
|
|
|
|
|
|
|
if(can_join_team(team, notthisid))
|
|
|
|
return team;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
bool GAMECONTROLLER::can_join_team(int team, int notthisid)
|
2008-03-23 14:59:58 +00:00
|
|
|
{
|
|
|
|
(void)team;
|
|
|
|
int numplayers[2] = {0,0};
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i] && i != notthisid)
|
2008-03-23 14:59:58 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i]->team >= 0 || game.players[i]->team == 1)
|
|
|
|
numplayers[game.players[i]->team]++;
|
2008-03-23 14:59:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (numplayers[0] + numplayers[1]) < config.sv_max_clients-config.sv_spectator_slots;
|
2007-10-05 00:05:21 +00:00
|
|
|
}
|
|
|
|
|
2008-09-07 08:10:56 +00:00
|
|
|
bool GAMECONTROLLER::check_team_balance()
|
|
|
|
{
|
|
|
|
if(!is_teamplay() || !config.sv_teambalance_time)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
int t[2] = {0, 0};
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
PLAYER *p = game.players[i];
|
|
|
|
if(p && p->team != -1)
|
2008-09-07 08:10:56 +00:00
|
|
|
t[p->team]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(abs(t[0]-t[1]) >= 2)
|
|
|
|
{
|
|
|
|
dbg_msg("game", "Team is NOT balanced (red=%d blue=%d)", t[0], t[1]);
|
|
|
|
if (game.controller->unbalanced_tick == -1)
|
|
|
|
game.controller->unbalanced_tick = server_tick();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbg_msg("game", "Team is balanced (red=%d blue=%d)", t[0], t[1]);
|
|
|
|
game.controller->unbalanced_tick = -1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GAMECONTROLLER::can_change_team(PLAYER *pplayer, int jointeam)
|
|
|
|
{
|
|
|
|
int t[2] = {0, 0};
|
|
|
|
|
|
|
|
if (!is_teamplay() || jointeam == -1 || !config.sv_teambalance_time)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
PLAYER *p = game.players[i];
|
|
|
|
if(p && p->team != -1)
|
2008-09-07 08:10:56 +00:00
|
|
|
t[p->team]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// simulate what would happen if changed team
|
|
|
|
t[jointeam]++;
|
|
|
|
if (pplayer->team != -1)
|
|
|
|
t[jointeam^1]--;
|
|
|
|
|
|
|
|
// there is a player-difference of at least 2
|
|
|
|
if(abs(t[0]-t[1]) >= 2)
|
|
|
|
{
|
|
|
|
// player wants to join team with less players
|
|
|
|
if ((t[0] < t[1] && jointeam == 0) || (t[0] > t[1] && jointeam == 1))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::do_player_score_wincheck()
|
2008-01-17 23:09:49 +00:00
|
|
|
{
|
|
|
|
if(game_over_tick == -1 && !warmup)
|
|
|
|
{
|
|
|
|
// gather some stats
|
|
|
|
int topscore = 0;
|
|
|
|
int topscore_count = 0;
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i])
|
2008-01-17 23:09:49 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
if(game.players[i]->score > topscore)
|
2008-01-17 23:09:49 +00:00
|
|
|
{
|
2008-09-23 18:08:19 +00:00
|
|
|
topscore = game.players[i]->score;
|
2008-01-17 23:09:49 +00:00
|
|
|
topscore_count = 1;
|
|
|
|
}
|
2008-09-23 18:08:19 +00:00
|
|
|
else if(game.players[i]->score == topscore)
|
2008-01-17 23:09:49 +00:00
|
|
|
topscore_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check score win condition
|
|
|
|
if((config.sv_scorelimit > 0 && topscore >= config.sv_scorelimit) ||
|
|
|
|
(config.sv_timelimit > 0 && (server_tick()-round_start_tick) >= config.sv_timelimit*server_tickspeed()*60))
|
|
|
|
{
|
|
|
|
if(topscore_count == 1)
|
|
|
|
endround();
|
|
|
|
else
|
|
|
|
sudden_death = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
void GAMECONTROLLER::do_team_score_wincheck()
|
2007-11-26 20:47:49 +00:00
|
|
|
{
|
|
|
|
if(game_over_tick == -1 && !warmup)
|
|
|
|
{
|
|
|
|
// check score win condition
|
2007-12-11 23:10:07 +00:00
|
|
|
if((config.sv_scorelimit > 0 && (teamscore[0] >= config.sv_scorelimit || teamscore[1] >= config.sv_scorelimit)) ||
|
|
|
|
(config.sv_timelimit > 0 && (server_tick()-round_start_tick) >= config.sv_timelimit*server_tickspeed()*60))
|
2007-11-26 20:47:49 +00:00
|
|
|
{
|
|
|
|
if(teamscore[0] != teamscore[1])
|
|
|
|
endround();
|
|
|
|
else
|
|
|
|
sudden_death = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
int GAMECONTROLLER::clampteam(int team)
|
2007-12-18 23:21:57 +00:00
|
|
|
{
|
|
|
|
if(team < 0) // spectator
|
|
|
|
return -1;
|
2008-08-31 14:37:35 +00:00
|
|
|
if(is_teamplay())
|
2007-12-18 23:21:57 +00:00
|
|
|
return team&1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-12 10:51:48 +00:00
|
|
|
GAMECONTROLLER *gamecontroller = 0;
|