seta notification_INFO_QUIT_DISCONNECT "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_QUIT_KICK_IDLING "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_QUIT_KICK_SPECTATING "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-seta notification_INFO_QUIT_SPECTATE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_QUIT_SPECTATE "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_RACE_ABANDONED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_RACE_FAIL_RANKED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_RACE_FAIL_UNRANKED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_SUPERWEAPON_PICKUP "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_TEAMCHANGE_LARGERTEAM "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_TEAMCHANGE_NOTALLOWED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-seta notification_INFO_VERSION_BETA "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_VERSION_BETA "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_VERSION_OLD "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_VERSION_OUTDATED "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WATERMARK "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
this.m_model = MDL_Bullets_ITEM;
#endif
this.netname = "bullets";
- this.m_name = "bullets";
+ this.m_name = _("bullets");
this.m_icon = "ammo_bullets";
#ifdef SVQC
this.m_botvalue = 1500;
this.m_model = MDL_Cells_ITEM;
#endif
this.netname = "cells";
- this.m_name = "cells";
+ this.m_name = _("cells");
this.m_icon = "ammo_cells";
#ifdef SVQC
this.m_botvalue = 1500;
this.m_model = MDL_Plasma_ITEM;
#endif
this.netname = "plasma";
- this.m_name = "plasma";
+ this.m_name = _("plasma");
this.m_icon = "ammo_plasma";
#ifdef SVQC
this.m_botvalue = 1500;
this.m_model = MDL_Rockets_ITEM;
#endif
this.netname = "rockets";
- this.m_name = "rockets";
+ this.m_name = _("rockets");
this.m_icon = "ammo_rockets";
#ifdef SVQC
this.m_botvalue = 1500;
this.m_model = MDL_Shells_ITEM;
#endif
this.netname = "shells";
- this.m_name = "shells";
+ this.m_name = _("shells");
this.m_icon = "ammo_shells";
#ifdef SVQC
this.m_botvalue = 1000;
this.m_sound = SND_ArmorSmall;
#endif
this.netname = "armor_small";
- this.m_name = "5 Armor";
+ this.m_name = _("Small armor");
this.m_icon = "armor";
#ifdef SVQC
this.m_itemid = IT_ARMOR_SHARD;
this.m_sound = SND_ArmorMedium;
#endif
this.netname = "armor_medium";
- this.m_name = "25 Armor";
+ this.m_name = _("Medium armor");
this.m_icon = "armor";
#ifdef SVQC
this.m_itemid = IT_ARMOR;
this.m_sound = SND_ArmorBig;
#endif
this.netname = "armor_big";
- this.m_name = "50 Armor";
+ this.m_name = _("Big armor");
this.m_icon = "armor";
this.m_color = '0 1 0';
this.m_waypoint = _("Big armor");
this.m_sound = SND_ArmorMega;
#endif
this.netname = "armor_mega";
- this.m_name = "100 Armor";
+ this.m_name = _("Mega armor");
this.m_icon = "item_large_armor";
this.m_color = '0 1 0';
this.m_waypoint = _("Mega armor");
this.m_sound = SND_HealthSmall;
#endif
this.netname = "health_small";
- this.m_name = "5 Health";
+ this.m_name = _("Small health");
this.m_icon = "health";
#ifdef SVQC
this.m_itemid = IT_5HP;
this.m_sound = SND_HealthMedium;
#endif
this.netname = "health_medium";
- this.m_name = "25 Health";
+ this.m_name = _("Medium health");
this.m_icon = "health";
#ifdef SVQC
this.m_itemid = IT_25HP;
this.m_sound = SND_HealthBig;
#endif
this.netname = "health_big";
- this.m_name = "50 Health";
+ this.m_name = _("Big health");
this.m_icon = "health";
this.m_color = '1 0 0';
this.m_waypoint = _("Big health");
this.m_sound = SND_HealthMega;
#endif
this.netname = "health_mega";
- this.m_name = "100 Health";
+ this.m_name = _("Mega health");
this.m_icon = "item_mega_health";
this.m_color = '1 0 0';
this.m_waypoint = _("Mega health");
this.m_itemid = IT_JETPACK;
#endif
this.netname = "jetpack";
- this.m_name = "Jetpack";
+ this.m_name = _("Jetpack");
this.m_icon = "jetpack";
this.m_color = '0.5 0.5 0.5';
this.m_waypoint = _("Jetpack");
this.m_model = MDL_JetpackFuel_ITEM;
#endif
this.netname = "fuel";
- this.m_name = "Fuel";
+ this.m_name = _("fuel");
this.m_icon = "ammo_fuel";
#ifdef SVQC
this.m_botvalue = 2000;
this.m_model = MDL_JetpackRegen_ITEM;
#endif
this.netname = "fuel_regen";
- this.m_name = "Fuel regenerator";
+ this.m_name = _("Fuel regenerator");
this.m_icon = "fuelregen";
this.m_color = '1 0.5 0';
this.m_waypoint = _("Fuel regen");
this.m_respawnsound = SND_STRENGTH_RESPAWN;
#endif
this.netname = "strength";
- this.m_name = "Strength Powerup";
+ this.m_name = _("Strength");
this.m_icon = "strength";
this.m_color = '0 0 1';
this.m_waypoint = _("Strength");
this.m_respawnsound = SND_SHIELD_RESPAWN;
#endif
this.netname = "invincible";
- this.m_name = "Shield";
+ this.m_name = _("Shield");
this.m_icon = "shield";
this.m_color = '1 0 1';
this.m_waypoint = _("Shield");
set_movetype(player, MOVETYPE_WALK);
else
set_movetype(player, MOVETYPE_FLY_WORLDONLY);
- player.team_forced = 0;
+ Player_SetForcedTeamIndex(player, TEAM_FORCE_DEFAULT);
}
void minigame_rmplayer(entity minigame_session, entity player)
PutObserverInServer(player);
}
if ( autocvar_sv_minigames_observer == 2 )
- player.team_forced = -1;
+ Player_SetForcedTeamIndex(player, TEAM_FORCE_SPECTATOR);
minigame_resend(minigame_session);
}
}
REGISTER_BUFF(AMMO) {
- this.m_prettyName = _("Ammo");
- this.m_name = "ammo";
+ this.m_name = _("Ammo");
+ this.netname = "ammo";
this.m_skin = 3;
this.m_color = '0.76 1 0.1';
}
BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
REGISTER_BUFF(RESISTANCE) {
- this.m_prettyName = _("Resistance");
- this.m_name = "resistance";
+ this.m_name = _("Resistance");
+ this.netname = "resistance";
this.m_skin = 0;
this.m_color = '0.36 1 0.07';
}
BUFF_SPAWNFUNC_Q3TA_COMPAT(resistance, BUFF_RESISTANCE)
REGISTER_BUFF(SPEED) {
- this.m_prettyName = _("Speed");
- this.m_name = "speed";
+ this.m_name = _("Speed");
+ this.netname = "speed";
this.m_skin = 9;
this.m_color = '0.1 1 0.84';
}
BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
REGISTER_BUFF(MEDIC) {
- this.m_prettyName = _("Medic");
- this.m_name = "medic";
+ this.m_name = _("Medic");
+ this.netname = "medic";
this.m_skin = 1;
this.m_color = '1 0.12 0';
}
BUFF_SPAWNFUNC_Q3TA_COMPAT(revival, BUFF_MEDIC)
REGISTER_BUFF(BASH) {
- this.m_prettyName = _("Bash");
- this.m_name = "bash";
+ this.m_name = _("Bash");
+ this.netname = "bash";
this.m_skin = 5;
this.m_color = '1 0.39 0';
}
BUFF_SPAWNFUNCS(bash, BUFF_BASH)
REGISTER_BUFF(VAMPIRE) {
- this.m_prettyName = _("Vampire");
- this.m_name = "vampire";
+ this.m_name = _("Vampire");
+ this.netname = "vampire";
this.m_skin = 2;
this.m_color = '1 0 0.24';
}
BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
REGISTER_BUFF(DISABILITY) {
- this.m_prettyName = _("Disability");
- this.m_name = "disability";
+ this.m_name = _("Disability");
+ this.netname = "disability";
this.m_skin = 7;
this.m_color = '0.94 0.3 1';
}
BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
REGISTER_BUFF(VENGEANCE) {
- this.m_prettyName = _("Vengeance");
- this.m_name = "vengeance";
+ this.m_name = _("Vengeance");
+ this.netname = "vengeance";
this.m_skin = 15;
this.m_color = '1 0.23 0.61';
}
BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
REGISTER_BUFF(JUMP) {
- this.m_prettyName = _("Jump");
- this.m_name = "jump";
+ this.m_name = _("Jump");
+ this.netname = "jump";
this.m_skin = 10;
this.m_color = '0.24 0.78 1';
}
BUFF_SPAWNFUNC_Q3TA_COMPAT(jumper, BUFF_JUMP)
REGISTER_BUFF(INVISIBLE) {
- this.m_prettyName = _("Invisible");
- this.m_name = "invisible";
+ this.m_name = _("Invisible");
+ this.netname = "invisible";
this.m_skin = 12;
this.m_color = '0.5 0.5 1';
}
BUFF_SPAWNFUNC_Q3TA_COMPAT(invis, BUFF_INVISIBLE)
REGISTER_BUFF(INFERNO) {
- this.m_prettyName = _("Inferno");
- this.m_name = "inferno";
+ this.m_name = _("Inferno");
+ this.netname = "inferno";
this.m_skin = 16;
this.m_color = '1 0.62 0';
}
BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
REGISTER_BUFF(SWAPPER) {
- this.m_prettyName = _("Swapper");
- this.m_name = "swapper";
+ this.m_name = _("Swapper");
+ this.netname = "swapper";
this.m_skin = 17;
this.m_color = '0.63 0.36 1';
}
BUFF_SPAWNFUNCS(swapper, BUFF_SWAPPER)
REGISTER_BUFF(MAGNET) {
- this.m_prettyName = _("Magnet");
- this.m_name = "magnet";
+ this.m_name = _("Magnet");
+ this.netname = "magnet";
this.m_skin = 18;
this.m_color = '1 0.95 0.18';
}
BUFF_SPAWNFUNCS(magnet, BUFF_MAGNET)
REGISTER_BUFF(LUCK) {
- this.m_prettyName = _("Luck");
- this.m_name = "luck";
+ this.m_name = _("Luck");
+ this.netname = "luck";
this.m_skin = 19;
this.m_color = '1 0.23 0.44';
}
BUFF_SPAWNFUNCS(luck, BUFF_LUCK)
REGISTER_BUFF(FLIGHT) {
- this.m_prettyName = _("Flight");
- this.m_name = "flight";
+ this.m_name = _("Flight");
+ this.netname = "flight";
this.m_skin = 11;
this.m_color = '0.23 0.44 1';
}
string BUFF_NAME(int i)
{
Buff b = Buffs_from(i);
- return strcat(rgb_to_hexcolor(b.m_color), b.m_prettyName);
+ return strcat(rgb_to_hexcolor(b.m_color), b.m_name);
}
entity buff_FirstFromFlags(int _buffs)
CLASS(Buff, Pickup)
/** bit index */
ATTRIB(Buff, m_itemid, int, 0);
- ATTRIB(Buff, m_name, string, "buff");
+ ATTRIB(Buff, netname, string, "buff");
ATTRIB(Buff, m_color, vector, '1 1 1');
- ATTRIB(Buff, m_prettyName, string, "Buff");
+ ATTRIB(Buff, m_name, string, "Buff");
ATTRIB(Buff, m_skin, int, 0);
ATTRIB(Buff, m_sprite, string, "");
METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
- returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
+ returns(this.m_name, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.netname));
}
#ifdef SVQC
METHOD(Buff, m_time, float(Buff this))
STATIC_INIT(REGISTER_BUFFS) {
FOREACH(Buffs, true, {
- it.netname = it.m_name; \
it.m_itemid = BIT(it.m_id - 1); \
- it.m_sprite = strzone(strcat("buff-", it.m_name)); \
+ it.m_sprite = strzone(strcat("buff-", it.netname)); \
});
}
{
int allBuffs = STAT(BUFFS);
FOREACH(Buffs, it.m_itemid & allBuffs, {
- addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, STAT(BUFF_TIME) - time, 99), 60);
+ addPowerupItem(it.m_name, strcat("buff_", it.netname), it.m_color, bound(0, STAT(BUFF_TIME) - time, 99), 60);
});
}
MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
{
Buff b = Buffs_from(this.wp_extra);
M_ARGV(2, vector) = b.m_color;
- M_ARGV(3, string) = b.m_prettyName;
- M_ARGV(4, string) = strcat("buff_", b.m_name);
+ M_ARGV(3, string) = b.m_name;
+ M_ARGV(4, string) = strcat("buff_", b.netname);
return true;
}
}
return false;
if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
return false;
- return cvar(strcat("g_buffs_", buff.m_name));
+ return cvar(strcat("g_buffs_", buff.netname));
}
.int buff_seencount;
this.m_sound = SND_VaporizerCells;
#endif
this.netname = "vaporizer_cells";
- this.m_name = "Vaporizer Ammo";
+ this.m_name = _("Vaporizer ammo");
this.m_icon = "ammo_supercells";
#ifdef SVQC
this.m_botvalue = 2000;
this.m_sound = SND_ExtraLife;
#endif
this.netname = "extralife";
- this.m_name = "Extra life";
+ this.m_name = _("Extra life");
this.m_icon = "item_mega_health";
this.m_color = '1 0 0';
this.m_waypoint = _("Extra life");
this.m_respawnsound = SND_STRENGTH_RESPAWN;
#endif
this.netname = "invisibility";
- this.m_name = "Invisibility";
+ this.m_name = _("Invisibility");
this.m_icon = "strength";
this.m_color = '0 0 1';
this.m_waypoint = _("Invisibility");
this.m_respawnsound = SND_SHIELD_RESPAWN;
#endif
this.netname = "speed";
- this.m_name = "Speed";
+ this.m_name = _("Speed");
this.m_icon = "shield";
this.m_color = '1 0 1';
this.m_waypoint = _("Speed");
float autocvar_g_waypointsprite_timealphaexponent;
bool autocvar_g_waypointsprite_turrets = true;
float autocvar_g_waypointsprite_turrets_maxdist = 5000;
+bool autocvar_g_waypointsprite_turrets_text = false;
bool autocvar_g_waypointsprite_uppercase;
bool autocvar_g_waypointsprite_text;
float autocvar_g_waypointsprite_iconsize = 32;
MSG_INFO_NOTIF(ITEM_BUFF_GOT, N_CONSOLE, 0, 1, "item_buffname", "", "", _("^BGYou got the %s^BG buff!"), "")
MSG_INFO_NOTIF(ITEM_WEAPON_DONTHAVE, N_DISABLE, 0, 1, "item_wepname", "", "", _("^BGYou do not have the ^F1%s"), "")
- MSG_INFO_NOTIF(ITEM_WEAPON_DROP, N_DISABLE, 1, 1, "item_wepname item_wepammo", "", "", _("^BGYou dropped the ^F1%s^BG%s"), "")
+ MSG_INFO_NOTIF(ITEM_WEAPON_DROP, N_DISABLE, 0, 2, "item_wepname item_wepammo", "", "", _("^BGYou dropped the ^F1%s^BG%s"), "")
MSG_INFO_NOTIF(ITEM_WEAPON_GOT, N_DISABLE, 0, 1, "item_wepname", "", "", _("^BGYou got the ^F1%s"), "")
MSG_INFO_NOTIF(ITEM_WEAPON_NOAMMO, N_DISABLE, 0, 1, "item_wepname", "", "", _("^BGYou don't have enough ammo for the ^F1%s"), "")
MSG_INFO_NOTIF(ITEM_WEAPON_PRIMORSEC, N_DISABLE, 0, 3, "item_wepname f2primsec f3primsec", "", "", _("^F1%s %s^BG is unable to fire, but its ^F1%s^BG can"), "")
MSG_INFO_NOTIF(QUIT_KICK_IDLING, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked for idling"), "")
MSG_INFO_NOTIF(QUIT_KICK_SPECTATING, N_CONSOLE, 0, 0, "", "", "", _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked for excessive teamkilling"), "")
- MSG_INFO_NOTIF(QUIT_SPECTATE, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^F3 is now spectating"), "")
+ MSG_INFO_NOTIF(QUIT_SPECTATE, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 is now spectating"), "")
MSG_INFO_NOTIF(RACE_ABANDONED, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG has abandoned the race"), "")
MSG_INFO_NOTIF(RACE_FAIL_RANKED, N_CONSOLE, 1, 3, "s1 race_col f1ord race_col f3race_time race_diff", "s1 f3race_time", "race_newfail", _("^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s"), "")
MSG_INFO_NOTIF(TEAMCHANGE_LARGERTEAM, N_CONSOLE, 0, 0, "", "", "", _("^BGYou cannot change to a larger team"), "")
MSG_INFO_NOTIF(TEAMCHANGE_NOTALLOWED, N_CONSOLE, 0, 0, "", "", "", _("^BGYou are not allowed to change teams"), "")
- MSG_INFO_NOTIF(VERSION_BETA, N_CHATCON, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s"), "")
+ MSG_INFO_NOTIF(VERSION_BETA, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s"), "")
MSG_INFO_NOTIF(VERSION_OLD, N_CHATCON, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"), "")
MSG_INFO_NOTIF(VERSION_OUTDATED, N_CHATCON, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get the update from ^F3http://www.xonotic.org/^BG!"), "")
MSG_CENTER_NOTIF(ITEM_FUELREGEN_GOT, N_ENABLE, 0, 0, "", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Fuel regenerator"), "")
MSG_CENTER_NOTIF(ITEM_JETPACK_GOT, N_ENABLE, 0, 0, "", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Jetpack"), "")
MSG_CENTER_NOTIF(ITEM_WEAPON_DONTHAVE, N_ENABLE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "")
- MSG_CENTER_NOTIF(ITEM_WEAPON_DROP, N_ENABLE, 1, 1, "item_wepname item_wepammo", CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "")
+ MSG_CENTER_NOTIF(ITEM_WEAPON_DROP, N_ENABLE, 0, 2, "item_wepname item_wepammo", CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "")
MSG_CENTER_NOTIF(ITEM_WEAPON_GOT, N_ENABLE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%s"), "")
MSG_CENTER_NOTIF(ITEM_WEAPON_NOAMMO, N_ENABLE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou don't have enough ammo for the ^F1%s"), "")
MSG_CENTER_NOTIF(ITEM_WEAPON_PRIMORSEC, N_ENABLE, 0, 3, "item_wepname f2primsec f3primsec", CPID_ITEM, "item_centime 0", _("^F1%s %s^BG is unable to fire, but its ^F1%s^BG can"), "")
#include <common/teams.qh>
#include <common/util.qh>
#include <common/sounds/sound.qh>
+#include <common/weapons/all.qh>
#ifdef CSQC
#include <client/autocvars.qh>
spree_end: placed at the end of murder messages to show ending of sprees
spree_lost: placed at the end of suicide messages to show losing of sprees
item_wepname: return full name of a weapon from weaponid
- item_wepammo: ammo display for weapon from string
+ item_wepammo: ammo display for weapon from f1 and f2
item_centime: amount of time to display weapon message in centerprint
item_buffname: return full name of a buff from buffid
death_team: show the full name of the team a player is switching from
ARG_CASE(ARG_CS_SV, "item_wepname", Weapons_from(f1).m_name) \
ARG_CASE(ARG_CS_SV, "item_buffname", BUFF_NAME(f1)) \
ARG_CASE(ARG_CS_SV, "f3buffname", BUFF_NAME(f3)) \
- ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
+ ARG_CASE(ARG_CS_SV, "item_wepammo", (f2 > 0 ? notif_arg_item_wepammo(f1, f2) : "")) \
ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \
ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \
ARG_CASE(ARG_CS, "death_team", Team_ColoredFullName(f1 - 1)) \
return "";
}
+string notif_arg_item_wepammo(float f1, float f2)
+{
+ string ammoitems = "";
+ Weapon wep = Weapons_from(f1);
+ switch (wep.ammo_type)
+ {
+ case RESOURCE_SHELLS: ammoitems = ITEM_Shells.m_name; break;
+ case RESOURCE_BULLETS: ammoitems = ITEM_Bullets.m_name; break;
+ case RESOURCE_ROCKETS: ammoitems = ITEM_Rockets.m_name; break;
+ case RESOURCE_CELLS: ammoitems = ITEM_Cells.m_name; break;
+ case RESOURCE_PLASMA: ammoitems = ITEM_Plasma.m_name; break;
+ case RESOURCE_FUEL: ammoitems = ITEM_JetpackFuel.m_name; break;
+ default: return ""; // doesn't use ammo
+ }
+ return sprintf(_(" with %d %s"), f2, ammoitems);
+}
+
// ====================================
// Initialization/Create Declarations
}
}
bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+ if(this.viewloc && !(this.viewloc.spawnflags & VIEWLOC_FREEMOVE) && PHYS_CS(this).movement.x < 0)
+ do_crouch = true;
if (have_hook) {
do_crouch = false;
//} else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
}
o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
- o = drawsprite_TextOrIcon(true, o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
+ if(autocvar_g_waypointsprite_turrets_text)
+ {
+ o = drawsprite_TextOrIcon(true, o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
+ }
drawhealthbar(
o,
0,
if(!checkpvs(e_target.origin, e_turret))
return -1;
- if(e_target.alpha <= 0.3)
+ if(e_target.alpha != 0 && e_target.alpha <= 0.3)
return -1;
if(MUTATOR_CALLHOOK(TurretValidateTarget, e_turret, e_target, validate_flags))
if(PHYS_CS(this).movement_x > 0) // right
this.angles_y = forward.y;
}
-
+ #if 0
//if(!PHYS_INPUT_BUTTON_CROUCH(this) && !IS_DUCKED(this))
if(!(this.viewloc.spawnflags & VIEWLOC_FREEMOVE))
{
//else { input_buttons &= ~16; this.flags &= ~FL_DUCKED; }
#endif
}
+ #endif
}
}
//float autocvar_g_balance_powerup_strength_time;
float autocvar_g_balance_superweapons_time;
float autocvar_g_balance_selfdamagepercent;
-bool autocvar_g_balance_teams;
-bool autocvar_g_balance_teams_prevent_imbalance;
-//float autocvar_g_balance_teams_scorefactor;
float autocvar_g_ballistics_density_corpse;
float autocvar_g_ballistics_density_player;
float autocvar_g_ballistics_mindistance;
#define autocvar_g_campaign_forceteam cvar("g_campaign_forceteam")
int autocvar_g_campaign_skill;
int autocvar_g_casings;
-bool autocvar_g_changeteam_banned;
float autocvar_g_chat_flood_burst;
float autocvar_g_chat_flood_burst_team;
float autocvar_g_chat_flood_burst_tell;
bool autocvar_g_chat_teamcolors;
bool autocvar_g_chat_tellprivacy;
bool autocvar_g_forced_respawn;
-string autocvar_g_forced_team_blue;
-string autocvar_g_forced_team_otherwise;
-string autocvar_g_forced_team_pink;
-string autocvar_g_forced_team_red;
-string autocvar_g_forced_team_yellow;
+string autocvar_g_forced_team_otherwise; // TODO: Move to teamplay.qc
#define autocvar_g_friendlyfire cvar("g_friendlyfire")
#define autocvar_g_friendlyfire_virtual cvar("g_friendlyfire_virtual")
#define autocvar_g_friendlyfire_virtual_force cvar("g_friendlyfire_virtual_force")
string autocvar_sv_weaponstats_file;
float autocvar_sv_gibhealth;
float autocvar_sys_ticrate;
-bool autocvar_teamplay_lockonrestart;
-int autocvar_teamplay_mode;
#define autocvar_timelimit cvar("timelimit")
#define autocvar_timelimit_override cvar("timelimit_override")
float autocvar_timelimit_increment;
WaypointSprite_PlayerDead(this);
- if (mutator_returnvalue) {
- // mutator prevents resetting teams+score
- } else {
- Player_SetTeamIndex(this, -1);
- this.frags = FRAGS_SPECTATOR;
- PlayerScore_Clear(this); // clear scores when needed
- }
-
if (CS(this).killcount != FRAGS_SPECTATOR)
{
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
if(!game_stopped)
if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2))
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
-
- if(!CS(this).just_joined)
- LogTeamchange(this.playerid, -1, TEAM_CHANGE_SPECTATOR);
- else
- CS(this).just_joined = false;
}
accuracy_resend(this);
this.strength_finished = 0;
this.invincible_finished = 0;
this.superweapons_finished = 0;
- this.dphitcontentsmask = 0;
+ //this.dphitcontentsmask = 0;
+ this.dphitcontentsmask = DPCONTENTS_SOLID;
+ if (autocvar_g_playerclip_collisions)
+ this.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
this.pushltime = 0;
this.istypefrag = 0;
setthink(this, func_null);
if(axh.owner == this && axh != NULL && !wasfreed(axh))
delete(axh);
}
+
+ if (mutator_returnvalue)
+ {
+ // mutator prevents resetting teams+score
+ }
+ else
+ {
+ SetPlayerTeam(this, -1, TEAM_CHANGE_SPECTATOR);
+ this.frags = FRAGS_SPECTATOR;
+ }
}
int player_getspecies(entity this)
bot_clientconnect(this);
- // identify the right forced team
- if (autocvar_g_campaign)
- {
- if (IS_REAL_CLIENT(this)) // only players, not bots
- {
- switch (autocvar_g_campaign_forceteam)
- {
- case 1: this.team_forced = NUM_TEAM_1; break;
- case 2: this.team_forced = NUM_TEAM_2; break;
- case 3: this.team_forced = NUM_TEAM_3; break;
- case 4: this.team_forced = NUM_TEAM_4; break;
- default: this.team_forced = 0;
- }
- }
- }
- else if (PlayerInList(this, autocvar_g_forced_team_red)) this.team_forced = NUM_TEAM_1;
- else if (PlayerInList(this, autocvar_g_forced_team_blue)) this.team_forced = NUM_TEAM_2;
- else if (PlayerInList(this, autocvar_g_forced_team_yellow)) this.team_forced = NUM_TEAM_3;
- else if (PlayerInList(this, autocvar_g_forced_team_pink)) this.team_forced = NUM_TEAM_4;
- else switch (autocvar_g_forced_team_otherwise)
- {
- default: this.team_forced = 0; break;
- case "red": this.team_forced = NUM_TEAM_1; break;
- case "blue": this.team_forced = NUM_TEAM_2; break;
- case "yellow": this.team_forced = NUM_TEAM_3; break;
- case "pink": this.team_forced = NUM_TEAM_4; break;
- case "spectate":
- case "spectator":
- this.team_forced = -1;
- break;
- }
- if (!teamplay && this.team_forced > 0) this.team_forced = 0;
+ Player_DetermineForcedTeam(this);
TRANSMUTE(Observer, this);
keys = BITSET(keys, KEY_LEFT, CS(this).movement.y < 0);
keys = BITSET(keys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(this));
- keys = BITSET(keys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(this));
+ keys = BITSET(keys, KEY_CROUCH, IS_DUCKED(this)); // workaround: player can't un-crouch until their path is clear, so we keep the button held here
keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this));
keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this));
CS(this).pressedkeys = keys; // store for other users
.bool team_selected;
bool ShowTeamSelection(entity this)
{
- if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (CS(this).wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0)
+ if (!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (CS(this).wasplayer && autocvar_g_changeteam_banned) || Player_HasRealForcedTeam(this))
return false;
stuffcmd(this, "menu_showteamselect\n");
return true;
if(IS_PLAYER(this))
if(teamplay && this.team != -1)
{
- //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname);
}
else
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname);
return 0;
}
- if(this && this.team_forced < 0)
+ if(this && (Player_GetForcedTeamIndex(this) == TEAM_FORCE_SPECTATOR))
return 0; // forced spectators can never join
// TODO simplify this
// don't do this in ClientConnect
// many things can go wrong if a client is spawned as player on connection
if (MUTATOR_CALLHOOK(AutoJoinOnConnection, this)
- || (!(autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0)
+ || (!(autocvar_sv_spectate || autocvar_g_campaign || (Player_GetForcedTeamIndex(this) == TEAM_FORCE_SPECTATOR))
&& (!teamplay || autocvar_g_balance_teams)))
{
campaign_bots_may_start = true;
return false;
}
+bool PlayerInList(entity player, string list);
+
/// \brief Print the string to the client's chat.
/// \param[in] client Client to print to.
/// \param[in] text Text to print.
PutObserverInServer(this);
}
else
- SV_ChangeTeam(this, this.killindicator_teamchange - 1);
+ {
+ Player_SetTeamIndexChecked(this, Team_TeamToIndex(
+ this.killindicator_teamchange));
+ }
this.killindicator_teamchange = 0;
}
{
// JoinBestTeam(caller, false, true);
}
- else if (teamplay && !autocvar_sv_spectate && !(caller.team_forced > 0))
+ else if (teamplay && !autocvar_sv_spectate && !(Player_GetForcedTeamIndex(caller) > 0))
{
TRANSMUTE(Observer, caller); // really?
stuffcmd(caller, "menu_showteamselect\n");
case CMD_REQUEST_COMMAND:
{
if (argc >= 2)
- {
- string _classname = string_null;
- if (!IS_PLAYER(caller) && caller.caplayer)
- {
- // CA: make work team chat for killed players
- _classname = caller.classname;
- caller.classname = STR_PLAYER;
- }
-
Say(caller, true, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
- if (_classname)
- caller.classname = _classname;
- }
return; // never fall through to usage
}
sprint(caller, "^7selectteam can only be used in teamgames\n");
return;
}
- if (caller.team_forced > 0)
+ if (Player_GetForcedTeamIndex(caller) > 0)
{
sprint(caller, "^7selectteam can not be used as your team is forced\n");
return;
{
// set up
float team_id;
- float save = client.team_forced;
- client.team_forced = 0;
+ int save = Player_GetForcedTeamIndex(client);
+ Player_SetForcedTeamIndex(client, TEAM_FORCE_DEFAULT);
// find the team to move the player to
team_id = Team_ColorToTeam(destination);
{
balance = TeamBalance_CheckAllowedTeams(client);
}
- client.team_forced = save;
+ Player_SetForcedTeamIndex(client, save);
// Check to see if the destination team is even available
switch (team_id)
}
// If so, lets continue and finally move the player
- client.team_forced = 0;
+ Player_SetForcedTeamIndex(client, TEAM_FORCE_DEFAULT);
if (MoveToTeam(client, Team_TeamToIndex(team_id), 6))
{
successful = strcat(successful, (successful ? ", " : ""), playername(client, false));
}
FOREACH_CLIENT(IS_PLAYER(it) || it.caplayer, {
- if (it.team_forced) {
+ if (Player_HasRealForcedTeam(it)) {
// 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
//float serverflags;
-.int team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
-
.bool player_blocked;
.float revival_time; // time at which player was last revived
#include "bot/api.qh"
#include "g_hook.qh"
#include <server/mutators/_mod.qh>
+#include "teamplay.qh"
#include "scores.qh"
#include "spawnpoints.qh"
#include "../common/state.qh"
string NearestLocation(vector p);
+string AmmoNameFromWeaponentity(Weapon wep);
+
void play2(entity e, string filename);
string playername(entity p, bool team_colorize);
#include "../common/minigames/sv_minigames.qh"
+#include <common/gamemodes/_mod.qh>
+
#include "../common/physics/player.qh"
#include "../common/effects/qc/_mod.qh"
#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
if(this.classname != "body")
Obituary (attacker, inflictor, this, deathtype, weaponentity);
- // increment frag counter for used weapon type
- Weapon w = DEATH_WEAPONOF(deathtype);
+ // increment frag counter for used weapon type
+ Weapon w = DEATH_WEAPONOF(deathtype);
if(w != WEP_Null && accuracy_isgooddamage(attacker, this))
CS(attacker).accuracy.(accuracy_frags[w.m_id-1]) += 1;
int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
{
if (!teamsay && !privatesay && substring(msgin, 0, 1) == " ")
- msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
+ msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
- if(source)
+ if (source)
msgin = formatmessage(source, msgin);
- string colorstr;
- if (!IS_PLAYER(source))
+ string colorstr;
+ if (!(IS_PLAYER(source) || source.caplayer))
colorstr = "^0"; // black for spectators
else if(teamplay)
colorstr = Team_ColorCode(source.team);
if(game_stopped)
teamsay = false;
- if (!source) {
+ if (!source) {
colorstr = "";
teamsay = false;
- }
+ }
if(msgin != "")
msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin);
}
*/
- string namestr = "";
- if (source)
- namestr = playername(source, autocvar_g_chat_teamcolors);
+ string namestr = "";
+ if (source)
+ namestr = playername(source, autocvar_g_chat_teamcolors);
- string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
+ string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
- string msgstr, cmsgstr;
- string privatemsgprefix = string_null;
- int privatemsgprefixlen = 0;
- if (msgin == "") {
- msgstr = cmsgstr = "";
- } else {
+ string msgstr = "", cmsgstr = "";
+ string privatemsgprefix = string_null;
+ int privatemsgprefixlen = 0;
+ if (msgin != "")
+ {
if(privatesay)
{
msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7");
msgstr = strcat("\{1}^4* ", "^7", msgin);
}
else {
- msgstr = "\{1}";
- msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
- msgstr = strcat(msgstr, msgin);
- }
+ msgstr = "\{1}";
+ msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
+ msgstr = strcat(msgstr, msgin);
+ }
cmsgstr = "";
}
msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
source.(flood_field) = flood = 0;
}
- string sourcemsgstr, sourcecmsgstr;
+ string sourcemsgstr, sourcecmsgstr;
if(flood == 2) // cannot happen for empty msgstr
{
if(autocvar_g_chat_flood_notify_flooder)
sourcecmsgstr = cmsgstr;
}
- if (!privatesay && source && !IS_PLAYER(source))
+ if (!privatesay && source && !(IS_PLAYER(source) || source.caplayer))
{
if (!game_stopped)
if (teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
if(privatesay)
sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
- int ret;
+ int ret;
if(source && CS(source).muted)
{
// always fake the message
ret = 1;
}
- if (privatesay && source && !IS_PLAYER(source))
+ if (privatesay && source && !(IS_PLAYER(source) || source.caplayer))
{
if (!game_stopped)
- if ((privatesay && IS_PLAYER(privatesay)) && ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage)))
+ if ((privatesay && (IS_PLAYER(privatesay) || privatesay.caplayer)) && ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage)))
ret = -1; // just hide the message completely
}
{
sprint(source, sourcemsgstr);
dedicated_print(msgstr); // send to server console too
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && CS(it).active_minigame == CS(source).active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && CS(it).active_minigame == CS(source).active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+ sprint(it, msgstr);
+ });
}
else if(teamsay > 0) // team message, only sent to team mates
{
dedicated_print(msgstr); // send to server console too
if(sourcecmsgstr != "")
centerprint(source, sourcecmsgstr);
- FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+ FOREACH_CLIENT((IS_PLAYER(it) || it.caplayer) && IS_REAL_CLIENT(it) && it != source && it.team == source.team && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
sprint(it, msgstr);
if(cmsgstr != "")
centerprint(it, cmsgstr);
{
sprint(source, sourcemsgstr);
dedicated_print(msgstr); // send to server console too
- FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
+ FOREACH_CLIENT(!(IS_PLAYER(it) || it.caplayer) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+ sprint(it, msgstr);
+ });
}
else
{
- if (source) {
- sprint(source, sourcemsgstr);
- dedicated_print(msgstr); // send to server console too
- MX_Say(strcat(playername(source, true), "^7: ", msgin));
- }
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
- }
+ if (source) {
+ sprint(source, sourcemsgstr);
+ dedicated_print(msgstr); // send to server console too
+ MX_Say(strcat(playername(source, true), "^7: ", msgin));
+ }
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+ sprint(it, msgstr);
+ });
+ }
}
return ret;
/// \brief Indicates that the player is not allowed to join a team.
const int TEAM_NOT_ALLOWED = -1;
+.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
+
.int m_team_balance_state; ///< Holds the state of the team balance entity.
.entity m_team_balance_team[NUM_TEAMS]; ///< ???
.int m_num_players_alive; ///< Number of alive players in a team.
.int m_num_control_points; ///< Number of control points owned by a team.
+string autocvar_g_forced_team_red;
+string autocvar_g_forced_team_blue;
+string autocvar_g_forced_team_yellow;
+string autocvar_g_forced_team_pink;
+
entity g_team_entities[NUM_TEAMS]; ///< Holds global team entities.
STATIC_INIT(g_team_entities)
{
return false;
}
- LogTeamchange(player.playerid, player.team, type);
+ LogTeamChange(player.playerid, player.team, type);
if (team_index != old_team_index)
{
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team,
- INFO_JOIN_PLAY_TEAM), player.netname);
+ PlayerScore_Clear(player);
+ if (team_index != -1)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(
+ player.team, INFO_JOIN_PLAY_TEAM), player.netname);
+ }
+ else
+ {
+ if (!CS(player).just_joined)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE,
+ player.netname);
+ }
+ else
+ {
+ CS(player).just_joined = false;
+ }
+ }
KillPlayerForTeamChange(player);
+ if (!IS_BOT_CLIENT(player))
+ {
+ TeamBalance_AutoBalanceBots();
+ }
}
return true;
}
+void Player_SetTeamIndexChecked(entity player, int team_index)
+{
+ if (!teamplay)
+ {
+ return;
+ }
+ if (!Team_IsValidIndex(team_index))
+ {
+ return;
+ }
+ if ((autocvar_g_campaign) || (autocvar_g_changeteam_banned &&
+ CS(player).wasplayer))
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_INFO,
+ INFO_TEAMCHANGE_NOTALLOWED);
+ return;
+ }
+ entity balance = TeamBalance_CheckAllowedTeams(player);
+ if (team_index == 1 && !TeamBalance_IsTeamAllowedInternal(balance, 1))
+ {
+ team_index = 4;
+ }
+ if (team_index == 4 && !TeamBalance_IsTeamAllowedInternal(balance, 4))
+ {
+ team_index = 3;
+ }
+ if (team_index == 3 && !TeamBalance_IsTeamAllowedInternal(balance, 3))
+ {
+ team_index = 2;
+ }
+ if (team_index == 2 && !TeamBalance_IsTeamAllowedInternal(balance, 2))
+ {
+ team_index = 1;
+ }
+ // 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)
+ {
+ TeamBalance_GetTeamCounts(balance, player);
+ if ((Team_IndexToBit(team_index) & TeamBalance_FindBestTeams(balance,
+ player, false)) == 0)
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_INFO,
+ INFO_TEAMCHANGE_LARGERTEAM);
+ TeamBalance_Destroy(balance);
+ return;
+ }
+ }
+ TeamBalance_Destroy(balance);
+ SetPlayerTeam(player, team_index, TEAM_CHANGE_MANUAL);
+}
+
bool MoveToTeam(entity client, int team_index, int type)
{
//PrintToChatAll(sprintf("MoveToTeam: %s, %f", client.netname, team_index));
int lockteams_backup = lockteams; // backup any team lock
lockteams = 0; // disable locked teams
- PlayerScore_Clear(client);
if (!SetPlayerTeam(client, team_index, type))
{
lockteams = lockteams_backup; // restore the team lock
return true;
}
-void KillPlayerForTeamChange(entity player)
+bool Player_HasRealForcedTeam(entity player)
{
- if (IS_DEAD(player))
+ return player.team_forced > TEAM_FORCE_DEFAULT;
+}
+
+int Player_GetForcedTeamIndex(entity player)
+{
+ return player.team_forced;
+}
+
+void Player_SetForcedTeamIndex(entity player, int team_index)
+{
+ switch (team_index)
{
- return;
+ case TEAM_FORCE_SPECTATOR:
+ case TEAM_FORCE_DEFAULT:
+ {
+ player.team_forced = team_index;
+ break;
+ }
+ default:
+ {
+ if (!Team_IsValidIndex(team_index))
+ {
+ LOG_FATAL("Player_SetForcedTeamIndex: Invalid team index.");
+ }
+ else
+ {
+ player.team_forced = team_index;
+ break;
+ }
+ }
}
- if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
+}
+
+void Player_DetermineForcedTeam(entity player)
+{
+ if (autocvar_g_campaign)
{
- return;
+ if (IS_REAL_CLIENT(player)) // only players, not bots
+ {
+ if (Team_IsValidIndex(autocvar_g_campaign_forceteam))
+ {
+ player.team_forced = autocvar_g_campaign_forceteam;
+ }
+ else
+ {
+ player.team_forced = TEAM_FORCE_DEFAULT;
+ }
+ }
+ }
+ else if (PlayerInList(player, autocvar_g_forced_team_red))
+ {
+ player.team_forced = 1;
+ }
+ else if (PlayerInList(player, autocvar_g_forced_team_blue))
+ {
+ player.team_forced = 2;
+ }
+ else if (PlayerInList(player, autocvar_g_forced_team_yellow))
+ {
+ player.team_forced = 3;
+ }
+ else if (PlayerInList(player, autocvar_g_forced_team_pink))
+ {
+ player.team_forced = 4;
+ }
+ else
+ {
+ switch (autocvar_g_forced_team_otherwise)
+ {
+ case "red":
+ {
+ player.team_forced = 1;
+ break;
+ }
+ case "blue":
+ {
+ player.team_forced = 2;
+ break;
+ }
+ case "yellow":
+ {
+ player.team_forced = 3;
+ break;
+ }
+ case "pink":
+ {
+ player.team_forced = 4;
+ break;
+ }
+ case "spectate":
+ case "spectator":
+ {
+ player.team_forced = TEAM_FORCE_SPECTATOR;
+ break;
+ }
+ default:
+ {
+ player.team_forced = TEAM_FORCE_DEFAULT;
+ break;
+ }
+ }
+ }
+ if (!teamplay && Player_HasRealForcedTeam(player))
+ {
+ player.team_forced = TEAM_FORCE_DEFAULT;
}
- Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP,
- player.origin, '0 0 0');
}
-void LogTeamchange(float player_id, float team_number, int type)
+void TeamBalance_JoinBestTeam(entity player)
{
- if(!autocvar_sv_eventlog)
+ //PrintToChatAll(sprintf("TeamBalance_JoinBestTeam: %s", player.netname));
+ if (!teamplay)
+ {
return;
-
- if(player_id < 1)
+ }
+ if (player.bot_forced_team)
+ {
return;
-
- GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type)));
+ }
+ entity balance = TeamBalance_CheckAllowedTeams(player);
+ if (Player_HasRealForcedTeam(player))
+ {
+ int forced_team_index = player.team_forced;
+ bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance,
+ forced_team_index);
+ TeamBalance_Destroy(balance);
+ if (!is_team_allowed)
+ {
+ return;
+ }
+ if (!SetPlayerTeam(player, forced_team_index, TEAM_CHANGE_AUTO))
+ {
+ return;
+ }
+ return;
+ }
+ int best_team_index = TeamBalance_FindBestTeam(balance, player, true);
+ TeamBalance_Destroy(balance);
+ if (!SetPlayerTeam(player, best_team_index, TEAM_CHANGE_AUTO))
+ {
+ return;
+ }
}
entity TeamBalance_CheckAllowedTeams(entity for_whom)
// if player has a forced team, ONLY allow that one
for (int i = 1; i <= NUM_TEAMS; ++i)
{
- if (for_whom.team_forced == Team_IndexToTeam(i) &&
+ if (for_whom.team_forced == i &&
TeamBalance_IsTeamAllowedInternal(balance, i))
{
TeamBalance_BanTeamsExcept(balance, i);
continue;
}
int team_num;
- if (IS_PLAYER(it) || it.caplayer)
+ // TODO: Reconsider when the player is truly on the team.
+ if (IS_CLIENT(it) || (it.caplayer))
{
team_num = it.team;
}
- else if (it.team_forced > 0)
+ else if (Player_HasRealForcedTeam(it))
{
- team_num = it.team_forced; // reserve the spot
+ // Do we really need this? Probably not.
+ team_num = Team_IndexToTeam(it.team_forced); // reserve the spot
}
else
{
return team_bits;
}
-void TeamBalance_JoinBestTeam(entity this)
-{
- //PrintToChatAll(sprintf("JoinBestTeam: %s", this.netname));
- if (!teamplay)
- {
- return;
- }
- if (this.bot_forced_team)
- {
- return;
- }
- int old_team_index = Team_TeamToIndex(this.team);
- entity balance = TeamBalance_CheckAllowedTeams(this);
- if (this.team_forced > 0)
- {
- int forced_team_index = Team_TeamToIndex(this.team_forced);
- bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance,
- forced_team_index);
- TeamBalance_Destroy(balance);
- if (!is_team_allowed)
- {
- return;
- }
- if (!SetPlayerTeam(this, forced_team_index, TEAM_CHANGE_AUTO))
- {
- return;
- }
- if ((old_team_index != -1) && !IS_BOT_CLIENT(this))
- {
- TeamBalance_AutoBalanceBots(forced_team_index, old_team_index);
- }
- return;
- }
- int best_team_index = TeamBalance_FindBestTeam(balance, this, true);
- TeamBalance_Destroy(balance);
- PlayerScore_Clear(this);
- if (!SetPlayerTeam(this, best_team_index, TEAM_CHANGE_AUTO))
- {
- return;
- }
- if ((old_team_index != -1) && !IS_BOT_CLIENT(this))
- {
- TeamBalance_AutoBalanceBots(best_team_index, old_team_index);
- }
-}
-
int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b,
entity player, bool use_score)
{
return TeamBalance_CompareTeamsInternal(team_a, team_b, player, use_score);
}
-void TeamBalance_AutoBalanceBots(int source_team_index,
- int destination_team_index)
+void TeamBalance_AutoBalanceBots()
{
- if (!Team_IsValidIndex(source_team_index))
- {
- LOG_WARNF("TeamBalance_AutoBalanceBots: "
- "Source team index is invalid: %f", source_team_index);
- return;
- }
- if (!Team_IsValidIndex(destination_team_index))
- {
- LOG_WARNF("TeamBalance_AutoBalanceBots: "
- "Destination team index is invalid: %f", destination_team_index);
- return;
- }
if (!autocvar_g_balance_teams ||
!autocvar_g_balance_teams_prevent_imbalance)
{
return;
}
+ //PrintToChatAll("TeamBalance_AutoBalanceBots");
entity balance = TeamBalance_CheckAllowedTeams(NULL);
TeamBalance_GetTeamCounts(balance, NULL);
- entity source_team = TeamBalance_GetTeamFromIndex(balance,
- source_team_index);
- entity destination_team = TeamBalance_GetTeamFromIndex(balance,
- destination_team_index);
- if ((source_team.m_num_bots == 0) || (source_team.m_num_players <=
- destination_team.m_num_players))
+ int smallest_team_index = 0;
+ int smallest_team_player_count = 0;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
{
- TeamBalance_Destroy(balance);
- return;
+ entity team_ = TeamBalance_GetTeamFromIndex(balance, i);
+ if (!TeamBalanceTeam_IsAllowed(team_))
+ {
+ continue;
+ }
+ int player_count = TeamBalanceTeam_GetNumberOfPlayers(team_);
+ if (smallest_team_index == 0)
+ {
+ smallest_team_index = i;
+ smallest_team_player_count = player_count;
+ }
+ else if (player_count < smallest_team_player_count)
+ {
+ smallest_team_index = i;
+ smallest_team_player_count = player_count;
+ }
+ }
+ //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index));
+ //PrintToChatAll(sprintf("Smallest team players: %f", smallest_team_player_count));
+ entity switchable_bot = NULL;
+ int teams = BITS(NUM_TEAMS);
+ while (teams != 0)
+ {
+ int largest_team_index = TeamBalance_GetLargestTeamIndex(balance,
+ teams);
+ if (smallest_team_index == largest_team_index)
+ {
+ TeamBalance_Destroy(balance);
+ return;
+ }
+ entity largest_team = TeamBalance_GetTeamFromIndex(balance,
+ largest_team_index);
+ int largest_team_player_count = TeamBalanceTeam_GetNumberOfPlayers(
+ largest_team);
+ if (largest_team_player_count - smallest_team_player_count < 2)
+ {
+ TeamBalance_Destroy(balance);
+ return;
+ }
+ //PrintToChatAll(sprintf("Largest team: %f", largest_team_index));
+ //PrintToChatAll(sprintf("Largest team players: %f", largest_team_player_count));
+ switchable_bot = TeamBalance_GetPlayerForTeamSwitch(largest_team_index,
+ smallest_team_index, true);
+ if (switchable_bot != NULL)
+ {
+ break;
+ }
+ teams &= ~Team_IndexToBit(largest_team_index);
}
TeamBalance_Destroy(balance);
- entity lowest_bot = NULL;
+ if (switchable_bot == NULL)
+ {
+ //PrintToChatAll("No bot found after searching through all the teams");
+ return;
+ }
+ SetPlayerTeam(switchable_bot, smallest_team_index, TEAM_CHANGE_AUTO);
+}
+
+int TeamBalance_GetLargestTeamIndex(entity balance, int teams)
+{
+ int largest_team_index = 0;
+ int largest_team_player_count = 0;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ if (!(Team_IndexToBit(i) & teams))
+ {
+ continue;
+ }
+ entity team_ = TeamBalance_GetTeamFromIndex(balance, i);
+ if (!TeamBalanceTeam_IsAllowed(team_))
+ {
+ continue;
+ }
+ int player_count = TeamBalanceTeam_GetNumberOfPlayers(team_);
+ if (largest_team_index == 0)
+ {
+ largest_team_index = i;
+ largest_team_player_count = player_count;
+ }
+ else if (player_count > largest_team_player_count)
+ {
+ largest_team_index = i;
+ largest_team_player_count = player_count;
+ }
+ }
+ return largest_team_index;
+}
+
+entity TeamBalance_GetPlayerForTeamSwitch(int source_team_index,
+ int destination_team_index, bool is_bot)
+{
if (MUTATOR_CALLHOOK(TeamBalance_GetPlayerForTeamSwitch, source_team_index,
- destination_team_index, true))
+ destination_team_index, is_bot))
{
- lowest_bot = M_ARGV(3, entity);
+ return M_ARGV(3, entity);
}
- else
+ entity lowest_player = NULL;
+ float lowest_score = FLOAT_MAX;
+ FOREACH_CLIENT(Entity_GetTeamIndex(it) == source_team_index,
{
- float lowest_score = FLOAT_MAX;
- FOREACH_CLIENT(IS_BOT_CLIENT(it) && (Entity_GetTeamIndex(it) ==
- source_team_index),
+ if (IS_BOT_CLIENT(it) != is_bot)
{
- float temp_score = PlayerScore_Get(it, SP_SCORE);
- if (temp_score >= lowest_score)
- {
- continue;
- }
- balance = TeamBalance_CheckAllowedTeams(it);
- if (TeamBalance_IsTeamAllowed(balance, destination_team_index))
- {
- lowest_bot = it;
- lowest_score = temp_score;
- }
- TeamBalance_Destroy(balance);
- });
+ continue;
+ }
+ float temp_score = PlayerScore_Get(it, SP_SCORE);
+ if (temp_score >= lowest_score)
+ {
+ continue;
+ }
+ //PrintToChatAll(sprintf(
+ // "Found %s with lowest score, checking allowed teams", it.netname));
+ entity balance = TeamBalance_CheckAllowedTeams(it);
+ if (TeamBalance_IsTeamAllowed(balance, source_team_index))
+ {
+ //PrintToChatAll("Allowed");
+ lowest_player = it;
+ lowest_score = temp_score;
+ }
+ else
+ {
+ //PrintToChatAll("Not allowed");
+ }
+ TeamBalance_Destroy(balance);
+ });
+ return lowest_player;
+}
+
+void LogTeamChange(float player_id, float team_number, int type)
+{
+ if (!autocvar_sv_eventlog)
+ {
+ return;
+ }
+ if (player_id < 1)
+ {
+ return;
}
- if (lowest_bot == NULL)
+ GameLogEcho(sprintf(":team:%f:%f:%f", player_id, team_number, type));
+}
+
+void KillPlayerForTeamChange(entity player)
+{
+ if (IS_DEAD(player))
{
return;
}
- if (!Player_SetTeamIndex(lowest_bot, destination_team_index))
+ if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
{
return;
}
- KillPlayerForTeamChange(lowest_bot);
+ Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP,
+ player.origin, '0 0 0');
}
bool TeamBalance_IsTeamAllowedInternal(entity balance, int index)
return TEAMS_COMPARE_EQUAL;
}
-// Called when the player connects or when they change their color with "color"
-// command.
-void SV_ChangeTeam(entity this, float _color)
+void SV_ChangeTeam(entity player, int new_color)
{
- //PrintToChatAll(sprintf("SV_ChangeTeam: %s, %f", this.netname, _color));
-
- // in normal deathmatch we can just apply the color and we're done
- if(!teamplay)
- SetPlayerColors(this, _color);
-
- if(!IS_CLIENT(this))
- {
- // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, this.netname);
- return;
- }
-
- if(!teamplay)
- return;
-
- int source_color, destination_color;
- int source_team_index, destination_team_index;
-
- source_color = this.clientcolors & 0x0F;
- destination_color = _color & 0x0F;
-
- source_team_index = Team_TeamToIndex(source_color + 1);
- destination_team_index = Team_TeamToIndex(destination_color + 1);
-
- if (destination_team_index == -1)
- {
- return;
- }
-
- entity balance = TeamBalance_CheckAllowedTeams(this);
-
- if (destination_team_index == 1 && !TeamBalance_IsTeamAllowedInternal(
- balance, 1))
- {
- destination_team_index = 4;
- }
- if (destination_team_index == 4 && !TeamBalance_IsTeamAllowedInternal(
- balance, 4))
- {
- destination_team_index = 3;
- }
- if (destination_team_index == 3 && !TeamBalance_IsTeamAllowedInternal(
- balance, 3))
- {
- destination_team_index = 2;
- }
- if (destination_team_index == 2 && !TeamBalance_IsTeamAllowedInternal(
- balance, 2))
- {
- destination_team_index = 1;
- }
-
- // not changing teams
- if (source_color == destination_color)
- {
- SetPlayerTeam(this, destination_team_index, TEAM_CHANGE_MANUAL);
- TeamBalance_Destroy(balance);
- return;
- }
-
- if((autocvar_g_campaign) || (autocvar_g_changeteam_banned && CS(this).wasplayer)) {
- Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_NOTALLOWED);
- return; // changing teams is not allowed
- }
-
- // 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)
- {
- TeamBalance_GetTeamCounts(balance, this);
- if ((Team_IndexToBit(destination_team_index) &
- TeamBalance_FindBestTeams(balance, this, false)) == 0)
- {
- Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
- TeamBalance_Destroy(balance);
- return;
- }
- }
- TeamBalance_Destroy(balance);
- if (IS_PLAYER(this) && source_team_index != destination_team_index)
+ if (!teamplay)
{
- // reduce frags during a team change
- PlayerScore_Clear(this);
+ SetPlayerColors(player, new_color);
}
- if (!SetPlayerTeam(this, destination_team_index, TEAM_CHANGE_MANUAL))
+ // TODO: Should we really bother with this?
+ if(!IS_CLIENT(player))
{
+ // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING,
+ player.netname);
return;
}
- if (source_team_index == -1)
+ if (!teamplay)
{
return;
}
- TeamBalance_AutoBalanceBots(destination_team_index, source_team_index);
+ Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) +
+ 1));
}
#pragma once
+int autocvar_teamplay_mode;
+
+bool autocvar_g_changeteam_banned;
+bool autocvar_teamplay_lockonrestart;
+
+bool autocvar_g_balance_teams;
+bool autocvar_g_balance_teams_prevent_imbalance;
+
bool lockteams;
// ========================== Global teams API ================================
/// \return True if team switch was successful, false otherwise.
bool Player_SetTeamIndex(entity player, int index);
+enum
+{
+ TEAM_CHANGE_AUTO = 2, ///< The team was selected by autobalance.
+ TEAM_CHANGE_MANUAL = 3, ///< Player has manually selected their team.
+ TEAM_CHANGE_SPECTATOR = 4 ///< Player is joining spectators. //TODO: Remove?
+};
+
/// \brief Sets the team of the player.
/// \param[in,out] player Player to adjust.
/// \param[in] team_index Index of the team to set.
-/// \param[in] type ???
+/// \param[in] type Type of the team change. See TEAM_CHANGE constants.
/// \return True if team switch was successful, false otherwise.
bool SetPlayerTeam(entity player, int team_index, int type);
+/// \brief Sets the team of the player with all sanity checks.
+/// \param[in,out] player Player to adjust.
+/// \param[in] team_index Index of the team to set.
+void Player_SetTeamIndexChecked(entity player, int team_index);
+
/// \brief Moves player to the specified team.
/// \param[in,out] client Client to move.
/// \param[in] team_index Index of the team.
/// \return True on success, false otherwise.
bool MoveToTeam(entity client, int team_index, int type);
-/// \brief Kills player as a result of team change.
-/// \param[in,out] player Player to kill.
-void KillPlayerForTeamChange(entity player);
-
enum
{
- TEAM_CHANGE_AUTO = 2,
- TEAM_CHANGE_MANUAL = 3,
- TEAM_CHANGE_SPECTATOR = 4
+ TEAM_FORCE_SPECTATOR = -1, ///< Force the player to spectator team.
+ TEAM_FORCE_DEFAULT = 0 ///< Don't force any team.
};
-void LogTeamchange(float player_id, float team_number, int type);
+/// \brief Returns whether player has real forced team. Spectator team is
+/// ignored.
+/// \param[in] player Player to check.
+/// \return True if player has real forced team, false otherwise.
+bool Player_HasRealForcedTeam(entity player);
+
+/// \brief Returns the index of the forced team of the given player.
+/// \param[in] player Player to check.
+/// \return Index of the forced team.
+int Player_GetForcedTeamIndex(entity player);
+
+/// \brief Sets the index of the forced team of the given player.
+/// \param[in,out] player Player to adjust.
+/// \param[in] team_index Index of the team to set.
+void Player_SetForcedTeamIndex(entity player, int team_index);
+
+/// \brief Determines the forced team of the player using current global config.
+/// \param[in,out] player Player to adjust.
+void Player_DetermineForcedTeam(entity player);
// ========================= Team balance API =================================
+/// \brief Assigns the given player to a team that will make the game most
+/// balanced.
+/// \param[in,out] player Player to assign.
+void TeamBalance_JoinBestTeam(entity player);
+
/// \brief Checks whether the player can join teams according to global
/// configuration and mutator settings.
/// \param[in] for_whom Player to check for. Pass NULL for global rules.
/// function.
int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score);
-void TeamBalance_JoinBestTeam(entity this);
-
/// \brief Describes the result of comparing teams.
enum
{
entity player, bool use_score);
/// \brief Switches a bot from one team to another if teams are not balanced.
-/// \param[in] source_team_index Index of the team to switch from.
+void TeamBalance_AutoBalanceBots();
+
+/// \brief Returns the index of the team with most players that is contained in
+/// the given bitmask of teams.
+/// \param[in] balance Team balance entity.
+/// \param[in] teams Bitmask of teams to search in.
+/// \return Index of the team with most players.
+int TeamBalance_GetLargestTeamIndex(entity balance, int teams);
+
+/// \brief Returns the player who is the most suitable for switching between
+/// the given teams.
+/// \param[in] source_team_index Index of the team to search in.
/// \param[in] destination_team_index Index of the team to switch to.
-void TeamBalance_AutoBalanceBots(int source_team_index,
- int destination_team_index);
+/// \param[in] is_bot True to search for bot, false for human.
+/// \return Player who is the most suitable for switching between the given
+/// teams or NULL if not found.
+entity TeamBalance_GetPlayerForTeamSwitch(int source_team_index,
+ int destination_team_index, bool is_bot);
// ============================ Internal API ==================================
+void LogTeamChange(float player_id, float team_number, int type);
+
+/// \brief Kills player as a result of team change.
+/// \param[in,out] player Player to kill.
+void KillPlayerForTeamChange(entity player);
+
/// \brief Returns whether the team change to the specified team is allowed.
/// \param[in] balance Team balance entity.
/// \param[in] index Index of the team.
/// function.
int TeamBalance_CompareTeamsInternal(entity team_a, entity team_index_b,
entity player, bool use_score);
+
+/// \brief Called when the player connects or when they change their color with
+/// the "color" command.
+/// \param[in,out] player Player that requested a new color.
+/// \param[in] new_color Requested color.
+void SV_ChangeTeam(entity player, int new_color);
SUB_VanishOrRemove(this);
}
-// returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
-string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity)
+// returns amount of ammo used, or -1 for failure, or 0 for no ammo count
+float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity)
{
- float thisammo;
- string s;
Weapon info = Weapons_from(wpn);
int ammotype = info.ammo_type;
weapon_defaultspawnfunc(wep, info);
if(startitem_failed)
- return string_null;
+ return -1;
setthink(wep, thrown_wep_think);
wep.savenextthink = wep.nextthink;
wep.nextthink = min(wep.nextthink, time + 0.5);
//wa = W_AmmoItemCode(wpn);
if(ammotype == RESOURCE_NONE)
{
- return "";
+ return 0;
}
else
{
- s = "";
-
if(doreduce && g_weapon_stay == 2)
{
// if our weapon is loaded, give its load back to the player
}
float ownderammo = GetResourceAmount(own, ammotype);
- thisammo = min(ownderammo, GetResourceAmount(wep, ammotype));
+ float thisammo = min(ownderammo, GetResourceAmount(wep, ammotype));
SetResourceAmount(wep, ammotype, thisammo);
SetResourceAmount(own, ammotype, ownderammo - thisammo);
- switch (ammotype)
- {
- case RESOURCE_SHELLS: s = sprintf("%s and %d shells", s, thisammo); break;
- case RESOURCE_BULLETS: s = sprintf("%s and %d nails", s, thisammo); break;
- case RESOURCE_ROCKETS: s = sprintf("%s and %d rockets", s, thisammo); break;
- case RESOURCE_CELLS: s = sprintf("%s and %d cells", s, thisammo); break;
- case RESOURCE_PLASMA: s = sprintf("%s and %d plasma", s, thisammo); break;
- case RESOURCE_FUEL: s = sprintf("%s and %d fuel", s, thisammo); break;
- }
-
- s = substring(s, 5, -1);
+ return thisammo;
}
- return s;
+ return 0;
}
}
STAT(WEAPONS, this) &= ~set;
W_SwitchWeapon_Force(this, w_getbestweapon(this, weaponentity), weaponentity);
- string a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo, weaponentity);
+ float a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo, weaponentity);
- if(!a) return;
- Send_Notification(NOTIF_ONE, this, MSG_MULTI, ITEM_WEAPON_DROP, a, w.m_id);
+ if(a < 0) return;
+ Send_Notification(NOTIF_ONE, this, MSG_MULTI, ITEM_WEAPON_DROP, w.m_id, a);
}
void SpawnThrownWeapon(entity this, vector org, Weapon wep, .entity weaponentity)
.float savenextthink;
void thrown_wep_think(entity this);
-// returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
-string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity);
+// returns amount of ammo used, or -1 for failure, or 0 for no ammo count
+float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity);
bool W_IsWeaponThrowable(entity this, int w);
set g_waypointsprite_timealphaexponent 1
seta g_waypointsprite_turrets 1 "disable turret waypoints"
seta g_waypointsprite_turrets_maxdist 5000 "max distance for turret waypoints"
+seta g_waypointsprite_turrets_text 0 "show the turret's name in the waypoint"
seta g_waypointsprite_uppercase 1
seta g_waypointsprite_text 0 "Always show text instead of icons, setting this to 0 will still use text if the icon is unavailable"
seta g_waypointsprite_iconsize 32
set g_balance_teams 1 "automatically balance out players entering instead of asking them for their preferred team"
set g_balance_teams_prevent_imbalance 1 "prevent players from changing to larger teams"
-set g_balance_teams_scorefactor 0.25 "at the end of the game, take score into account instead of team size by this amount (beware: values over 0.5 mean that a x:0 score imbalance will cause ALL new players to prefer the losing team at the end, despite numbers)"
set g_changeteam_banned 0 "not allowed to change team"
-set g_changeteam_fragtransfer 0 "% of frags you get to keep when you change teams (rounded down)"
set sv_teamnagger 1 "enable a nag message when the teams are unbalanced"