From: Mattia Basaglia Date: Sun, 19 Mar 2017 09:53:06 +0000 (+0000) Subject: Properly link bots and spawn points in single player X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=37c04d1172ada7a60b73afff846effdc060a7e07;p=xonotic%2Fxonotic-data.pk3dir.git Properly link bots and spawn points in single player --- diff --git a/qcsrc/server/bot/default/bot.qc b/qcsrc/server/bot/default/bot.qc index bcdc32e8d..67498d895 100644 --- a/qcsrc/server/bot/default/bot.qc +++ b/qcsrc/server/bot/default/bot.qc @@ -46,15 +46,20 @@ entity bot_spawn() 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) @@ -580,9 +585,12 @@ float bot_fixcount() { 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)) @@ -591,14 +599,19 @@ float bot_fixcount() )); } - 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; diff --git a/qcsrc/server/bot/default/bot.qh b/qcsrc/server/bot/default/bot.qh index b72fad9bd..f49b4f7bf 100644 --- a/qcsrc/server/bot/default/bot.qh +++ b/qcsrc/server/bot/default/bot.qh @@ -84,6 +84,10 @@ float bot_ignore_bots; // let bots not attack other bots (only works in non-team 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); diff --git a/qcsrc/server/mutators/events.qh b/qcsrc/server/mutators/events.qh index 89fec0178..e43f6a455 100644 --- a/qcsrc/server/mutators/events.qh +++ b/qcsrc/server/mutators/events.qh @@ -769,6 +769,8 @@ enum { /**/ 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); diff --git a/qcsrc/server/mutators/mutator/gamemode_singleplayer.qc b/qcsrc/server/mutators/mutator/gamemode_singleplayer.qc index b0b9f07f4..9e36f15c4 100644 --- a/qcsrc/server/mutators/mutator/gamemode_singleplayer.qc +++ b/qcsrc/server/mutators/mutator/gamemode_singleplayer.qc @@ -6,6 +6,7 @@ const int SP_TEAM_ENEMY = NUM_TEAM_2; .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. @@ -22,7 +23,7 @@ spawnfunc(sp_team) } // 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; @@ -42,6 +43,26 @@ spawnfunc(info_player_singleplayer) 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; } @@ -49,17 +70,18 @@ spawnfunc(info_player_singleplayer_enemy) 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); } } @@ -128,7 +150,8 @@ MUTATOR_HOOKFUNCTION(sp, Spawn_Score) 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 ) @@ -143,3 +166,12 @@ MUTATOR_HOOKFUNCTION(sp, HideTeamNagger) { 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; +} diff --git a/qcsrc/server/mutators/mutator/gamemode_singleplayer.qh b/qcsrc/server/mutators/mutator/gamemode_singleplayer.qh index 039aceb13..e7ead8637 100644 --- a/qcsrc/server/mutators/mutator/gamemode_singleplayer.qh +++ b/qcsrc/server/mutators/mutator/gamemode_singleplayer.qh @@ -2,7 +2,7 @@ #include "../gamemode.qh" -void sp_DelayedInit(entity this); +void sp_delayed_init(entity this); REGISTER_MUTATOR(sp, false) { @@ -10,7 +10,7 @@ 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);