From: Lyberta Date: Sun, 27 Aug 2017 23:44:07 +0000 (+0300) Subject: Merged master into Lyberta/TeamplayFixes_. X-Git-Tag: xonotic-v0.8.5~2482^2~1 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=04692f3bf447ec38a1bbb0a330c288bbe7a42726;hp=-c Merged master into Lyberta/TeamplayFixes_. --- 04692f3bf447ec38a1bbb0a330c288bbe7a42726 diff --combined qcsrc/server/client.qc index e255174c00,f1d417d6ba..1d3515e849 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@@ -1,5 -1,8 +1,8 @@@ #include "client.qh" + #include + #include + #include #include "anticheat.qh" #include "impulse.qh" #include "player.qh" @@@ -110,20 -113,18 +113,18 @@@ bool ClientData_Send(entity this, entit if (IS_SPEC(e)) e = e.enemy; sf = 0; - if (CS(e).race_completed) sf |= 1; // forced scoreboard - if (CS(to).spectatee_status) sf |= 2; // spectator ent number follows - if (CS(e).zoomstate) sf |= 4; // zoomed - if (autocvar_sv_showspectators) sf |= 16; // show spectators + if (CS(e).race_completed) sf |= BIT(0); // forced scoreboard + if (CS(to).spectatee_status) sf |= BIT(1); // spectator ent number follows + if (CS(e).zoomstate) sf |= BIT(2); // zoomed + if (autocvar_sv_showspectators) sf |= BIT(4); // show spectators WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA); WriteByte(MSG_ENTITY, sf); - if (sf & 2) - { + if (sf & BIT(1)) WriteByte(MSG_ENTITY, CS(to).spectatee_status); - } - if(sf & 16) + if(sf & BIT(4)) { float specs = CountSpectators(e, to); WriteByte(MSG_ENTITY, specs); @@@ -267,9 -268,7 +268,9 @@@ void PutObserverInServer(entity this if (mutator_returnvalue) { // mutator prevents resetting teams+score } else { + int oldteam = this.team; this.team = -1; // move this as it is needed to log the player spectating in eventlog + MUTATOR_CALLHOOK(Player_ChangedTeam, this, oldteam, this.team); this.frags = FRAGS_SPECTATOR; PlayerScore_Clear(this); // clear scores when needed } @@@ -893,10 -892,8 +894,10 @@@ void ClientKill_Now(entity this if(CS(this).killindicator_teamchange) ClientKill_Now_TeamChange(this); - if(!IS_SPEC(this) && !IS_OBSERVER(this)) + if (!IS_SPEC(this) && !IS_OBSERVER(this) && MUTATOR_CALLHOOK(ClientKill_Now, this) == false) + { Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0'); + } // now I am sure the player IS dead } @@@ -1190,7 -1187,10 +1191,10 @@@ void ClientConnect(entity this PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid)); // always track bots, don't ask for cl_allow_uidtracking - if (IS_BOT_CLIENT(this)) PlayerStats_GameReport_AddPlayer(this); + if (IS_BOT_CLIENT(this)) + PlayerStats_GameReport_AddPlayer(this); + else + CS(this).allowed_timeouts = autocvar_sv_timeout_number; if (autocvar_sv_eventlog) GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", playername(this, false))); @@@ -1239,7 -1239,6 +1243,6 @@@ } CS(this).jointime = time; - CS(this).allowed_timeouts = autocvar_sv_timeout_number; if (IS_REAL_CLIENT(this)) { @@@ -1623,7 -1622,6 +1626,6 @@@ void player_regen(entity this regen_health_stable = M_ARGV(9, float); regen_health_rotstable = M_ARGV(10, float); - if(!mutator_returnvalue) if(!STAT(FROZEN, this)) { @@@ -1662,6 -1660,18 +1664,18 @@@ this.ammo_fuel = CalcRotRegen(this.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > this.pauseregen_finished) * ((this.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > this.pauserotfuel_finished), limitf); } + // Ugly hack to make sure the health and armor don't go beyond hard limit. + // TODO: Remove this hack when all code uses GivePlayerHealth and + // GivePlayerArmor. + if (this.health > RESOURCE_AMOUNT_HARD_LIMIT) + { + this.health = RESOURCE_AMOUNT_HARD_LIMIT; + } + if (this.armorvalue > RESOURCE_AMOUNT_HARD_LIMIT) + { + this.armorvalue = RESOURCE_AMOUNT_HARD_LIMIT; + } + // End hack. } bool zoomstate_set; @@@ -2312,7 -2322,7 +2326,7 @@@ void ObserverThink(entity this TRANSMUTE(Spectator, this); } } else { - int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP); + int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? CS(this).cvar_cl_clippedspectating : !CS(this).cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP); set_movetype(this, preferred_movetype); } } else { @@@ -2450,6 -2460,9 +2464,9 @@@ Called every frame for each client befo .float last_vehiclecheck; void PlayerPreThink (entity this) { + STAT(GUNALIGN, this) = CS(this).cvar_cl_gunalign; // TODO + STAT(MOVEVARS_CL_TRACK_CANJUMP, this) = CS(this).cvar_cl_movement_track_canjump; + WarpZone_PlayerPhysics_FixVAngle(this); if (frametime) { @@@ -2479,19 -2492,19 +2496,19 @@@ } // version nagging - if (CS(this).version_nagtime && this.cvar_g_xonoticversion && time > CS(this).version_nagtime) { + if (CS(this).version_nagtime && CS(this).cvar_g_xonoticversion && time > CS(this).version_nagtime) { CS(this).version_nagtime = 0; - if (strstrofs(this.cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(this.cvar_g_xonoticversion, "autobuild", 0) >= 0) { + if (strstrofs(CS(this).cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(CS(this).cvar_g_xonoticversion, "autobuild", 0) >= 0) { // git client } else if (strstrofs(autocvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(autocvar_g_xonoticversion, "autobuild", 0) >= 0) { // git server - Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, this.cvar_g_xonoticversion); + Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, CS(this).cvar_g_xonoticversion); } else { - int r = vercmp(this.cvar_g_xonoticversion, autocvar_g_xonoticversion); + int r = vercmp(CS(this).cvar_g_xonoticversion, autocvar_g_xonoticversion); if (r < 0) { // old client - Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, this.cvar_g_xonoticversion); + Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, CS(this).cvar_g_xonoticversion); } else if (r > 0) { // old server - Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, this.cvar_g_xonoticversion); + Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, CS(this).cvar_g_xonoticversion); } } } @@@ -2555,7 -2568,7 +2572,7 @@@ this.last_vehiclecheck = time + 1; } - if(!this.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button + if(!CS(this).cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button { if(PHYS_INPUT_BUTTON_USE(this) && !CS(this).usekeypressed) PlayerUseKey(this); diff --combined qcsrc/server/client.qh index 2928aae1c9,9674872c0f..2282c09cbb --- a/qcsrc/server/client.qh +++ b/qcsrc/server/client.qh @@@ -1,5 -1,8 +1,8 @@@ #pragma once + #include "utils.qh" + #include + void ClientState_attach(entity this); IntrusiveList g_players; @@@ -107,8 -110,40 +110,40 @@@ CLASS(Client, Object ATTRIB(Client, specialcommand_pos, int, this.specialcommand_pos); ATTRIB(Client, hitplotfh, int, this.hitplotfh); ATTRIB(Client, clientdata, entity, this.clientdata); + ATTRIB(Client, cmd_floodcount, int, this.cmd_floodcount); + ATTRIB(Client, cmd_floodtime, float, this.cmd_floodtime); ATTRIB(Client, wasplayer, bool, this.wasplayer); + // networked cvars + + ATTRIB(Client, cvar_cl_allow_uid2name, int, this.cvar_cl_allow_uid2name); + ATTRIB(Client, cvar_cl_allow_uidtracking, int, this.cvar_cl_allow_uidtracking); + ATTRIB(Client, cvar_cl_autotaunt, float, this.cvar_cl_autotaunt); + ATTRIB(Client, cvar_cl_voice_directional, int, this.cvar_cl_voice_directional); + ATTRIB(Client, cvar_cl_voice_directional_taunt_attenuation, float, this.cvar_cl_voice_directional_taunt_attenuation); + ATTRIB(Client, cvar_cl_physics, string, this.cvar_cl_physics); + ATTRIB(Client, cvar_cl_buffs_autoreplace, bool, this.cvar_cl_buffs_autoreplace); + ATTRIB(Client, cvar_cl_nade_type, int, this.cvar_cl_nade_type); + ATTRIB(Client, cvar_cl_pokenade_type, string, this.cvar_cl_pokenade_type); + ATTRIB(Client, cvar_cl_spawn_near_teammate, bool, this.cvar_cl_spawn_near_teammate); + ATTRIB(Client, cvar_cl_gunalign, int, this.cvar_cl_gunalign); + ATTRIB(Client, cvar_cl_handicap, float, this.cvar_cl_handicap); + ATTRIB(Client, cvar_cl_clippedspectating, bool, this.cvar_cl_clippedspectating); + ATTRIB(Client, cvar_cl_autoscreenshot, int, this.cvar_cl_autoscreenshot); + ATTRIB(Client, cvar_cl_jetpack_jump, bool, this.cvar_cl_jetpack_jump); + ATTRIB(Client, cvar_cl_newusekeysupported, bool, this.cvar_cl_newusekeysupported); + ATTRIB(Client, cvar_cl_noantilag, bool, this.cvar_cl_noantilag); + ATTRIB(Client, cvar_cl_movement_track_canjump, bool, this.cvar_cl_movement_track_canjump); + ATTRIB(Client, cvar_cl_weaponimpulsemode, int, this.cvar_cl_weaponimpulsemode); + ATTRIB(Client, cvar_g_xonoticversion, string, this.cvar_g_xonoticversion); + ATTRIB(Client, autoswitch, bool, this.autoswitch); + ATTRIB(Client, cvar_cl_dodging_timeout, float, this.cvar_cl_dodging_timeout); + ATTRIB(Client, cvar_cl_multijump, bool, this.cvar_cl_multijump); + ATTRIB(Client, cvar_cl_accuracy_data_share, bool, this.cvar_cl_accuracy_data_share); + ATTRIB(Client, cvar_cl_accuracy_data_receive, bool, this.cvar_cl_accuracy_data_receive); + ATTRIBARRAY(Client, cvar_cl_weaponpriorities, string, 10); + ATTRIB(Client, cvar_cl_weaponpriority, string, this.cvar_cl_weaponpriority); + METHOD(Client, m_unwind, bool(Client this)); STATIC_METHOD(Client, Add, void(Client this, int _team)); @@@ -189,6 -224,8 +224,6 @@@ METHOD(Client, m_unwind, bool(Client th return false; } -float c1, c2, c3, c4; - void play_countdown(entity this, float finished, Sound samp); float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit); diff --combined qcsrc/server/command/cmd.qc index 297ab8f0f3,a2c037c5d2..09a308ad5c --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@@ -1,4 -1,8 +1,8 @@@ #include "cmd.qh" + + #include + #include + #include #include "common.qh" @@@ -45,17 -49,19 +49,19 @@@ void ClientKill_TeamChange(entity this bool SV_ParseClientCommand_floodcheck(entity this) { + entity store = IS_CLIENT(this) ? CS(this) : this; // unfortunately, we need to store these on the client initially + if (!timeout_status) // not while paused { - if (time <= (this.cmd_floodtime + autocvar_sv_clientcommand_antispam_time)) + if (time <= (store.cmd_floodtime + autocvar_sv_clientcommand_antispam_time)) { - this.cmd_floodcount += 1; - if (this.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) return false; // too much spam, halt + store.cmd_floodcount += 1; + if (store.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) return false; // too much spam, halt } else { - this.cmd_floodtime = time; - this.cmd_floodcount = 1; + store.cmd_floodtime = time; + store.cmd_floodcount = 1; } } return true; // continue, as we're not flooding yet @@@ -74,8 -80,8 +80,8 @@@ void ClientCommand_autoswitch(entity ca { if (argv(1) != "") { - caller.autoswitch = InterpretBoolean(argv(1)); - sprint(caller, strcat("^1autoswitch is currently turned ", (caller.autoswitch ? "on" : "off"), ".\n")); + CS(caller).autoswitch = InterpretBoolean(argv(1)); + sprint(caller, strcat("^1autoswitch is currently turned ", (CS(caller).autoswitch ? "on" : "off"), ".\n")); return; } } @@@ -214,7 -220,7 +220,7 @@@ void ClientCommand_physics(entity calle } default: - sprint(caller, strcat("Current physics set: ^3", caller.cvar_cl_physics, "\n")); + sprint(caller, strcat("Current physics set: ^3", CS(caller).cvar_cl_physics, "\n")); case CMD_REQUEST_USAGE: { sprint(caller, "\nUsage:^3 cmd physics \n"); @@@ -319,90 -325,82 +325,90 @@@ void ClientCommand_selectteam(entity ca { case CMD_REQUEST_COMMAND: { - if (argv(1) != "") + if (argv(1) == "") { - if (IS_CLIENT(caller)) + return; + } + if (!IS_CLIENT(caller)) + { + return; + } + if (!teamplay) + { + sprint(caller, "^7selectteam can only be used in teamgames\n"); + return; + } + if (caller.team_forced > 0) + { + sprint(caller, "^7selectteam can not be used as your team is forced\n"); + return; + } + if (lockteams) + { + sprint(caller, "^7The game has already begun, you must wait until the next map to be able to join a team.\n"); + return; + } + float selection; + switch (argv(1)) + { + case "red": { - if (teamplay) - { - if (caller.team_forced <= 0) - { - if (!lockteams) - { - float selection; - - switch (argv(1)) - { - case "red": selection = NUM_TEAM_1; - break; - case "blue": selection = NUM_TEAM_2; - break; - case "yellow": selection = NUM_TEAM_3; - break; - case "pink": selection = NUM_TEAM_4; - break; - case "auto": selection = (-1); - break; - - default: selection = 0; - break; - } - - if (selection) - { - if (caller.team == selection && selection != -1 && !IS_DEAD(caller)) - { - sprint(caller, "^7You already are on that team.\n"); - } - else if (CS(caller).wasplayer && autocvar_g_changeteam_banned) - { - sprint(caller, "^1You cannot change team, forbidden by the server.\n"); - } - else - { - if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance) - { - CheckAllowedTeams(caller); - GetTeamCounts(caller); - if (!TeamSmallerEqThanTeam(Team_TeamToNumber(selection), Team_TeamToNumber(caller.team), caller)) - { - Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM); - return; - } - } - ClientKill_TeamChange(caller, selection); - } - if(!IS_PLAYER(caller)) - caller.team_selected = true; // avoids asking again for team selection on join - } - } - else - { - sprint(caller, "^7The game has already begun, you must wait until the next map to be able to join a team.\n"); - } - } - else - { - sprint(caller, "^7selectteam can not be used as your team is forced\n"); - } - } - else - { - sprint(caller, "^7selectteam can only be used in teamgames\n"); - } + selection = NUM_TEAM_1; + break; + } + case "blue": + { + selection = NUM_TEAM_2; + break; } + case "yellow": + { + selection = NUM_TEAM_3; + break; + } + case "pink": + { + selection = NUM_TEAM_4; + break; + } + case "auto": + { + selection = (-1); + break; + } + default: + { + return; + } + } + if (caller.team == selection && selection != -1 && !IS_DEAD(caller)) + { + sprint(caller, "^7You already are on that team.\n"); + return; + } + if (CS(caller).wasplayer && autocvar_g_changeteam_banned) + { + sprint(caller, "^1You cannot change team, forbidden by the server.\n"); return; } + if ((selection != -1) && autocvar_g_balance_teams && + autocvar_g_balance_teams_prevent_imbalance) + { + CheckAllowedTeams(caller); + GetTeamCounts(caller); + if ((BIT(Team_TeamToNumber(selection) - 1) & FindBestTeams(caller, false)) == 0) + { + Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM); + return; + } + } + ClientKill_TeamChange(caller, selection); + if (!IS_PLAYER(caller)) + { + caller.team_selected = true; // avoids asking again for team selection on join + } + return; } - default: sprint(caller, "Incorrect parameters for ^2selectteam^7\n"); case CMD_REQUEST_USAGE: @@@ -456,7 -454,7 +462,7 @@@ void ClientCommand_sentcvar(entity call tokenize_console(s); } - GetCvars(caller, 1); + GetCvars(caller, CS(caller), 1); return; } diff --combined qcsrc/server/command/sv_cmd.qc index 4687403d2a,2bb0f1365c..f5569c08f2 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@@ -1,6 -1,8 +1,8 @@@ #include "sv_cmd.qh" #include "_mod.qh" + #include + #include "banning.qh" #include "cmd.qh" #include "common.qh" @@@ -41,7 -43,7 +43,7 @@@ void make_mapinfo_Think(entity this { if (_MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1)) { - LOG_INFO("Done rebuiling mapinfos.\n"); + LOG_INFO("Done rebuiling mapinfos."); MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); delete(this); } @@@ -123,7 -125,7 +125,7 @@@ void GameCommand_adminmsg(float request if (accepted <= 0) { - LOG_INFO("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n")); + LOG_INFO("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".")); continue; } @@@ -144,22 -146,22 +146,22 @@@ } if (successful) bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n"); - else LOG_INFO("No players given (", original_targets, ") could receive the message.\n"); + else LOG_INFO("No players given (", original_targets, ") could receive the message."); return; } } default: - LOG_INFO("Incorrect parameters for ^2adminmsg^7\n"); + LOG_INFO("Incorrect parameters for ^2adminmsg^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd adminmsg clients \"message\" [infobartime]\n"); - LOG_INFO(" 'clients' is a list (separated by commas) of player entity ID's or nicknames\n"); - LOG_INFO(" If infobartime is provided, the message will be sent to infobar.\n"); - LOG_INFO(" Otherwise, it will just be sent as a centerprint message.\n"); - LOG_INFO("Examples: adminmsg 2,4 \"this infomessage will last for ten seconds\" 10\n"); - LOG_INFO(" adminmsg 2,5 \"this message will be a centerprint\"\n"); + LOG_INFO("Usage:^3 sv_cmd adminmsg clients \"message\" [infobartime]"); + LOG_INFO(" 'clients' is a list (separated by commas) of player entity ID's or nicknames"); + LOG_INFO(" If infobartime is provided, the message will be sent to infobar."); + LOG_INFO(" Otherwise, it will just be sent as a centerprint message."); + LOG_INFO("Examples: adminmsg 2,4 \"this infomessage will last for ten seconds\" 10"); + LOG_INFO(" adminmsg 2,5 \"this message will be a centerprint\""); return; } } @@@ -178,8 -180,8 +180,8 @@@ void GameCommand_allready(float request default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd allready\n"); - LOG_INFO(" No arguments required.\n"); + LOG_INFO("Usage:^3 sv_cmd allready"); + LOG_INFO(" No arguments required."); return; } } @@@ -199,16 -201,16 +201,16 @@@ void GameCommand_allspec(float request ++n; }); if (n) bprint(strcat("Successfully forced all (", ftos(n), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n")); - else LOG_INFO("No players found to spectate.\n"); + else LOG_INFO("No players found to spectate."); return; } default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd allspec [reason]\n"); - LOG_INFO(" Where 'reason' is an optional argument for explanation of allspec command.\n"); - LOG_INFO("See also: ^2moveplayer, shuffleteams^7\n"); + LOG_INFO("Usage:^3 sv_cmd allspec [reason]"); + LOG_INFO(" Where 'reason' is an optional argument for explanation of allspec command."); + LOG_INFO("See also: ^2moveplayer, shuffleteams^7"); return; } } @@@ -230,16 -232,16 +232,16 @@@ void GameCommand_anticheat(float reques } else { - LOG_INFO("anticheat: ", GetClientErrorString(accepted, argv(1)), ".\n"); + LOG_INFO("anticheat: ", GetClientErrorString(accepted, argv(1)), "."); } } default: - LOG_INFO("Incorrect parameters for ^2anticheat^7\n"); + LOG_INFO("Incorrect parameters for ^2anticheat^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd anticheat client\n"); - LOG_INFO(" 'client' is the entity number or name of the player.\n"); + LOG_INFO("Usage:^3 sv_cmd anticheat client"); + LOG_INFO(" 'client' is the entity number or name of the player."); return; } } @@@ -301,18 -303,18 +303,18 @@@ void GameCommand_bbox(float request NULL); size_max.z = (trace_startsolid) ? world.absmax.z : trace_endpos.z; - LOG_INFOF("Original size: %v %v\n", world.absmin, world.absmax); - LOG_INFOF("Currently set size: %v %v\n", world.mins, world.maxs); - LOG_INFOF("Solid bounding box size: %v %v\n", size_min, size_max); + LOG_INFOF("Original size: %v %v", world.absmin, world.absmax); + LOG_INFOF("Currently set size: %v %v", world.mins, world.maxs); + LOG_INFOF("Solid bounding box size: %v %v", size_min, size_max); return; } default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd bbox\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2gettaginfo, trace^7\n"); + LOG_INFO("Usage:^3 sv_cmd bbox"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2gettaginfo, trace^7"); return; } } @@@ -338,7 -340,7 +340,7 @@@ void GameCommand_bot_cmd(float request cvar_settemp("bot_number", "0"); bot_fixcount(); cvar_settemp("bot_number", argv(2)); - if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count\n"); + if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count"); return; } else if (argv(1) == "load" && argc == 3) @@@ -348,7 -350,7 +350,7 @@@ fh = fopen(argv(2), FILE_READ); if (fh < 0) { - LOG_INFO("cannot open the file\n"); + LOG_INFO("cannot open the file"); return; } @@@ -370,7 -372,7 +372,7 @@@ cvar_settemp("bot_number", "0"); bot_fixcount(); cvar_settemp("bot_number", argv(3)); - if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count\n"); + if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count"); } else { @@@ -393,7 -395,7 +395,7 @@@ ++i; } - LOG_INFO(ftos(i), " commands read\n"); + LOG_INFO(ftos(i), " commands read"); fclose(fh); return; } @@@ -413,7 -415,7 +415,7 @@@ bot_num++; }); if(bot_num) - LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to all bots (", ftos(bot_num), ")\n")); + LOG_INFO("Command '", substring(command, argv_start_index(2), -1), "' sent to all bots (", ftos(bot_num), ")"); return; } else @@@ -422,29 -424,29 +424,29 @@@ if (bot == NULL) bot = find_bot_by_name(argv(1)); if (bot) { - LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname, "\n")); + LOG_INFO("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname); bot_queuecommand(bot, substring(command, argv_start_index(2), -1)); return; } else { - LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?\n")); // don't return so that usage is shown + LOG_INFO("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?"); // don't return so that usage is shown } } } } default: - LOG_INFO("Incorrect parameters for ^2bot_cmd^7\n"); + LOG_INFO("Incorrect parameters for ^2bot_cmd^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd bot_cmd client command [argument]\n"); - LOG_INFO(" 'client' can be either the name of the bot or a progressive number (not the entity number!)\n"); - LOG_INFO(" can also be '*' or 'all' to allow sending the command to all the bots\n"); - LOG_INFO(" For full list of commands, see bot_cmd help [command].\n"); - LOG_INFO("Examples: sv_cmd bot_cmd 1 cc \"say something\"\n"); - LOG_INFO(" sv_cmd bot_cmd 1 presskey jump\n"); - LOG_INFO(" sv_cmd bot_cmd * pause\n"); + LOG_INFO("Usage:^3 sv_cmd bot_cmd client command [argument]"); + LOG_INFO(" 'client' can be either the name of the bot or a progressive number (not the entity number!)"); + LOG_INFO(" can also be '*' or 'all' to allow sending the command to all the bots"); + LOG_INFO(" For full list of commands, see bot_cmd help [command]."); + LOG_INFO("Examples: sv_cmd bot_cmd 1 cc \"say something\""); + LOG_INFO(" sv_cmd bot_cmd 1 presskey jump"); + LOG_INFO(" sv_cmd bot_cmd * pause"); return; } } @@@ -467,8 -469,8 +469,8 @@@ void GameCommand_cointoss(float request default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd cointoss [result1 result2]\n"); - LOG_INFO(" Where 'result1' and 'result2' are user created options.\n"); + LOG_INFO("Usage:^3 sv_cmd cointoss [result1 result2]"); + LOG_INFO(" Where 'result1' and 'result2' are user created options."); return; } } @@@ -485,33 -487,33 +487,33 @@@ void GameCommand_database(float request if (argv(1) == "save") { db_save(ServerProgsDB, argv(2)); - LOG_INFO(strcat("Copied serverprogs database to '", argv(2), "' in the data directory.\n")); + LOG_INFO("Copied serverprogs database to '", argv(2), "' in the data directory."); return; } else if (argv(1) == "dump") { db_dump(ServerProgsDB, argv(2)); - LOG_INFO("DB dumped.\n"); // wtf does this do? + LOG_INFO("DB dumped."); // wtf does this do? return; } else if (argv(1) == "load") { db_close(ServerProgsDB); ServerProgsDB = db_load(argv(2)); - LOG_INFO(strcat("Loaded '", argv(2), "' as new serverprogs database.\n")); + LOG_INFO("Loaded '", argv(2), "' as new serverprogs database."); return; } } } default: - LOG_INFO("Incorrect parameters for ^2database^7\n"); + LOG_INFO("Incorrect parameters for ^2database^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd database action filename\n"); - LOG_INFO(" Where 'action' is the command to complete,\n"); - LOG_INFO(" and 'filename' is what it acts upon.\n"); - LOG_INFO(" Full list of commands here: \"save, dump, load.\"\n"); + LOG_INFO("Usage:^3 sv_cmd database action filename"); + LOG_INFO(" Where 'action' is the command to complete,"); + LOG_INFO(" and 'filename' is what it acts upon."); + LOG_INFO(" Full list of commands here: \"save, dump, load.\""); return; } } @@@ -534,21 -536,21 +536,21 @@@ void GameCommand_defer_clear(float requ if (accepted > 0) { stuffcmd(client, "defer clear\n"); - LOG_INFO("defer clear stuffed to ", playername(client, false), "\n"); + LOG_INFO("defer clear stuffed to ", playername(client, false)); } - else { LOG_INFO("defer_clear: ", GetClientErrorString(accepted, argv(1)), ".\n"); } + else { LOG_INFO("defer_clear: ", GetClientErrorString(accepted, argv(1)), "."); } return; } } default: - LOG_INFO("Incorrect parameters for ^2defer_clear^7\n"); + LOG_INFO("Incorrect parameters for ^2defer_clear^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd defer_clear client\n"); - LOG_INFO(" 'client' is the entity number or name of the player.\n"); - LOG_INFO("See also: ^2defer_clear_all^7\n"); + LOG_INFO("Usage:^3 sv_cmd defer_clear client"); + LOG_INFO(" 'client' is the entity number or name of the player."); + LOG_INFO("See also: ^2defer_clear_all^7"); return; } } @@@ -568,16 -570,16 +570,16 @@@ void GameCommand_defer_clear_all(float GameCommand_defer_clear(CMD_REQUEST_COMMAND, argc); ++n; }); - if (n) LOG_INFO(strcat("Successfully stuffed defer clear to all clients (", ftos(n), ")\n")); // should a message be added if no players were found? + if (n) LOG_INFO("Successfully stuffed defer clear to all clients (", ftos(n), ")"); // should a message be added if no players were found? return; } default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd defer_clear_all\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2defer_clear^7\n"); + LOG_INFO("Usage:^3 sv_cmd defer_clear_all"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2defer_clear^7"); return; } } @@@ -598,13 -600,13 +600,13 @@@ void GameCommand_delrec(float request, } default: - LOG_INFO("Incorrect parameters for ^2delrec^7\n"); + LOG_INFO("Incorrect parameters for ^2delrec^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd delrec ranking [map]\n"); - LOG_INFO(" 'ranking' is which ranking level to clear up to, \n"); - LOG_INFO(" it will clear all records up to nth place.\n"); - LOG_INFO(" if 'map' is not provided it will use current map.\n"); + LOG_INFO("Usage:^3 sv_cmd delrec ranking [map]"); + LOG_INFO(" 'ranking' is which ranking level to clear up to, "); + LOG_INFO(" it will clear all records up to nth place."); + LOG_INFO(" if 'map' is not provided it will use current map."); return; } } @@@ -620,79 -622,79 +622,79 @@@ void GameCommand_effectindexdump(float string s; d = db_create(); - LOG_INFO("begin of effects list\n"); + LOG_INFO("begin of effects list"); db_put(d, "TE_GUNSHOT", "1"); - LOG_INFO("effect TE_GUNSHOT is ", ftos(_particleeffectnum("TE_GUNSHOT")), "\n"); + LOG_INFO("effect TE_GUNSHOT is ", ftos(_particleeffectnum("TE_GUNSHOT"))); db_put(d, "TE_GUNSHOTQUAD", "1"); - LOG_INFO("effect TE_GUNSHOTQUAD is ", ftos(_particleeffectnum("TE_GUNSHOTQUAD")), "\n"); + LOG_INFO("effect TE_GUNSHOTQUAD is ", ftos(_particleeffectnum("TE_GUNSHOTQUAD"))); db_put(d, "TE_SPIKE", "1"); - LOG_INFO("effect TE_SPIKE is ", ftos(_particleeffectnum("TE_SPIKE")), "\n"); + LOG_INFO("effect TE_SPIKE is ", ftos(_particleeffectnum("TE_SPIKE"))); db_put(d, "TE_SPIKEQUAD", "1"); - LOG_INFO("effect TE_SPIKEQUAD is ", ftos(_particleeffectnum("TE_SPIKEQUAD")), "\n"); + LOG_INFO("effect TE_SPIKEQUAD is ", ftos(_particleeffectnum("TE_SPIKEQUAD"))); db_put(d, "TE_SUPERSPIKE", "1"); - LOG_INFO("effect TE_SUPERSPIKE is ", ftos(_particleeffectnum("TE_SUPERSPIKE")), "\n"); + LOG_INFO("effect TE_SUPERSPIKE is ", ftos(_particleeffectnum("TE_SUPERSPIKE"))); db_put(d, "TE_SUPERSPIKEQUAD", "1"); - LOG_INFO("effect TE_SUPERSPIKEQUAD is ", ftos(_particleeffectnum("TE_SUPERSPIKEQUAD")), "\n"); + LOG_INFO("effect TE_SUPERSPIKEQUAD is ", ftos(_particleeffectnum("TE_SUPERSPIKEQUAD"))); db_put(d, "TE_WIZSPIKE", "1"); - LOG_INFO("effect TE_WIZSPIKE is ", ftos(_particleeffectnum("TE_WIZSPIKE")), "\n"); + LOG_INFO("effect TE_WIZSPIKE is ", ftos(_particleeffectnum("TE_WIZSPIKE"))); db_put(d, "TE_KNIGHTSPIKE", "1"); - LOG_INFO("effect TE_KNIGHTSPIKE is ", ftos(_particleeffectnum("TE_KNIGHTSPIKE")), "\n"); + LOG_INFO("effect TE_KNIGHTSPIKE is ", ftos(_particleeffectnum("TE_KNIGHTSPIKE"))); db_put(d, "TE_EXPLOSION", "1"); - LOG_INFO("effect TE_EXPLOSION is ", ftos(_particleeffectnum("TE_EXPLOSION")), "\n"); + LOG_INFO("effect TE_EXPLOSION is ", ftos(_particleeffectnum("TE_EXPLOSION"))); db_put(d, "TE_EXPLOSIONQUAD", "1"); - LOG_INFO("effect TE_EXPLOSIONQUAD is ", ftos(_particleeffectnum("TE_EXPLOSIONQUAD")), "\n"); + LOG_INFO("effect TE_EXPLOSIONQUAD is ", ftos(_particleeffectnum("TE_EXPLOSIONQUAD"))); db_put(d, "TE_TAREXPLOSION", "1"); - LOG_INFO("effect TE_TAREXPLOSION is ", ftos(_particleeffectnum("TE_TAREXPLOSION")), "\n"); + LOG_INFO("effect TE_TAREXPLOSION is ", ftos(_particleeffectnum("TE_TAREXPLOSION"))); db_put(d, "TE_TELEPORT", "1"); - LOG_INFO("effect TE_TELEPORT is ", ftos(_particleeffectnum("TE_TELEPORT")), "\n"); + LOG_INFO("effect TE_TELEPORT is ", ftos(_particleeffectnum("TE_TELEPORT"))); db_put(d, "TE_LAVASPLASH", "1"); - LOG_INFO("effect TE_LAVASPLASH is ", ftos(_particleeffectnum("TE_LAVASPLASH")), "\n"); + LOG_INFO("effect TE_LAVASPLASH is ", ftos(_particleeffectnum("TE_LAVASPLASH"))); db_put(d, "TE_SMALLFLASH", "1"); - LOG_INFO("effect TE_SMALLFLASH is ", ftos(_particleeffectnum("TE_SMALLFLASH")), "\n"); + LOG_INFO("effect TE_SMALLFLASH is ", ftos(_particleeffectnum("TE_SMALLFLASH"))); db_put(d, "TE_FLAMEJET", "1"); - LOG_INFO("effect TE_FLAMEJET is ", ftos(_particleeffectnum("TE_FLAMEJET")), "\n"); + LOG_INFO("effect TE_FLAMEJET is ", ftos(_particleeffectnum("TE_FLAMEJET"))); db_put(d, "EF_FLAME", "1"); - LOG_INFO("effect EF_FLAME is ", ftos(_particleeffectnum("EF_FLAME")), "\n"); + LOG_INFO("effect EF_FLAME is ", ftos(_particleeffectnum("EF_FLAME"))); db_put(d, "TE_BLOOD", "1"); - LOG_INFO("effect TE_BLOOD is ", ftos(_particleeffectnum("TE_BLOOD")), "\n"); + LOG_INFO("effect TE_BLOOD is ", ftos(_particleeffectnum("TE_BLOOD"))); db_put(d, "TE_SPARK", "1"); - LOG_INFO("effect TE_SPARK is ", ftos(_particleeffectnum("TE_SPARK")), "\n"); + LOG_INFO("effect TE_SPARK is ", ftos(_particleeffectnum("TE_SPARK"))); db_put(d, "TE_PLASMABURN", "1"); - LOG_INFO("effect TE_PLASMABURN is ", ftos(_particleeffectnum("TE_PLASMABURN")), "\n"); + LOG_INFO("effect TE_PLASMABURN is ", ftos(_particleeffectnum("TE_PLASMABURN"))); db_put(d, "TE_TEI_G3", "1"); - LOG_INFO("effect TE_TEI_G3 is ", ftos(_particleeffectnum("TE_TEI_G3")), "\n"); + LOG_INFO("effect TE_TEI_G3 is ", ftos(_particleeffectnum("TE_TEI_G3"))); db_put(d, "TE_TEI_SMOKE", "1"); - LOG_INFO("effect TE_TEI_SMOKE is ", ftos(_particleeffectnum("TE_TEI_SMOKE")), "\n"); + LOG_INFO("effect TE_TEI_SMOKE is ", ftos(_particleeffectnum("TE_TEI_SMOKE"))); db_put(d, "TE_TEI_BIGEXPLOSION", "1"); - LOG_INFO("effect TE_TEI_BIGEXPLOSION is ", ftos(_particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n"); + LOG_INFO("effect TE_TEI_BIGEXPLOSION is ", ftos(_particleeffectnum("TE_TEI_BIGEXPLOSION"))); db_put(d, "TE_TEI_PLASMAHIT", "1"); - LOG_INFO("effect TE_TEI_PLASMAHIT is ", ftos(_particleeffectnum("TE_TEI_PLASMAHIT")), "\n"); + LOG_INFO("effect TE_TEI_PLASMAHIT is ", ftos(_particleeffectnum("TE_TEI_PLASMAHIT"))); db_put(d, "EF_STARDUST", "1"); - LOG_INFO("effect EF_STARDUST is ", ftos(_particleeffectnum("EF_STARDUST")), "\n"); + LOG_INFO("effect EF_STARDUST is ", ftos(_particleeffectnum("EF_STARDUST"))); db_put(d, "TR_ROCKET", "1"); - LOG_INFO("effect TR_ROCKET is ", ftos(_particleeffectnum("TR_ROCKET")), "\n"); + LOG_INFO("effect TR_ROCKET is ", ftos(_particleeffectnum("TR_ROCKET"))); db_put(d, "TR_GRENADE", "1"); - LOG_INFO("effect TR_GRENADE is ", ftos(_particleeffectnum("TR_GRENADE")), "\n"); + LOG_INFO("effect TR_GRENADE is ", ftos(_particleeffectnum("TR_GRENADE"))); db_put(d, "TR_BLOOD", "1"); - LOG_INFO("effect TR_BLOOD is ", ftos(_particleeffectnum("TR_BLOOD")), "\n"); + LOG_INFO("effect TR_BLOOD is ", ftos(_particleeffectnum("TR_BLOOD"))); db_put(d, "TR_WIZSPIKE", "1"); - LOG_INFO("effect TR_WIZSPIKE is ", ftos(_particleeffectnum("TR_WIZSPIKE")), "\n"); + LOG_INFO("effect TR_WIZSPIKE is ", ftos(_particleeffectnum("TR_WIZSPIKE"))); db_put(d, "TR_SLIGHTBLOOD", "1"); - LOG_INFO("effect TR_SLIGHTBLOOD is ", ftos(_particleeffectnum("TR_SLIGHTBLOOD")), "\n"); + LOG_INFO("effect TR_SLIGHTBLOOD is ", ftos(_particleeffectnum("TR_SLIGHTBLOOD"))); db_put(d, "TR_KNIGHTSPIKE", "1"); - LOG_INFO("effect TR_KNIGHTSPIKE is ", ftos(_particleeffectnum("TR_KNIGHTSPIKE")), "\n"); + LOG_INFO("effect TR_KNIGHTSPIKE is ", ftos(_particleeffectnum("TR_KNIGHTSPIKE"))); db_put(d, "TR_VORESPIKE", "1"); - LOG_INFO("effect TR_VORESPIKE is ", ftos(_particleeffectnum("TR_VORESPIKE")), "\n"); + LOG_INFO("effect TR_VORESPIKE is ", ftos(_particleeffectnum("TR_VORESPIKE"))); db_put(d, "TR_NEHAHRASMOKE", "1"); - LOG_INFO("effect TR_NEHAHRASMOKE is ", ftos(_particleeffectnum("TR_NEHAHRASMOKE")), "\n"); + LOG_INFO("effect TR_NEHAHRASMOKE is ", ftos(_particleeffectnum("TR_NEHAHRASMOKE"))); db_put(d, "TR_NEXUIZPLASMA", "1"); - LOG_INFO("effect TR_NEXUIZPLASMA is ", ftos(_particleeffectnum("TR_NEXUIZPLASMA")), "\n"); + LOG_INFO("effect TR_NEXUIZPLASMA is ", ftos(_particleeffectnum("TR_NEXUIZPLASMA"))); db_put(d, "TR_GLOWTRAIL", "1"); - LOG_INFO("effect TR_GLOWTRAIL is ", ftos(_particleeffectnum("TR_GLOWTRAIL")), "\n"); + LOG_INFO("effect TR_GLOWTRAIL is ", ftos(_particleeffectnum("TR_GLOWTRAIL"))); db_put(d, "TR_SEEKER", "1"); - LOG_INFO("effect TR_SEEKER is ", ftos(_particleeffectnum("TR_SEEKER")), "\n"); + LOG_INFO("effect TR_SEEKER is ", ftos(_particleeffectnum("TR_SEEKER"))); db_put(d, "SVC_PARTICLE", "1"); - LOG_INFO("effect SVC_PARTICLE is ", ftos(_particleeffectnum("SVC_PARTICLE")), "\n"); + LOG_INFO("effect SVC_PARTICLE is ", ftos(_particleeffectnum("SVC_PARTICLE"))); fh = fopen("effectinfo.txt", FILE_READ); while ((s = fgets(fh))) @@@ -703,12 -705,12 +705,12 @@@ if (db_get(d, argv(1)) != "1") { int i = _particleeffectnum(argv(1)); - if (i >= 0) LOG_INFO("effect ", argv(1), " is ", ftos(i), "\n"); + if (i >= 0) LOG_INFO("effect ", argv(1), " is ", ftos(i)); db_put(d, argv(1), "1"); } } } - LOG_INFO("end of effects list\n"); + LOG_INFO("end of effects list"); db_close(d); return; @@@ -717,8 -719,8 +719,8 @@@ default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd effectindexdump\n"); - LOG_INFO(" No arguments required.\n"); + LOG_INFO("Usage:^3 sv_cmd effectindexdump"); + LOG_INFO(" No arguments required."); return; } } @@@ -737,9 -739,9 +739,9 @@@ void GameCommand_extendmatchtime(float default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd extendmatchtime\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2reducematchtime^7\n"); + LOG_INFO("Usage:^3 sv_cmd extendmatchtime"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2reducematchtime^7"); return; } } @@@ -784,12 -786,12 +786,12 @@@ void GameCommand_gametype(float request } default: - LOG_INFO("Incorrect parameters for ^2gametype^7\n"); + LOG_INFO("Incorrect parameters for ^2gametype^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd gametype mode\n"); - LOG_INFO(" Where 'mode' is the gametype mode to switch to.\n"); - LOG_INFO("See also: ^2gotomap^7\n"); + LOG_INFO("Usage:^3 sv_cmd gametype mode"); + LOG_INFO(" Where 'mode' is the gametype mode to switch to."); + LOG_INFO("See also: ^2gotomap^7"); return; } } @@@ -824,13 -826,15 +826,15 @@@ void GameCommand_gettaginfo(float reque if (i) { v = gettaginfo(tmp_entity, i); - LOG_INFO("model ", tmp_entity.model, " frame ", ftos(tmp_entity.frame), " tag ", gettaginfo_name); - LOG_INFO(" index ", ftos(i), " parent ", ftos(gettaginfo_parent), "\n"); - LOG_INFO(" vector = ", ftos(v.x), " ", ftos(v.y), " ", ftos(v.z), "\n"); - LOG_INFO(" offset = ", ftos(gettaginfo_offset.x), " ", ftos(gettaginfo_offset.y), " ", ftos(gettaginfo_offset.z), "\n"); - LOG_INFO(" forward = ", ftos(gettaginfo_forward.x), " ", ftos(gettaginfo_forward.y), " ", ftos(gettaginfo_forward.z), "\n"); - LOG_INFO(" right = ", ftos(gettaginfo_right.x), " ", ftos(gettaginfo_right.y), " ", ftos(gettaginfo_right.z), "\n"); - LOG_INFO(" up = ", ftos(gettaginfo_up.x), " ", ftos(gettaginfo_up.y), " ", ftos(gettaginfo_up.z), "\n"); + LOG_INFOF( + "model %s frame %s tag %s index %s parent %s", + tmp_entity.model, ftos(tmp_entity.frame), gettaginfo_name, ftos(i), ftos(gettaginfo_parent) + ); + LOG_INFOF(" vector = %s %s %s", ftos(v.x), ftos(v.y), ftos(v.z)); + LOG_INFOF(" offset = %s %s %s", ftos(gettaginfo_offset.x), ftos(gettaginfo_offset.y), ftos(gettaginfo_offset.z)); + LOG_INFOF(" forward = %s %s %s", ftos(gettaginfo_forward.x), ftos(gettaginfo_forward.y), ftos(gettaginfo_forward.z)); + LOG_INFOF(" right = %s %s %s", ftos(gettaginfo_right.x), ftos(gettaginfo_right.y), ftos(gettaginfo_right.z)); + LOG_INFOF(" up = %s %s %s", ftos(gettaginfo_up.x), ftos(gettaginfo_up.y), ftos(gettaginfo_up.z)); if (argc >= 6) { v.y = -v.y; @@@ -839,7 -843,7 +843,7 @@@ } else { - LOG_INFO("bone not found\n"); + LOG_INFO("bone not found"); } delete(tmp_entity); @@@ -848,11 -852,11 +852,11 @@@ } default: - LOG_INFO("Incorrect parameters for ^2gettaginfo^7\n"); + LOG_INFO("Incorrect parameters for ^2gettaginfo^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd gettaginfo model frame index [command one] [command two]\n"); - LOG_INFO("See also: ^2bbox, trace^7\n"); + LOG_INFO("Usage:^3 sv_cmd gettaginfo model frame index [command one] [command two]"); + LOG_INFO("See also: ^2bbox, trace^7"); return; } } @@@ -898,8 -902,8 +902,8 @@@ void GameCommand_animbench(float reques t2 += gettime(GETTIME_HIRES) - t0; n += 1; } - LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f1), " animtime ", ftos(n / t1), "/s\n"); - LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f2), " animtime ", ftos(n / t2), "/s\n"); + LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f1), " animtime ", ftos(n / t1), "/s"); + LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f2), " animtime ", ftos(n / t2), "/s"); delete(tmp_entity); return; @@@ -907,11 -911,11 +911,11 @@@ } default: - LOG_INFO("Incorrect parameters for ^2gettaginfo^7\n"); + LOG_INFO("Incorrect parameters for ^2gettaginfo^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd gettaginfo model frame index [command one] [command two]\n"); - LOG_INFO("See also: ^2bbox, trace^7\n"); + LOG_INFO("Usage:^3 sv_cmd gettaginfo model frame index [command one] [command two]"); + LOG_INFO("See also: ^2bbox, trace^7"); return; } } @@@ -925,18 -929,18 +929,18 @@@ void GameCommand_gotomap(float request { if (argv(1)) { - LOG_INFO(GotoMap(argv(1)), "\n"); + LOG_INFO(GotoMap(argv(1))); return; } } default: - LOG_INFO("Incorrect parameters for ^2gotomap^7\n"); + LOG_INFO("Incorrect parameters for ^2gotomap^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd gotomap map\n"); - LOG_INFO(" Where 'map' is the *.bsp file to change to.\n"); - LOG_INFO("See also: ^2gametype^7\n"); + LOG_INFO("Usage:^3 sv_cmd gotomap map"); + LOG_INFO(" Where 'map' is the *.bsp file to change to."); + LOG_INFO("See also: ^2gametype^7"); return; } } @@@ -963,9 -967,9 +967,9 @@@ void GameCommand_lockteams(float reques default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd lockteams\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2unlockteams^7\n"); + LOG_INFO("Usage:^3 sv_cmd lockteams"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2unlockteams^7"); return; } } @@@ -989,9 -993,9 +993,9 @@@ void GameCommand_make_mapinfo(float req default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd make_mapinfo\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2radarmap^7\n"); + LOG_INFO("Usage:^3 sv_cmd make_mapinfo"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2radarmap^7"); return; } } @@@ -1027,7 -1031,7 +1031,7 @@@ void GameCommand_moveplayer(float reque if (accepted <= 0) { - LOG_INFO("moveplayer: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n")); + LOG_INFO("moveplayer: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".")); continue; } @@@ -1043,7 -1047,7 +1047,7 @@@ } else { - LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") is already spectating.\n"); + LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") is already spectating."); } continue; } @@@ -1063,7 -1067,7 +1067,7 @@@ if (team_id == client.team) // already on the destination team { // keep the forcing undone - LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") is already on the ", Team_ColoredFullName(client.team), (targets ? "^7, skipping to next player.\n" : "^7.\n")); + LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") is already on the ", Team_ColoredFullName(client.team), (targets ? "^7, skipping to next player.\n" : "^7.")); continue; } else if (team_id == 0) // auto team @@@ -1080,60 -1084,54 +1084,60 @@@ // Check to see if the destination team is even available switch (team_id) { - case NUM_TEAM_1: if (c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break; - case NUM_TEAM_2: if (c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break; - case NUM_TEAM_3: if (c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break; - case NUM_TEAM_4: if (c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break; + case NUM_TEAM_1: if (c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist."); return; } break; + case NUM_TEAM_2: if (c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist."); return; } break; + case NUM_TEAM_3: if (c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist."); return; } break; + case NUM_TEAM_4: if (c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist."); return; } break; - default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); + default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist."); return; } // If so, lets continue and finally move the player client.team_forced = 0; - MoveToTeam(client, team_id, 6); - successful = strcat(successful, (successful ? ", " : ""), playername(client, false)); - LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") has been moved to the ", Team_ColoredFullName(team_id), "^7."); + if (MoveToTeam(client, team_id, 6)) + { + successful = strcat(successful, (successful ? ", " : ""), playername(client, false)); - LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") has been moved to the ", Team_ColoredFullName(team_id), "^7.\n"); ++ LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") has been moved to the ", Team_ColoredFullName(team_id), "^7."); + } + else + { + LOG_INFO("Unable to move player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ")"); + } continue; } else { - LOG_INFO("Can't change teams when currently not playing a team game.\n"); + LOG_INFO("Can't change teams when currently not playing a team game."); return; } } else { - LOG_INFO("Can't change teams if the player isn't in the game.\n"); // well technically we could, but should we allow that? :P + LOG_INFO("Can't change teams if the player isn't in the game."); // well technically we could, but should we allow that? :P return; } } } if (successful) bprint("Successfully moved players ", successful, " to destination ", destination, ".\n"); - else LOG_INFO("No players given (", original_targets, ") are able to move.\n"); + else LOG_INFO("No players given (", original_targets, ") are able to move."); return; // still correct parameters so return to avoid usage print } } default: - LOG_INFO("Incorrect parameters for ^2moveplayer^7\n"); + LOG_INFO("Incorrect parameters for ^2moveplayer^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd moveplayer clients destination\n"); - LOG_INFO(" 'clients' is a list (separated by commas) of player entity ID's or nicknames\n"); - LOG_INFO(" 'destination' is what to send the player to, be it team or spectating\n"); - LOG_INFO(" Full list of destinations here: \"spec, spectator, red, blue, yellow, pink, auto.\"\n"); - LOG_INFO("Examples: sv_cmd moveplayer 1,3,5 red 3\n"); - LOG_INFO(" sv_cmd moveplayer 2 spec \n"); - LOG_INFO("See also: ^2allspec, shuffleteams^7\n"); + LOG_INFO("Usage:^3 sv_cmd moveplayer clients destination"); + LOG_INFO(" 'clients' is a list (separated by commas) of player entity ID's or nicknames"); + LOG_INFO(" 'destination' is what to send the player to, be it team or spectating"); + LOG_INFO(" Full list of destinations here: \"spec, spectator, red, blue, yellow, pink, auto.\""); + LOG_INFO("Examples: sv_cmd moveplayer 1,3,5 red 3"); + LOG_INFO(" sv_cmd moveplayer 2 spec "); + LOG_INFO("See also: ^2allspec, shuffleteams^7"); return; } } @@@ -1161,8 -1159,8 +1165,8 @@@ void GameCommand_nospectators(float req default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd nospectators\n"); - LOG_INFO(" No arguments required.\n"); + LOG_INFO("Usage:^3 sv_cmd nospectators"); + LOG_INFO(" No arguments required."); return; } } @@@ -1188,7 -1186,7 +1192,7 @@@ void GameCommand_playerdemo(float reque if (accepted <= 0) { - LOG_INFO("playerdemo: read: ", GetClientErrorString(accepted, argv(2)), ".\n"); + LOG_INFO("playerdemo: read: ", GetClientErrorString(accepted, argv(2)), "."); return; } @@@ -1203,7 -1201,7 +1207,7 @@@ if (accepted <= 0) { - LOG_INFO("playerdemo: write: ", GetClientErrorString(accepted, argv(2)), ".\n"); + LOG_INFO("playerdemo: write: ", GetClientErrorString(accepted, argv(2)), "."); return; } @@@ -1238,11 -1236,11 +1242,11 @@@ } default: - LOG_INFO("Incorrect parameters for ^2playerdemo^7\n"); + LOG_INFO("Incorrect parameters for ^2playerdemo^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd playerdemo command (entitynumber filename | entitynumber botnumber)\n"); - LOG_INFO(" Full list of commands here: \"read, write, auto_read_and_write, auto_read.\"\n"); + LOG_INFO("Usage:^3 sv_cmd playerdemo command (entitynumber filename | entitynumber botnumber)"); + LOG_INFO(" Full list of commands here: \"read, write, auto_read_and_write, auto_read.\""); return; } } @@@ -1255,15 -1253,15 +1259,15 @@@ void GameCommand_printstats(float reque case CMD_REQUEST_COMMAND: { DumpStats(false); - LOG_INFO("stats dumped.\n"); + LOG_INFO("stats dumped."); return; } default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd printstats\n"); - LOG_INFO(" No arguments required.\n"); + LOG_INFO("Usage:^3 sv_cmd printstats"); + LOG_INFO(" No arguments required."); return; } } @@@ -1279,13 -1277,13 +1283,13 @@@ void GameCommand_radarmap(float request } default: - LOG_INFO("Incorrect parameters for ^2radarmap^7\n"); + LOG_INFO("Incorrect parameters for ^2radarmap^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]\n"); - LOG_INFO(" The quality factor Q is roughly proportional to the time taken.\n"); - LOG_INFO(" trace supports no quality factor; its result should look like --block with infinite quality factor.\n"); - LOG_INFO("See also: ^2make_mapinfo^7\n"); + LOG_INFO("Usage:^3 sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]"); + LOG_INFO(" The quality factor Q is roughly proportional to the time taken."); + LOG_INFO(" trace supports no quality factor; its result should look like --block with infinite quality factor."); + LOG_INFO("See also: ^2make_mapinfo^7"); return; } } @@@ -1304,9 -1302,9 +1308,9 @@@ void GameCommand_reducematchtime(float default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd reducematchtime\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2extendmatchtime^7\n"); + LOG_INFO("Usage:^3 sv_cmd reducematchtime"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2extendmatchtime^7"); return; } } @@@ -1328,12 -1326,12 +1332,12 @@@ void GameCommand_setbots(float request } default: - LOG_INFO("Incorrect parameters for ^2setbots^7\n"); + LOG_INFO("Incorrect parameters for ^2setbots^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd setbots botnumber\n"); - LOG_INFO(" Where 'botnumber' is the amount of bots to set bot_number cvar to.\n"); - LOG_INFO("See also: ^2bot_cmd^7\n"); + LOG_INFO("Usage:^3 sv_cmd setbots botnumber"); + LOG_INFO(" Where 'botnumber' is the amount of bots to set bot_number cvar to."); + LOG_INFO("See also: ^2bot_cmd^7"); return; } } @@@ -1347,7 -1345,7 +1351,7 @@@ void GameCommand_shuffleteams(float req { if (!teamplay) { - LOG_INFO("Can't shuffle teams when currently not playing a team game.\n"); + LOG_INFO("Can't shuffle teams when currently not playing a team game."); return; } @@@ -1356,7 -1354,7 +1360,7 @@@ // we could theoretically assign forced players to their teams // and shuffle the rest to fill the empty spots but in practise // either all players or none are gonna have forced teams - LOG_INFO("Can't shuffle teams because at least one player has a forced team.\n"); + LOG_INFO("Can't shuffle teams because at least one player has a forced team."); return; } }); @@@ -1382,9 -1380,9 +1386,9 @@@ default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd shuffleteams\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2moveplayer, allspec^7\n"); + LOG_INFO("Usage:^3 sv_cmd shuffleteams"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2moveplayer, allspec^7"); return; } } @@@ -1409,11 -1407,11 +1413,11 @@@ void GameCommand_stuffto(float request if (accepted > 0) { stuffcmd(client, strcat("\n", argv(next_token), "\n")); - LOG_INFO(strcat("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1), ").\n")); + LOG_INFO("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1), ")."); } else { - LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".\n"); + LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), "."); } return; @@@ -1421,19 -1419,19 +1425,19 @@@ } default: - LOG_INFO("Incorrect parameters for ^2stuffto^7\n"); + LOG_INFO("Incorrect parameters for ^2stuffto^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd stuffto client \"command\"\n"); - LOG_INFO(" 'client' is the entity number or name of the player,\n"); - LOG_INFO(" and 'command' is the command to be sent to that player.\n"); + LOG_INFO("Usage:^3 sv_cmd stuffto client \"command\""); + LOG_INFO(" 'client' is the entity number or name of the player,"); + LOG_INFO(" and 'command' is the command to be sent to that player."); return; } } #else if (request) { - LOG_INFO("stuffto command is not enabled on this server.\n"); + LOG_INFO("stuffto command is not enabled on this server."); return; } #endif @@@ -1454,7 -1452,7 +1458,7 @@@ void GameCommand_trace(float request, f case "debug": { float hitcount = 0; - LOG_INFO("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n"); + LOG_INFO("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky."); float worst_endpos_bug = 0; for ( ; ; ) { @@@ -1501,12 -1499,12 +1505,12 @@@ } } - LOG_INFO("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu\n"); - LOG_INFO("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n"); + LOG_INFO("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu"); + LOG_INFO("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu"); tracebox(p, PL_MIN_CONST + '0.1 0.1 0.1', PL_MAX_CONST - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, NULL); - if (trace_startsolid) LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n"); - else LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n"); + if (trace_startsolid) LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p)); + else LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p)); if (++hitcount >= 10) break; } else @@@ -1527,8 -1525,8 +1531,8 @@@ if (dq > worst_endpos_bug) { worst_endpos_bug = dq; - LOG_INFO("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n"); - LOG_INFO("could go ", ftos(dq), " units further to ", vtos(q), "\n"); + LOG_INFO("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p)); + LOG_INFO("could go ", ftos(dq), " units further to ", vtos(q)); if (++hitcount >= 10) break; } } @@@ -1544,7 -1542,7 +1548,7 @@@ vv = trace_endpos; if (trace_fraction == 1) { - LOG_INFO("not above ground, aborting\n"); + LOG_INFO("not above ground, aborting"); return; } f = 0; @@@ -1553,18 -1551,18 +1557,18 @@@ dv = randomvec(); if (dv.z > 0) dv = -1 * dv; tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e); - if (trace_startsolid) LOG_INFO("bug 1\n"); + if (trace_startsolid) LOG_INFO("bug 1"); if (trace_fraction == 1) { if (dv.z < f) { LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z)); - LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)\n"); + LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)"); f = dv.z; } } } - LOG_INFO("highest possible dist: ", ftos(f), "\n"); + LOG_INFO("highest possible dist: ", ftos(f)); return; } @@@ -1573,8 -1571,8 +1577,8 @@@ if (argc == 4) { e = nextent(NULL); - if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), MOVE_NORMAL)) LOG_INFO("can walk\n"); - else LOG_INFO("cannot walk\n"); + if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), MOVE_NORMAL)) LOG_INFO("can walk"); + else LOG_INFO("cannot walk"); return; } } @@@ -1597,12 -1595,12 +1601,12 @@@ } default: - LOG_INFO("Incorrect parameters for ^2trace^7\n"); + LOG_INFO("Incorrect parameters for ^2trace^7"); case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd trace command (startpos endpos)\n"); - LOG_INFO(" Full list of commands here: \"debug, debug2, walk, showline.\"\n"); - LOG_INFO("See also: ^2bbox, gettaginfo^7\n"); + LOG_INFO("Usage:^3 sv_cmd trace command (startpos endpos)"); + LOG_INFO(" Full list of commands here: \"debug, debug2, walk, showline.\""); + LOG_INFO("See also: ^2bbox, gettaginfo^7"); return; } } @@@ -1629,9 -1627,9 +1633,9 @@@ void GameCommand_unlockteams(float requ default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd unlockteams\n"); - LOG_INFO(" No arguments required.\n"); - LOG_INFO("See also: ^2lockteams^7\n"); + LOG_INFO("Usage:^3 sv_cmd unlockteams"); + LOG_INFO(" No arguments required."); + LOG_INFO("See also: ^2lockteams^7"); return; } } @@@ -1648,17 -1646,17 +1652,17 @@@ void GameCommand_warp(float request, fl if (argc >= 2) { CampaignLevelWarp(stof(argv(1))); - LOG_INFO("Successfully warped to campaign level ", argv(1), ".\n"); + LOG_INFO("Successfully warped to campaign level ", argv(1), "."); } else { CampaignLevelWarp(-1); - LOG_INFO("Successfully warped to next campaign level.\n"); + LOG_INFO("Successfully warped to next campaign level."); } } else { - LOG_INFO("Not in campaign, can't level warp\n"); + LOG_INFO("Not in campaign, can't level warp"); } return; } @@@ -1666,9 -1664,9 +1670,9 @@@ default: case CMD_REQUEST_USAGE: { - LOG_INFO("\nUsage:^3 sv_cmd warp [level]\n"); - LOG_INFO(" 'level' is the level to change campaign mode to.\n"); - LOG_INFO(" if 'level' is not provided it will change to the next level.\n"); + LOG_INFO("Usage:^3 sv_cmd warp [level]"); + LOG_INFO(" 'level' is the level to change campaign mode to."); + LOG_INFO(" if 'level' is not provided it will change to the next level."); return; } } @@@ -1737,7 -1735,7 +1741,7 @@@ SERVER_COMMAND(warp, "Choose different void GameCommand_macro_help() { - FOREACH(SERVER_COMMANDS, true, { LOG_INFOF(" ^2%s^7: %s\n", it.m_name, it.m_description); }); + FOREACH(SERVER_COMMANDS, true, { LOG_INFOF(" ^2%s^7: %s", it.m_name, it.m_description); }); } float GameCommand_macro_command(float argc, string command) @@@ -1784,20 -1782,22 +1788,22 @@@ void GameCommand(string command { if (argc == 1) { - LOG_INFO("\nServer console commands:\n"); + LOG_INFO("Server console commands:"); GameCommand_macro_help(); - LOG_INFO("\nBanning commands:\n"); + LOG_INFO("\nBanning commands:"); BanCommand_macro_help(); - LOG_INFO("\nCommon networked commands:\n"); + LOG_INFO("\nCommon networked commands:"); CommonCommand_macro_help(NULL); - LOG_INFO("\nGeneric commands shared by all programs:\n"); + LOG_INFO("\nGeneric commands shared by all programs:"); GenericCommand_macro_help(); - LOG_INFO("\nUsage:^3 sv_cmd COMMAND...^7, where possible commands are listed above.\n"); - LOG_INFO("For help about a specific command, type sv_cmd help COMMAND\n"); + LOG_INFO( + "\nUsage:^3 sv_cmd COMMAND...^7, where possible commands are listed above.\n" + "For help about a specific command, type sv_cmd help COMMAND" + ); return; } @@@ -1840,5 -1840,5 +1846,5 @@@ } // nothing above caught the command, must be invalid - LOG_INFO(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help.\n"); + LOG_INFO(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help."); } diff --combined qcsrc/server/player.qc index e41bf931b7,44a877791b..dd06152626 --- a/qcsrc/server/player.qc +++ b/qcsrc/server/player.qc @@@ -1,5 -1,6 +1,6 @@@ #include "player.qh" + #include #include "bot/api.qh" #include "cheats.qh" #include "g_damage.qh" @@@ -21,7 -22,7 +22,7 @@@ #include "../common/minigames/sv_minigames.qh" #include "../common/physics/player.qh" - #include "../common/effects/qc/all.qh" + #include "../common/effects/qc/_mod.qh" #include "../common/mutators/mutator/waypoints/waypointsprites.qh" #include "../common/triggers/include.qh" #include "../common/wepent.qh" @@@ -316,9 -317,9 +317,9 @@@ void PlayerDamage(entity this, entity i if(!DEATH_ISSPECIAL(deathtype)) { - damage *= bound(1.0, this.cvar_cl_handicap, 10.0); - if(this != attacker) - damage /= bound(1.0, attacker.cvar_cl_handicap, 10.0); + damage *= bound(1.0, CS(this).cvar_cl_handicap, 10.0); + if(this != attacker && IS_PLAYER(attacker)) + damage /= bound(1.0, CS(attacker).cvar_cl_handicap, 10.0); } if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1) @@@ -471,10 -472,10 +472,10 @@@ if (this != attacker) { float realdmg = damage - excess; if (IS_PLAYER(attacker)) { - PlayerScore_Add(attacker, SP_DMG, realdmg); + GameRules_scoring_add(attacker, DMG, realdmg); } if (IS_PLAYER(this)) { - PlayerScore_Add(this, SP_DMGTAKEN, realdmg); + GameRules_scoring_add(this, DMGTAKEN, realdmg); } } @@@ -667,19 -668,15 +668,19 @@@ } } -void MoveToTeam(entity client, int team_colour, int type) +bool MoveToTeam(entity client, int team_colour, int type) { int lockteams_backup = lockteams; // backup any team lock lockteams = 0; // disable locked teams TeamchangeFrags(client); // move the players frags - SetPlayerColors(client, team_colour - 1); // set the players colour + if (!SetPlayerTeamSimple(client, team_colour)) + { + return false; + } Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0'); // kill the player lockteams = lockteams_backup; // restore the team lock LogTeamchange(client.playerid, client.team, type); + return true; } /** print(), but only print if the server is not local */ @@@ -942,7 -939,7 +943,7 @@@ int Say(entity source, int teamsay, ent } if(flood) - LOG_INFO("NOTE: ", playername(source, true), "^7 is flooding.\n"); + LOG_INFO("NOTE: ", playername(source, true), "^7 is flooding."); // build sourcemsgstr by cutting off a prefix and replacing it by the other one if(privatesay) diff --combined qcsrc/server/scores_rules.qc index 5ee25f5bf3,2b539c9996..d46d95bd1c --- a/qcsrc/server/scores_rules.qc +++ b/qcsrc/server/scores_rules.qc @@@ -1,8 -1,10 +1,11 @@@ #include "scores_rules.qh" + #include + #include #include "client.qh" #include "scores.qh" + #include +#include "teamplay.qh" int ScoreRules_teams; @@@ -56,17 -58,13 +59,13 @@@ void ScoreRules_basics_end( } void ScoreRules_generic() { - if(teamplay) - { + int teams = 0; + if (teamplay) { CheckAllowedTeams(NULL); - int teams = 0; - if(c1 >= 0) teams |= BIT(0); - if(c2 >= 0) teams |= BIT(1); - if(c3 >= 0) teams |= BIT(2); - if(c4 >= 0) teams |= BIT(3); - ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true); + if (c1 >= 0) teams |= BIT(0); + if (c2 >= 0) teams |= BIT(1); + if (c3 >= 0) teams |= BIT(2); + if (c4 >= 0) teams |= BIT(3); } - else - ScoreRules_basics(0, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true); - ScoreRules_basics_end(); + GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {}); } diff --combined qcsrc/server/teamplay.qc index dfa9b89f99,e93a03201a..77c65319d4 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@@ -37,13 -37,6 +37,6 @@@ void default_delayedinit(entity this ScoreRules_generic(); } - void ActivateTeamplay() - { - serverflags |= SERVERFLAG_TEAMPLAY; - teamplay = 1; - cvar_set("teamplay", "2"); // DP needs this for sending proper getstatus replies. - } - void InitGameplayMode() { VoteReset(); @@@ -59,13 -52,11 +52,11 @@@ max_shot_distance = min(230000, vlen(world.maxs - world.mins)); MapInfo_LoadMapSettings(mapname); - serverflags &= ~SERVERFLAG_TEAMPLAY; - teamplay = 0; - cvar_set("teamplay", "0"); // DP needs this for sending proper getstatus replies. + GameRules_teams(false); if (!cvar_value_issafe(world.fog)) { - LOG_INFO("The current map contains a potentially harmful fog setting, ignored\n"); + LOG_INFO("The current map contains a potentially harmful fog setting, ignored"); world.fog = string_null; } if(MapInfo_Map_fog != "") @@@ -169,79 -160,58 +160,79 @@@ void setcolor(entity this, int clr #endif } -void SetPlayerColors(entity pl, float _color) +void SetPlayerColors(entity player, float _color) { - /*string s; - s = ftos(cl); - stuffcmd(pl, strcat("color ", s, " ", s, "\n") ); - pl.team = cl + 1; - //pl.clientcolors = pl.clientcolors - (pl.clientcolors & 15) + cl; - pl.clientcolors = 16*cl + cl;*/ - - float pants, shirt; - pants = _color & 0x0F; - shirt = _color & 0xF0; - - - if(teamplay) { - setcolor(pl, 16*pants + pants); - } else { - setcolor(pl, shirt + pants); + float pants = _color & 0x0F; + float shirt = _color & 0xF0; + if (teamplay) + { + setcolor(player, 16 * pants + pants); + } + else + { + setcolor(player, shirt + pants); } } -void SetPlayerTeam(entity pl, float t, float s, float noprint) +void KillPlayerForTeamChange(entity player) { - float _color; - - if(t == 4) - _color = NUM_TEAM_4 - 1; - else if(t == 3) - _color = NUM_TEAM_3 - 1; - else if(t == 2) - _color = NUM_TEAM_2 - 1; - else - _color = NUM_TEAM_1 - 1; - - SetPlayerColors(pl,_color); - - if(t != s) { - LogTeamchange(pl.playerid, pl.team, 3); // log manual team join + if (IS_DEAD(player)) + { + return; + } + if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true) + { + return; + } + Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, player.origin, + '0 0 0'); +} - if(!noprint) - bprint(playername(pl, false), "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n"); +bool SetPlayerTeamSimple(entity player, int team_num) +{ + if (player.team == team_num) + { + // This is important when players join the game and one of their color + // matches the team color while other doesn't. For example [BOT]Lion. + SetPlayerColors(player, team_num - 1); + return true; } + if (MUTATOR_CALLHOOK(Player_ChangeTeam, player, Team_TeamToNumber( + player.team), Team_TeamToNumber(team_num)) == true) + { + // Mutator has blocked team change. + return false; + } + int old_team = player.team; + SetPlayerColors(player, team_num - 1); + MUTATOR_CALLHOOK(Player_ChangedTeam, player, old_team, player.team); + return true; +} +bool SetPlayerTeam(entity player, int destination_team, int source_team, + bool no_print) +{ + int team_num = Team_NumberToTeam(destination_team); + if (!SetPlayerTeamSimple(player, team_num)) + { + return false; + } + LogTeamchange(player.playerid, player.team, 3); // log manual team join + if (no_print) + { + return true; + } + bprint(playername(player, false), "^7 has changed from ", Team_NumberToColoredFullName(source_team), "^7 to ", Team_NumberToColoredFullName(destination_team), "\n"); + return true; } // set c1...c4 to show what teams are allowed -void CheckAllowedTeams (entity for_whom) +void CheckAllowedTeams(entity for_whom) { int teams_mask = 0; c1 = c2 = c3 = c4 = -1; - cb1 = cb2 = cb3 = cb4 = 0; + num_bots_team1 = num_bots_team2 = num_bots_team3 = num_bots_team4 = 0; string teament_name = string_null; @@@ -343,570 -313,284 +334,570 @@@ float PlayerValue(entity p // teams that are allowed will now have their player counts stored in c1...c4 void GetTeamCounts(entity ignore) { - float value, bvalue; - // now count how many players are on each team already - - // FIXME: also find and memorize the lowest-scoring bot on each team (in case players must be shuffled around) - // also remember the lowest-scoring player - - FOREACH_CLIENT(true, { - float t; - if(IS_PLAYER(it) || it.caplayer) - t = it.team; - else if(it.team_forced > 0) - t = it.team_forced; // reserve the spot - else - continue; - if(it != ignore)// && it.netname != "") + if (MUTATOR_CALLHOOK(GetTeamCounts) == true) + { + if (c1 >= 0) + { + MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_1, ignore, c1, + num_bots_team1, lowest_human_team1, lowest_bot_team1); + c1 = M_ARGV(2, float); + num_bots_team1 = M_ARGV(3, float); + lowest_human_team1 = M_ARGV(4, entity); + lowest_bot_team1 = M_ARGV(5, entity); + } + if (c2 >= 0) + { + MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_2, ignore, c2, + num_bots_team2, lowest_human_team2, lowest_bot_team2); + c2 = M_ARGV(2, float); + num_bots_team2 = M_ARGV(3, float); + lowest_human_team2 = M_ARGV(4, entity); + lowest_bot_team2 = M_ARGV(5, entity); + } + if (c3 >= 0) + { + MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_3, ignore, c3, + num_bots_team3, lowest_human_team3, lowest_bot_team3); + c3 = M_ARGV(2, float); + num_bots_team3 = M_ARGV(3, float); + lowest_human_team3 = M_ARGV(4, entity); + lowest_bot_team3 = M_ARGV(5, entity); + } + if (c4 >= 0) + { + MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_4, ignore, + c4, num_bots_team4, lowest_human_team4, lowest_bot_team4); + c4 = M_ARGV(2, float); + num_bots_team4 = M_ARGV(3, float); + lowest_human_team4 = M_ARGV(4, entity); + lowest_bot_team4 = M_ARGV(5, entity); + } + } + else + { + float value, bvalue; + // now count how many players are on each team already + float lowest_human_score1 = FLOAT_MAX; + float lowest_bot_score1 = FLOAT_MAX; + float lowest_human_score2 = FLOAT_MAX; + float lowest_bot_score2 = FLOAT_MAX; + float lowest_human_score3 = FLOAT_MAX; + float lowest_bot_score3 = FLOAT_MAX; + float lowest_human_score4 = FLOAT_MAX; + float lowest_bot_score4 = FLOAT_MAX; + FOREACH_CLIENT(true, { + float t; + if (IS_PLAYER(it) || it.caplayer) + { + t = it.team; + } + else if (it.team_forced > 0) + { + t = it.team_forced; // reserve the spot + } + else + { + continue; + } + if (it == ignore) + { + continue; + } value = PlayerValue(it); - if(IS_BOT_CLIENT(it)) + if (IS_BOT_CLIENT(it)) + { bvalue = value; + } else + { bvalue = 0; - if(t == NUM_TEAM_1) + } + if (value == 0) { - if(c1 >= 0) - { - c1 = c1 + value; - cb1 = cb1 + bvalue; - } + continue; } - else if(t == NUM_TEAM_2) + switch (t) { - if(c2 >= 0) + case NUM_TEAM_1: { - c2 = c2 + value; - cb2 = cb2 + bvalue; + if (c1 < 0) + { + break; + } + c1 += value; + num_bots_team1 += bvalue; + float temp_score = PlayerScore_Get(it, SP_SCORE); + if (!bvalue) + { + if (temp_score < lowest_human_score1) + { + lowest_human_team1 = it; + lowest_human_score1 = temp_score; + } + break; + } + if (temp_score < lowest_bot_score1) + { + lowest_bot_team1 = it; + lowest_bot_score1 = temp_score; + } + break; } - } - else if(t == NUM_TEAM_3) - { - if(c3 >= 0) + case NUM_TEAM_2: { - c3 = c3 + value; - cb3 = cb3 + bvalue; + if (c2 < 0) + { + break; + } + c2 += value; + num_bots_team2 += bvalue; + float temp_score = PlayerScore_Get(it, SP_SCORE); + if (!bvalue) + { + if (temp_score < lowest_human_score2) + { + lowest_human_team2 = it; + lowest_human_score2 = temp_score; + } + break; + } + if (temp_score < lowest_bot_score2) + { + lowest_bot_team2 = it; + lowest_bot_score2 = temp_score; + } + break; } - } - else if(t == NUM_TEAM_4) - { - if(c4 >= 0) + case NUM_TEAM_3: + { + if (c3 < 0) + { + break; + } + c3 += value; + num_bots_team3 += bvalue; + float temp_score = PlayerScore_Get(it, SP_SCORE); + if (!bvalue) + { + if (temp_score < lowest_human_score3) + { + lowest_human_team3 = it; + lowest_human_score3 = temp_score; + } + break; + } + if (temp_score < lowest_bot_score3) + { + lowest_bot_team3 = it; + lowest_bot_score3 = temp_score; + } + break; + } + case NUM_TEAM_4: { - c4 = c4 + value; - cb4 = cb4 + bvalue; + if (c4 < 0) + { + break; + } + c4 += value; + num_bots_team4 += bvalue; + float temp_score = PlayerScore_Get(it, SP_SCORE); + if (!bvalue) + { + if (temp_score < lowest_human_score4) + { + lowest_human_team4 = it; + lowest_human_score4 = temp_score; + } + break; + } + if (temp_score < lowest_bot_score4) + { + lowest_bot_team4 = it; + lowest_bot_score4 = temp_score; + } + break; } } - } - }); + }); + } // if the player who has a forced team has not joined yet, reserve the spot if(autocvar_g_campaign) { switch(autocvar_g_campaign_forceteam) { - case 1: if(c1 == cb1) ++c1; break; - case 2: if(c2 == cb2) ++c2; break; - case 3: if(c3 == cb3) ++c3; break; - case 4: if(c4 == cb4) ++c4; break; + case 1: if(c1 == num_bots_team1) ++c1; break; + case 2: if(c2 == num_bots_team2) ++c2; break; + case 3: if(c3 == num_bots_team3) ++c3; break; + case 4: if(c4 == num_bots_team4) ++c4; break; } } } -float TeamSmallerEqThanTeam(float ta, float tb, entity e) +bool IsTeamSmallerThanTeam(int team_a, int team_b, entity player, + bool use_score) { + if (team_a == team_b) + { + return false; + } // we assume that CheckAllowedTeams and GetTeamCounts have already been called - float f; - float ca = -1, cb = -1, cba = 0, cbb = 0, sa = 0, sb = 0; - - switch(ta) + int num_players_team_a = -1, num_players_team_b = -1; + int num_bots_team_a = 0, num_bots_team_b = 0; + float score_team_a = 0, score_team_b = 0; + switch (team_a) { - case 1: ca = c1; cba = cb1; sa = team1_score; break; - case 2: ca = c2; cba = cb2; sa = team2_score; break; - case 3: ca = c3; cba = cb3; sa = team3_score; break; - case 4: ca = c4; cba = cb4; sa = team4_score; break; + case 1: + { + num_players_team_a = c1; + num_bots_team_a = num_bots_team1; + score_team_a = team1_score; + break; + } + case 2: + { + num_players_team_a = c2; + num_bots_team_a = num_bots_team2; + score_team_a = team2_score; + break; + } + case 3: + { + num_players_team_a = c3; + num_bots_team_a = num_bots_team3; + score_team_a = team3_score; + break; + } + case 4: + { + num_players_team_a = c4; + num_bots_team_a = num_bots_team4; + score_team_a = team4_score; + break; + } } - switch(tb) + switch (team_b) { - case 1: cb = c1; cbb = cb1; sb = team1_score; break; - case 2: cb = c2; cbb = cb2; sb = team2_score; break; - case 3: cb = c3; cbb = cb3; sb = team3_score; break; - case 4: cb = c4; cbb = cb4; sb = team4_score; break; + case 1: + { + num_players_team_b = c1; + num_bots_team_b = num_bots_team1; + score_team_b = team1_score; + break; + } + case 2: + { + num_players_team_b = c2; + num_bots_team_b = num_bots_team2; + score_team_b = team2_score; + break; + } + case 3: + { + num_players_team_b = c3; + num_bots_team_b = num_bots_team3; + score_team_b = team3_score; + break; + } + case 4: + { + num_players_team_b = c4; + num_bots_team_b = num_bots_team4; + score_team_b = team4_score; + break; + } } - // invalid - if(ca < 0 || cb < 0) + if (num_players_team_a < 0 || num_players_team_b < 0) + { return false; - - // equal - if(ta == tb) + } + if (IS_REAL_CLIENT(player) && bots_would_leave) + { + num_players_team_a -= num_bots_team_a; + num_players_team_b -= num_bots_team_b; + } + if (!use_score) + { + return num_players_team_a < num_players_team_b; + } + if (num_players_team_a < num_players_team_b) + { return true; + } + if (num_players_team_a > num_players_team_b) + { + return false; + } + return score_team_a < score_team_b; +} - if(IS_REAL_CLIENT(e)) +bool IsTeamEqualToTeam(int team_a, int team_b, entity player, bool use_score) +{ + if (team_a == team_b) { - if(bots_would_leave) + return true; + } + // we assume that CheckAllowedTeams and GetTeamCounts have already been called + int num_players_team_a = -1, num_players_team_b = -1; + int num_bots_team_a = 0, num_bots_team_b = 0; + float score_team_a = 0, score_team_b = 0; + switch (team_a) + { + case 1: { - ca -= cba * 0.999; - cb -= cbb * 0.999; + num_players_team_a = c1; + num_bots_team_a = num_bots_team1; + score_team_a = team1_score; + break; + } + case 2: + { + num_players_team_a = c2; + num_bots_team_a = num_bots_team2; + score_team_a = team2_score; + break; + } + case 3: + { + num_players_team_a = c3; + num_bots_team_a = num_bots_team3; + score_team_a = team3_score; + break; + } + case 4: + { + num_players_team_a = c4; + num_bots_team_a = num_bots_team4; + score_team_a = team4_score; + break; } } + switch (team_b) + { + case 1: + { + num_players_team_b = c1; + num_bots_team_b = num_bots_team1; + score_team_b = team1_score; + break; + } + case 2: + { + num_players_team_b = c2; + num_bots_team_b = num_bots_team2; + score_team_b = team2_score; + break; + } + case 3: + { + num_players_team_b = c3; + num_bots_team_b = num_bots_team3; + score_team_b = team3_score; + break; + } + case 4: + { + num_players_team_b = c4; + num_bots_team_b = num_bots_team4; + score_team_b = team4_score; + break; + } + } + // invalid + if (num_players_team_a < 0 || num_players_team_b < 0) + return false; - // keep teams alive (teams of size 0 always count as smaller, ignoring score) - if(ca < 1) - if(cb >= 1) - return true; - if(ca >= 1) - if(cb < 1) - return false; - - // first, normalize - f = max(ca, cb, 1); - ca /= f; - cb /= f; - f = max(sa, sb, 1); - sa /= f; - sb /= f; - - // the more we're at the end of the match, the more take scores into account - f = bound(0, game_completion_ratio * autocvar_g_balance_teams_scorefactor, 1); - ca += (sa - ca) * f; - cb += (sb - cb) * f; + if (IS_REAL_CLIENT(player) && bots_would_leave) + { + num_players_team_a -= num_bots_team_a; + num_players_team_b -= num_bots_team_b; + } + if (!use_score) + { + return num_players_team_a == num_players_team_b; + } + if (num_players_team_a != num_players_team_b) + { + return false; + } + return score_team_a == score_team_b; +} - return ca <= cb; +int FindBestTeams(entity player, bool use_score) +{ + if (MUTATOR_CALLHOOK(FindBestTeams, player) == true) + { + return M_ARGV(1, float); + } + int team_bits = 0; + int previous_team = 0; + if (c1 >= 0) + { + team_bits = BIT(0); + previous_team = 1; + } + if (c2 >= 0) + { + if (previous_team == 0) + { + team_bits = BIT(1); + previous_team = 2; + } + else if (IsTeamSmallerThanTeam(2, previous_team, player, use_score)) + { + team_bits = BIT(1); + previous_team = 2; + } + else if (IsTeamEqualToTeam(2, previous_team, player, use_score)) + { + team_bits |= BIT(1); + previous_team = 2; + } + } + if (c3 >= 0) + { + if (previous_team == 0) + { + team_bits = BIT(2); + previous_team = 3; + } + else if (IsTeamSmallerThanTeam(3, previous_team, player, use_score)) + { + team_bits = BIT(2); + previous_team = 3; + } + else if (IsTeamEqualToTeam(3, previous_team, player, use_score)) + { + team_bits |= BIT(2); + previous_team = 3; + } + } + if (c4 >= 0) + { + if (previous_team == 0) + { + team_bits = BIT(3); + } + else if (IsTeamSmallerThanTeam(4, previous_team, player, use_score)) + { + team_bits = BIT(3); + } + else if (IsTeamEqualToTeam(4, previous_team, player, use_score)) + { + team_bits |= BIT(3); + } + } + return team_bits; } // returns # of smallest team (1, 2, 3, 4) // NOTE: Assumes CheckAllowedTeams has already been called! -float FindSmallestTeam(entity pl, float ignore_pl) +int FindSmallestTeam(entity player, float ignore_player) { - int totalteams = 0; - int t = 1; // initialize with a random team? - if(c4 >= 0) t = 4; - if(c3 >= 0) t = 3; - if(c2 >= 0) t = 2; - if(c1 >= 0) t = 1; - - // find out what teams are available - //CheckAllowedTeams(); - - // make sure there are at least 2 teams to join - if(c1 >= 0) - totalteams = totalteams + 1; - if(c2 >= 0) - totalteams = totalteams + 1; - if(c3 >= 0) - totalteams = totalteams + 1; - if(c4 >= 0) - totalteams = totalteams + 1; - - if((autocvar_bot_vs_human || pl.team_forced > 0) && totalteams == 1) - totalteams += 1; - - if(totalteams <= 1) + // count how many players are in each team + if (ignore_player) { - if(autocvar_g_campaign && pl && IS_REAL_CLIENT(pl)) - return 1; // special case for campaign and player joining - else if(totalteams == 1) // single team - LOG_TRACEF("Only 1 team available for %s, you may need to fix your map", MapInfo_Type_ToString(MapInfo_CurrentGametype())); - else // no teams, major no no - error(sprintf("No teams available for %s\n", MapInfo_Type_ToString(MapInfo_CurrentGametype()))); + GetTeamCounts(player); } - - // count how many players are in each team - if(ignore_pl) - GetTeamCounts(pl); else + { GetTeamCounts(NULL); - + } + int team_bits = FindBestTeams(player, true); + if (team_bits == 0) + { + error(sprintf("No teams available for %s\n", MapInfo_Type_ToString(MapInfo_CurrentGametype()))); + } RandomSelection_Init(); - - if(TeamSmallerEqThanTeam(1, t, pl)) - t = 1; - if(TeamSmallerEqThanTeam(2, t, pl)) - t = 2; - if(TeamSmallerEqThanTeam(3, t, pl)) - t = 3; - if(TeamSmallerEqThanTeam(4, t, pl)) - t = 4; - - // now t is the minimum, or A minimum! - if(t == 1 || TeamSmallerEqThanTeam(1, t, pl)) + if ((team_bits & BIT(0)) != 0) + { RandomSelection_AddFloat(1, 1, 1); - if(t == 2 || TeamSmallerEqThanTeam(2, t, pl)) + } + if ((team_bits & BIT(1)) != 0) + { RandomSelection_AddFloat(2, 1, 1); - if(t == 3 || TeamSmallerEqThanTeam(3, t, pl)) + } + if ((team_bits & BIT(2)) != 0) + { RandomSelection_AddFloat(3, 1, 1); - if(t == 4 || TeamSmallerEqThanTeam(4, t, pl)) + } + if ((team_bits & BIT(3)) != 0) + { RandomSelection_AddFloat(4, 1, 1); - + } return RandomSelection_chosen_float; } -int JoinBestTeam(entity this, bool only_return_best, bool forcebestteam) +int JoinBestTeam(entity this, bool only_return_best, bool force_best_team) { - float smallest, selectedteam; - // don't join a team if we're not playing a team game - if(!teamplay) + if (!teamplay) + { return 0; + } // find out what teams are available CheckAllowedTeams(this); // if we don't care what team he ends up on, put him on whatever team he entered as. // if he's not on a valid team, then let other code put him on the smallest team - if(!forcebestteam) + if (!force_best_team) { + int selected_team; if( c1 >= 0 && this.team == NUM_TEAM_1) - selectedteam = this.team; + selected_team = this.team; else if(c2 >= 0 && this.team == NUM_TEAM_2) - selectedteam = this.team; + selected_team = this.team; else if(c3 >= 0 && this.team == NUM_TEAM_3) - selectedteam = this.team; + selected_team = this.team; else if(c4 >= 0 && this.team == NUM_TEAM_4) - selectedteam = this.team; + selected_team = this.team; else - selectedteam = -1; + selected_team = -1; - if(selectedteam > 0) + if (selected_team > 0) { - if(!only_return_best) + if (!only_return_best) { - SetPlayerColors(this, selectedteam - 1); + SetPlayerTeamSimple(this, selected_team); // when JoinBestTeam is called by client.qc/ClientKill_Now_TeamChange the players team is -1 and thus skipped // when JoinBestTeam is called by client.qc/ClientConnect the player_id is 0 the log attempt is rejected LogTeamchange(this.playerid, this.team, 99); } - return selectedteam; + return selected_team; } // otherwise end up on the smallest team (handled below) } - smallest = FindSmallestTeam(this, true); - - if(!only_return_best && !this.bot_forced_team) + int best_team = FindSmallestTeam(this, true); + if (only_return_best || this.bot_forced_team) { - TeamchangeFrags(this); - if(smallest == 1) - { - SetPlayerColors(this, NUM_TEAM_1 - 1); - } - else if(smallest == 2) - { - SetPlayerColors(this, NUM_TEAM_2 - 1); - } - else if(smallest == 3) - { - SetPlayerColors(this, NUM_TEAM_3 - 1); - } - else if(smallest == 4) - { - SetPlayerColors(this, NUM_TEAM_4 - 1); - } - else - { - error("smallest team: invalid team\n"); - } - - LogTeamchange(this.playerid, this.team, 2); // log auto join - - if(!IS_DEAD(this)) - Damage(this, this, this, 100000, DEATH_TEAMCHANGE.m_id, this.origin, '0 0 0'); + return best_team; } - - return smallest; + best_team = Team_NumberToTeam(best_team); + if (best_team == -1) + { + error("JoinBestTeam: invalid team\n"); + } + int old_team = Team_TeamToNumber(this.team); + TeamchangeFrags(this); + SetPlayerTeamSimple(this, best_team); + LogTeamchange(this.playerid, this.team, 2); // log auto join + if (!IS_BOT_CLIENT(this)) + { + AutoBalanceBots(old_team, Team_TeamToNumber(best_team)); + } + KillPlayerForTeamChange(this); + return best_team; } -//void() ctf_playerchanged; void SV_ChangeTeam(entity this, float _color) { - float scolor, dcolor, steam, dteam; //, dbotcount, scount, dcount; + float source_color, destination_color, source_team, destination_team; // in normal deathmatch we can just apply the color and we're done if(!teamplay) @@@ -922,23 -606,38 +913,23 @@@ if(!teamplay) return; - scolor = this.clientcolors & 0x0F; - dcolor = _color & 0x0F; - - if(scolor == NUM_TEAM_1 - 1) - steam = 1; - else if(scolor == NUM_TEAM_2 - 1) - steam = 2; - else if(scolor == NUM_TEAM_3 - 1) - steam = 3; - else // if(scolor == NUM_TEAM_4 - 1) - steam = 4; - if(dcolor == NUM_TEAM_1 - 1) - dteam = 1; - else if(dcolor == NUM_TEAM_2 - 1) - dteam = 2; - else if(dcolor == NUM_TEAM_3 - 1) - dteam = 3; - else // if(dcolor == NUM_TEAM_4 - 1) - dteam = 4; + source_color = this.clientcolors & 0x0F; + destination_color = _color & 0x0F; + + source_team = Team_TeamToNumber(source_color + 1); + destination_team = Team_TeamToNumber(destination_color + 1); CheckAllowedTeams(this); - if(dteam == 1 && c1 < 0) dteam = 4; - if(dteam == 4 && c4 < 0) dteam = 3; - if(dteam == 3 && c3 < 0) dteam = 2; - if(dteam == 2 && c2 < 0) dteam = 1; + if (destination_team == 1 && c1 < 0) destination_team = 4; + if (destination_team == 4 && c4 < 0) destination_team = 3; + if (destination_team == 3 && c3 < 0) destination_team = 2; + if (destination_team == 2 && c2 < 0) destination_team = 1; // not changing teams - if(scolor == dcolor) + if (source_color == destination_color) { - //bprint("same team change\n"); - SetPlayerTeam(this, dteam, steam, true); + SetPlayerTeam(this, destination_team, source_team, true); return; } @@@ -948,102 -647,169 +939,102 @@@ } // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless - if(autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance) + if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance) { GetTeamCounts(this); - if(!TeamSmallerEqThanTeam(dteam, steam, this)) + if ((BIT(destination_team - 1) & FindBestTeams(this, false)) == 0) { Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM); return; } } - -// bprint("allow change teams from ", ftos(steam), " to ", ftos(dteam), "\n"); - - if(IS_PLAYER(this) && steam != dteam) + if(IS_PLAYER(this) && source_team != destination_team) { // reduce frags during a team change TeamchangeFrags(this); } - - MUTATOR_CALLHOOK(Player_ChangeTeam, this, steam, dteam); - - SetPlayerTeam(this, dteam, steam, !IS_CLIENT(this)); - - if(IS_PLAYER(this) && steam != dteam) + if (!SetPlayerTeam(this, destination_team, source_team, !IS_CLIENT(this))) + { + return; + } + AutoBalanceBots(source_team, destination_team); + if (!IS_PLAYER(this) || (source_team == destination_team)) { - // kill player when changing teams - if(!IS_DEAD(this)) - Damage(this, this, this, 100000, DEATH_TEAMCHANGE.m_id, this.origin, '0 0 0'); + return; } + KillPlayerForTeamChange(this); } -void ShufflePlayerOutOfTeam (float source_team) +void AutoBalanceBots(int source_team, int destination_team) { - float smallestteam, smallestteam_count, steam; - float lowest_bot_score, lowest_player_score; - entity lowest_bot, lowest_player, selected; - - smallestteam = 0; - smallestteam_count = 999999999; - - if(c1 >= 0 && c1 < smallestteam_count) - { - smallestteam = 1; - smallestteam_count = c1; - } - if(c2 >= 0 && c2 < smallestteam_count) - { - smallestteam = 2; - smallestteam_count = c2; - } - if(c3 >= 0 && c3 < smallestteam_count) + if ((source_team == -1) || (destination_team == -1)) { - smallestteam = 3; - smallestteam_count = c3; + return; } - if(c4 >= 0 && c4 < smallestteam_count) + if (!autocvar_g_balance_teams || + !autocvar_g_balance_teams_prevent_imbalance) { - smallestteam = 4; - smallestteam_count = c4; - } - - if(!smallestteam) - { - bprint("warning: no smallest team\n"); return; } - - if(source_team == 1) - steam = NUM_TEAM_1; - else if(source_team == 2) - steam = NUM_TEAM_2; - else if(source_team == 3) - steam = NUM_TEAM_3; - else // if(source_team == 4) - steam = NUM_TEAM_4; - - lowest_bot = NULL; - lowest_bot_score = 999999999; - lowest_player = NULL; - lowest_player_score = 999999999; - - // find the lowest-scoring player & bot of that team - FOREACH_CLIENT(IS_PLAYER(it) && it.team == steam, { - if(it.isbot) + int num_players_source_team = 0; + int num_players_destination_team = 0; + entity lowest_bot_destination_team = NULL; + switch (source_team) + { + case 1: { - if(it.totalfrags < lowest_bot_score) - { - lowest_bot = it; - lowest_bot_score = it.totalfrags; - } + num_players_source_team = c1; + break; } - else + case 2: { - if(it.totalfrags < lowest_player_score) - { - lowest_player = it; - lowest_player_score = it.totalfrags; - } + num_players_source_team = c2; + break; + } + case 3: + { + num_players_source_team = c3; + break; + } + case 4: + { + num_players_source_team = c4; + break; } - }); - - // prefers to move a bot... - if(lowest_bot != NULL) - selected = lowest_bot; - // but it will move a player if it has to - else - selected = lowest_player; - // don't do anything if it couldn't find anyone - if(!selected) - { - bprint("warning: couldn't find a player to move from team\n"); - return; - } - - // smallest team gains a member - if(smallestteam == 1) - { - c1 = c1 + 1; - } - else if(smallestteam == 2) - { - c2 = c2 + 1; - } - else if(smallestteam == 3) - { - c3 = c3 + 1; - } - else if(smallestteam == 4) - { - c4 = c4 + 1; - } - else - { - bprint("warning: destination team invalid\n"); - return; - } - // source team loses a member - if(source_team == 1) - { - c1 = c1 + 1; - } - else if(source_team == 2) - { - c2 = c2 + 2; - } - else if(source_team == 3) - { - c3 = c3 + 3; } - else if(source_team == 4) + switch (destination_team) { - c4 = c4 + 4; + case 1: + { + num_players_destination_team = c1; + lowest_bot_destination_team = lowest_bot_team1; + break; + } + case 2: + { + num_players_destination_team = c2; + lowest_bot_destination_team = lowest_bot_team2; + break; + } + case 3: + { + num_players_destination_team = c3; + lowest_bot_destination_team = lowest_bot_team3; + break; + } + case 4: + { + num_players_destination_team = c4; + lowest_bot_destination_team = lowest_bot_team4; + break; + } } - else + if ((num_players_destination_team <= num_players_source_team) || + (lowest_bot_destination_team == NULL)) { - bprint("warning: source team invalid\n"); return; } - - // move the player to the new team - TeamchangeFrags(selected); - SetPlayerTeam(selected, smallestteam, source_team, false); - - if(!IS_DEAD(selected)) - Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE.m_id, selected.origin, '0 0 0'); - Send_Notification(NOTIF_ONE, selected, MSG_CENTER, CENTER_DEATH_SELF_AUTOTEAMCHANGE, selected.team); + SetPlayerTeamSimple(lowest_bot_destination_team, + Team_NumberToTeam(source_team)); + KillPlayerForTeamChange(lowest_bot_destination_team); } diff --combined qcsrc/server/teamplay.qh index 5311d4cb01,8d0ea9cb8a..1813db04d8 --- a/qcsrc/server/teamplay.qh +++ b/qcsrc/server/teamplay.qh @@@ -3,29 -3,10 +3,29 @@@ string cache_mutatormsg; string cache_lastmutatormsg; -// client counts for each team -//float c1, c2, c3, c4; -// # of bots on those teams -float cb1, cb2, cb3, cb4; +// The following variables are used for balancing. They are not updated +// automatically. You need to call CheckAllowedTeams and GetTeamCounts to get +// proper values. + +// These four have 2 different states. If they are equal to -1, it means that +// the player can't join the team. Zero or positive value means that player can +// join the team and means the number of players on that team. +float c1; +float c2; +float c3; +float c4; +float num_bots_team1; ///< Number of bots in the first team. +float num_bots_team2; ///< Number of bots in the second team. +float num_bots_team3; ///< Number of bots in the third team. +float num_bots_team4; ///< Number of bots in the fourth team. +entity lowest_human_team1; ///< Human with the lowest score in the first team. +entity lowest_human_team2; ///< Human with the lowest score in the second team. +entity lowest_human_team3; ///< Human with the lowest score in the third team. +entity lowest_human_team4; ///< Human with the lowest score in the fourth team. +entity lowest_bot_team1; ///< Bot with the lowest score in the first team. +entity lowest_bot_team2; ///< Bot with the lowest score in the second team. +entity lowest_bot_team3; ///< Bot with the lowest score in the third team. +entity lowest_bot_team4; ///< Bot with the lowest score in the fourth team. int redowned, blueowned, yellowowned, pinkowned; @@@ -37,38 -18,18 +37,36 @@@ void LogTeamchange(float player_id, flo void default_delayedinit(entity this); - void ActivateTeamplay(); - void InitGameplayMode(); string GetClientVersionMessage(entity this); string getwelcomemessage(entity this); -void SetPlayerColors(entity pl, float _color); +void SetPlayerColors(entity player, float _color); -void SetPlayerTeam(entity pl, float t, float s, float noprint); +/// \brief Kills player as a result of team change. +/// \param[in,out] player Player to kill. +/// \return No return. +void KillPlayerForTeamChange(entity player); + +/// \brief Sets the team of the player. +/// \param[in,out] player Player to adjust. +/// \param[in] team_num Team number to set. See TEAM_NUM constants. +/// \return True if team switch was successful, false otherwise. +bool SetPlayerTeamSimple(entity player, int team_num); + +/// \brief Sets the team of the player. +/// \param[in,out] player Player to adjust. +/// \param[in] destination_team Team to set. +/// \param[in] source_team Previous team of the player. +/// \param[in] no_print Whether to print this event to players' console. +/// \return True if team switch was successful, false otherwise. +bool SetPlayerTeam(entity player, int destination_team, int source_team, + bool no_print); // set c1...c4 to show what teams are allowed -void CheckAllowedTeams (entity for_whom); +void CheckAllowedTeams(entity for_whom); float PlayerValue(entity p); @@@ -76,47 -37,16 +74,47 @@@ // teams that are allowed will now have their player counts stored in c1...c4 void GetTeamCounts(entity ignore); -float TeamSmallerEqThanTeam(float ta, float tb, entity e); +/// \brief Returns whether one team is smaller than the other. +/// \param[in] team_a First team. +/// \param[in] team_b Second team. +/// \param[in] player Player to check. +/// \param[in] use_score Whether to take into account team scores. +/// \return True if first team is smaller than the second one, false otherwise. +/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have +/// been called. +bool IsTeamSmallerThanTeam(int team_a, int team_b, entity player, + bool use_score); + +/// \brief Returns whether one team is equal to the other. +/// \param[in] team_a First team. +/// \param[in] team_b Second team. +/// \param[in] player Player to check. +/// \param[in] use_score Whether to take into account team scores. +/// \return True if first team is equal to the second one, false otherwise. +/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have +/// been called. +bool IsTeamEqualToTeam(int team_a, int team_b, entity player, bool use_score); + +/// \brief Returns the bitmask of the best teams for the player to join. +/// \param[in] player Player to check. +/// \param[in] use_score Whether to take into account team scores. +/// \return Bitmask of the best teams for the player to join. +/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have +/// been called. +int FindBestTeams(entity player, bool use_score); // returns # of smallest team (1, 2, 3, 4) // NOTE: Assumes CheckAllowedTeams has already been called! -float FindSmallestTeam(entity pl, float ignore_pl); - -int JoinBestTeam(entity this, bool only_return_best, bool forcebestteam); +int FindSmallestTeam(entity player, float ignore_player); -//void() ctf_playerchanged; +int JoinBestTeam(entity this, bool only_return_best, bool force_best_team); -void ShufflePlayerOutOfTeam (float source_team); +/// \brief Auto balances bots in teams after the player has changed team. +/// \param[in] source_team Previous team of the player (1, 2, 3, 4). +/// \param[in] destination_team Current team of the player (1, 2, 3, 4). +/// \return No return. +/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have +/// been called. +void AutoBalanceBots(int source_team, int destination_team); void setcolor(entity this, int clr);