entity bot = spawnclient();
if (bot)
{
- setItemGroupCount();
- currentbots = currentbots + 1;
- bot_setnameandstuff(bot);
- ClientConnect(bot);
- PutClientInServer(bot);
+ bot_spawn_setup(bot);
}
return bot;
}
+void bot_spawn_setup(entity bot)
+{
+ setItemGroupCount();
+ currentbots = currentbots + 1;
+ bot_setnameandstuff(bot);
+ ClientConnect(bot);
+ PutClientInServer(bot);
+}
+
void bot_think(entity this)
{
if (this.bot_nextthink > time)
{
int activerealplayers = 0;
int realplayers = 0;
- if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers)) {
+ int bots = 0;
+
+ if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers, bots)) {
activerealplayers = M_ARGV(0, int);
realplayers = M_ARGV(1, int);
+ bots = M_ARGV(2, int);
} else {
FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
if(IS_PLAYER(it))
));
}
- int bots;
// add/remove bots if needed to make sure there are at least
// minplayers+bot_number, or remove all bots if no one is playing
// But don't remove bots immediately on level change, as the real players
// usually haven't rejoined yet
bots_would_leave = false;
- if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
+ if (bots)
+ {
+ // Nothing to do, number of bots set by the hook
+ }
+ else if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
+ {
bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
+ }
else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
{
float realminplayers, minplayers;
entity bot_spawn();
float bot_fixcount();
+/*
+ * Sets up an entity created with spawnclient() to be a bot
+ */
+void bot_spawn_setup(entity bot);
void bot_think(entity this);
void bot_setnameandstuff(entity this);
/**/ o(int, MUTATOR_ARGV_0_int) \
/** real players */ i(int, MUTATOR_ARGV_1_int) \
/**/ o(int, MUTATOR_ARGV_1_int) \
+ /** bots */ i(int, MUTATOR_ARGV_2_int) \
+ /**/ o(int, MUTATOR_ARGV_2_int) \
/**/
MUTATOR_HOOKABLE(Bot_FixCount, EV_Bot_FixCount);
.bool can_drop_weapon;
.string weapon_name;
.int sp_spawn_team;
+.entity sp_spawn_spot;
/*QUAKED spawnfunc_tdm_team (0 .5 .8) (-16 -16 -24) (16 16 32)
Team declaration for TDM gameplay, this allows you to decide what team names and control point models are used in your map.
}
// code from here on is just to support maps that don't have team entities
-void sp_SpawnTeam (string teamname, int teamcolor)
+void sp_spawn_team_entity(string teamname, int teamcolor)
{
entity this = new_pure(sp_team);
this.netname = teamname;
spawnfunc_info_player_deathmatch(this);
}
+void sp_spawn_bot(entity spawn_point)
+{
+ entity bot = spawnclient();
+ if (bot)
+ {
+ bot.sp_spawn_spot = spawn_point;
+ bot_spawn_setup(bot);
+ }
+ else
+ {
+ LOG_WARN("Could not spawn bot");
+ }
+}
+
+void sp_enemy_spawn_think(entity this)
+{
+ sp_spawn_bot(this);
+ setthink(this, SUB_Remove);
+}
+
spawnfunc(info_player_singleplayer_enemy)
{
if (!g_singleplayer) { delete(this); return; }
this.team = SP_TEAM_ENEMY;
this.sp_spawn_team = SP_TEAM_ENEMY;
spawnfunc_info_player_deathmatch(this);
+ setthink(this, sp_enemy_spawn_think);
}
-void sp_DelayedInit(entity this)
+void sp_delayed_init(entity this)
{
// if no teams are found, spawn defaults
if(find(NULL, classname, "sp_team") == NULL)
{
LOG_TRACE("No \"sp_team\" entities found on this map, creating them anyway.");
- sp_SpawnTeam("Player", SP_TEAM_PLAYER);
- sp_SpawnTeam("Enemy", SP_TEAM_ENEMY);
+ sp_spawn_team_entity("Player", SP_TEAM_PLAYER);
+ sp_spawn_team_entity("Enemy", SP_TEAM_ENEMY);
}
}
vector spawn_score = M_ARGV(2, vector);
if ( IS_BOT_CLIENT(player) )
{
- if ( spawn_spot.sp_spawn_team != SP_TEAM_ENEMY )
+ if ( spawn_spot.sp_spawn_team != SP_TEAM_ENEMY ||
+ (player.sp_spawn_spot && player.sp_spawn_spot !=spawn_spot) )
spawn_score.x = -1;
}
else if ( spawn_spot.sp_spawn_team != SP_TEAM_PLAYER )
{
return true;
}
+
+MUTATOR_HOOKFUNCTION(sp, Bot_FixCount)
+{
+ int count = 0;
+ for ( entity e = NULL; (e = findfloat(e, sp_spawn_team, SP_TEAM_ENEMY)); )
+ count++;
+ M_ARGV(2, int) = count;
+ return true;
+}
#include "../gamemode.qh"
-void sp_DelayedInit(entity this);
+void sp_delayed_init(entity this);
REGISTER_MUTATOR(sp, false)
{
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
- InitializeEntity(NULL, sp_DelayedInit, INITPRIO_GAMETYPE);
+ InitializeEntity(NULL, sp_delayed_init, INITPRIO_GAMETYPE);
ActivateTeamplay();
SetLimits(-1, -1, autocvar_timelimit_override, -1);