ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
}
- plyr.(weaponentity).weapons = plyr.weapons;
+ STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
- plyr.weapons = WEPSET(NEXBALL);
+ STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
Weapon w = WEP_NEXBALL;
w.wr_resetplayer(w, plyr);
plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
EXACTTRIGGER_INIT;
- if(this.team != GOAL_OUT && Team_TeamToNumber(this.team) != -1)
+ if(this.team != GOAL_OUT && Team_IsValidTeam(this.team))
{
entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (this.absmin + this.absmax) * 0.5, this, sprite, RADARICON_NONE);
wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0.5 0');
{
.entity weaponentity = weaponentities[slot];
- if(player.(weaponentity).weapons)
+ if(STAT(WEAPONS, player.(weaponentity)))
{
- player.weapons = player.(weaponentity).weapons;
+ STAT(WEAPONS, player) = STAT(WEAPONS, player.(weaponentity));
Weapon w = WEP_NEXBALL;
w.wr_resetplayer(w, player);
player.(weaponentity).m_switchweapon = player.m_switchweapon;
W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity);
- player.(weaponentity).weapons = '0 0 0';
+ STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
}
}
}
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
.entity weaponentity = weaponentities[slot];
- player.(weaponentity).weapons = '0 0 0';
+ STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
}
if (nexball_mode & NBM_BASKETBALL)
- player.weapons |= WEPSET(NEXBALL);
+ STAT(WEAPONS, player) |= WEPSET(NEXBALL);
else
- player.weapons = '0 0 0';
+ STAT(WEAPONS, player) = '0 0 0';
return false;
}
return MUT_ITEMTOUCH_CONTINUE;
}
-MUTATOR_HOOKFUNCTION(nb, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(nb, TeamBalance_CheckAllowedTeams)
{
M_ARGV(1, string) = "nexball_team";
return true;
void Onslaught_count_generators()
{
entity e;
- total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
+ total_generators = 0;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ Team_SetNumberOfControlPoints(Team_GetTeamFromIndex(i), 0);
+ }
for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
{
++total_generators;
- redowned += (e.team == NUM_TEAM_1 && e.health > 0);
- blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
- yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
- pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
+ if (GetResourceAmount(e, RESOURCE_HEALTH) < 1)
+ {
+ continue;
+ }
+ entity team_ = Entity_GetTeam(e);
+ int num_control_points = Team_GetNumberOfControlPoints(team_);
+ ++num_control_points;
+ Team_SetNumberOfControlPoints(team_, num_control_points);
}
}
int Onslaught_GetWinnerTeam()
{
int winner_team = 0;
- if(redowned > 0)
- winner_team = NUM_TEAM_1;
- if(blueowned > 0)
+ if (Team_GetNumberOfControlPoints(Team_GetTeamFromIndex(1)) >= 1)
{
- if(winner_team) return 0;
- winner_team = NUM_TEAM_2;
+ winner_team = NUM_TEAM_1;
}
- if(yellowowned > 0)
+ for (int i = 2; i <= NUM_TEAMS; ++i)
{
- if(winner_team) return 0;
- winner_team = NUM_TEAM_3;
+ if (Team_GetNumberOfControlPoints(Team_GetTeamFromIndex(i)) >= 1)
+ {
+ if (winner_team != 0)
+ {
+ return 0;
+ }
+ winner_team = Team_IndexToTeam(i);
+ }
}
- if(pinkowned > 0)
+ if (winner_team)
{
- if(winner_team) return 0;
- winner_team = NUM_TEAM_4;
- }
- if(winner_team)
return winner_team;
+ }
return -1; // no generators left?
}
void nades_Clear(entity e);
-#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
bool Onslaught_CheckWinner()
{
if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
Onslaught_count_generators();
- if(ONS_OWNED_GENERATORS_OK())
+ if (Team_GetNumberOfTeamsWithControlPoints() > 1)
+ {
return 0;
+ }
int winner_team = Onslaught_GetWinnerTeam();
// Needs weapons?
int c = 0;
FOREACH(Weapons, it != WEP_Null, {
- if(this.weapons & (it.m_wepset))
+ if(STAT(WEAPONS, this) & (it.m_wepset))
if(++c >= 4)
break;
});
{
// gather health and armor only
if (it.solid)
- if ( ((it.health || it.armorvalue) && needarmor) || (it.weapons && needweapons ) )
+ if ( ((it.health || it.armorvalue) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
if (vdist(it.origin - org, <, sradius))
{
int t = it.bot_pickupevalfunc(this, it);
return true;
}
-MUTATOR_HOOKFUNCTION(ons, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(ons, TeamBalance_CheckAllowedTeams)
{
// onslaught is special
for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
{
- switch(tmp_entity.team)
+ if (Team_IsValidTeam(tmp_entity.team))
{
- case NUM_TEAM_1: c1 = 0; break;
- case NUM_TEAM_2: c2 = 0; break;
- case NUM_TEAM_3: c3 = 0; break;
- case NUM_TEAM_4: c4 = 0; break;
+ M_ARGV(0, float) |= Team_TeamToBit(tmp_entity.team);
}
}
// scoreboard setup
void ons_ScoreRules()
{
- 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);
+ entity balance = TeamBalance_CheckAllowedTeams(NULL);
+ int teams = TeamBalance_GetAllowedTeams(balance);
+ TeamBalance_Destroy(balance);
GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
field_team(ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
field(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
}
else
{
- if (autocvar_cl_ghost_items_color)
- {
- this.alpha = autocvar_cl_ghost_items;
- this.colormod = this.glowmod = autocvar_cl_ghost_items_color;
- }
- else
- this.alpha = -1;
+ this.alpha = autocvar_cl_ghost_items;
+ this.colormod = this.glowmod = autocvar_cl_ghost_items_color;
}
if((!veh_hud) && (this.ItemStatus & ITS_STAYWEP))
if(autocvar_g_pickup_items == 0)
return false;
if(g_weaponarena)
- if(this.weapons || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
+ if(STAT(WEAPONS, this) || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
return false;
}
return true;
}
- /*
- float Item_Customize()
- {
- if(this.spawnshieldtime)
- return true;
- if(this.weapons & ~other.weapons)
- {
- this.colormod = '0 0 0';
- this.glowmod = this.colormod;
- this.alpha = 0.5 + 0.5 * g_ghost_items; // halfway more alpha
- return true;
- }
- else
- {
- if(g_ghost_items)
- {
- this.colormod = stov(autocvar_g_ghost_items_color);
- this.glowmod = this.colormod;
- this.alpha = g_ghost_items;
- return true;
- }
- else
- return false;
- }
- }
- */
-
void Item_Show (entity e, float mode)
{
e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
}
else
{
- bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+ bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.m_wepset & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
|| e.team // weapon stay isn't supported for teamed weapons
;
if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM); // play respawn sound
setorigin(this, this.origin);
- if (Item_ItemsTime_Allow(this.itemdef) || (this.weapons & WEPSET_SUPERWEAPONS))
+ if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
{
float t = Item_ItemsTime_UpdateTime(this, 0);
Item_ItemsTime_SetTime(this, t);
void Item_ScheduleRespawnIn(entity e, float t)
{
// if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
- if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
+ if ((Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
{
setthink(e, Item_RespawnCountdown);
e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
e.item_respawncounter = 0;
- if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+ if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
{
t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
Item_ItemsTime_SetTime(e, t);
e.scheduledrespawntime = time + t;
e.wait = time + t;
- if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+ if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
{
t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
Item_ItemsTime_SetTime(e, t);
return normal_respawntime;
}
- CheckAllowedTeams(NULL);
- GetTeamCounts(NULL);
+ entity balance = TeamBalance_CheckAllowedTeams(NULL);
+ TeamBalance_GetTeamCounts(balance, NULL);
int players = 0;
- if (c1 != -1) players += c1;
- if (c2 != -1) players += c2;
- if (c3 != -1) players += c3;
- if (c4 != -1) players += c4;
-
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ if (TeamBalance_IsTeamAllowed(balance, i))
+ {
+ players += TeamBalance_GetNumberOfPlayers(balance, i);
+ }
+ }
+ TeamBalance_Destroy(balance);
+
if (players >= 2) {
return normal_respawntime * (r / (players + o) + l);
} else {
FOREACH(Weapons, it != WEP_Null,
{
// Finding a weapon which player doesn't have.
- if (!(receiver.weapons & it.m_wepset) && (it.netname == weapon))
+ if (!(STAT(WEAPONS, receiver) & it.m_wepset) && (it.netname == weapon))
{
RandomSelection_AddEnt(it, 1, 1);
break;
{
return;
}
- receiver.weapons |= RandomSelection_chosen_ent.m_wepset;
+ STAT(WEAPONS, receiver) |= RandomSelection_chosen_ent.m_wepset;
if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
{
continue;
if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
_switchweapon |= BIT(slot);
- if(!(player.weapons & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
+ if(!(STAT(WEAPONS, player) & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
_switchweapon |= BIT(slot);
}
}
if (item.itemdef.instanceOfWeaponPickup)
{
WepSet w;
- w = item.weapons;
- w &= ~player.weapons;
+ w = STAT(WEAPONS, item);
+ w &= ~STAT(WEAPONS, player);
if (w || (item.spawnshieldtime && item.pickup_anyway > 0))
{
{
WaypointSprite_Kill(this.waypointsprite_attached);
}
- if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+ if (this.itemdef.instanceOfPowerup || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
{
Item_ScheduleInitialRespawn(this);
}
float weapon_pickupevalfunc(entity player, entity item)
{
// See if I have it already
- if(player.weapons & item.weapons)
+ if(STAT(WEAPONS, player) & STAT(WEAPONS, item))
{
// If I can pick it up
if(!item.spawnshieldtime)
// reduce weapon value if bot already got a good arsenal
float c = 1;
int weapons_value = 0;
- FOREACH(Weapons, it != WEP_Null && (player.weapons & it.m_wepset), {
+ FOREACH(Weapons, it != WEP_Null && (STAT(WEAPONS, player) & it.m_wepset), {
weapons_value += it.bot_pickupbasevalue;
});
c -= bound(0, weapons_value / 20000, 1) * 0.5;
else
{
FOREACH(Weapons, it != WEP_Null, {
- if(!(player.weapons & (it.m_wepset)))
+ if(!(STAT(WEAPONS, player) & (it.m_wepset)))
continue;
switch(it.ammo_type)
}
if(weaponid)
- this.weapons = WepSet_FromWeapon(Weapons_from(weaponid));
+ STAT(WEAPONS, this) = WepSet_FromWeapon(Weapons_from(weaponid));
this.flags = FL_ITEM | itemflags;
IL_PUSH(g_items, this);
s = W_UndeprecateName(argv(j));
if(s == it.netname)
{
- this.weapons |= (it.m_wepset);
+ STAT(WEAPONS, this) |= (it.m_wepset);
if(this.spawnflags == 0 || this.spawnflags == 2)
it.wr_init(it);
break;
if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
- FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
+ FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
}
this.netname = strzone(this.netname);
//print(this.netname, "\n");
{
WepSet v0, v1;
WepSet s = WepSet_FromWeapon(Weapons_from(wpn));
- v0 = (e.weapons & s);
+ v0 = (STAT(WEAPONS, e) & s);
switch(op)
{
case OP_SET:
if(val > 0)
- e.weapons |= s;
+ STAT(WEAPONS, e) |= s;
else
- e.weapons &= ~s;
+ STAT(WEAPONS, e) &= ~s;
break;
case OP_MIN:
case OP_PLUS:
if(val > 0)
- e.weapons |= s;
+ STAT(WEAPONS, e) |= s;
break;
case OP_MAX:
if(val <= 0)
- e.weapons &= ~s;
+ STAT(WEAPONS, e) &= ~s;
break;
case OP_MINUS:
if(val > 0)
- e.weapons &= ~s;
+ STAT(WEAPONS, e) &= ~s;
break;
}
- v1 = (e.weapons & s);
+ v1 = (STAT(WEAPONS, e) & s);
return (v0 != v1);
}
FOREACH(Weapons, it != WEP_Null, {
POSTGIVE_WEAPON(e, it, SND_WEAPONPICKUP, SND_Null);
if(!(save_weapons & (it.m_wepset)))
- if(e.weapons & (it.m_wepset))
+ if(STAT(WEAPONS, e) & (it.m_wepset))
it.wr_init(it);
});
POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
if(e.superweapons_finished <= 0)
- if(e.weapons & WEPSET_SUPERWEAPONS)
+ if(STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
e.superweapons_finished = autocvar_g_balance_superweapons_time;
if(e.strength_finished <= 0)
{
.entity weaponentity = weaponentities[slot];
if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
- if(!(e.weapons & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
+ if(!(STAT(WEAPONS, e) & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
_switchweapon |= BIT(slot);
}
#include "../common/items/_mod.qh"
#include "../common/mutators/mutator/waypoints/all.qh"
+ #include "../common/mutators/mutator/instagib/sv_instagib.qh"
#include "../common/triggers/subs.qh"
#include "../common/triggers/triggers.qh"
#include "../lib/warpzone/server.qh"
+ #include <common/mutators/mutator/overkill/oknex.qh>
+
STATIC_METHOD(Client, Add, void(Client this, int _team))
{
ClientConnect(this);
void ClientData_Touch(entity e)
{
- CS(e).clientdata.SendFlags = 1;
+ entity cd = CS(e).clientdata;
+ if (cd) { cd.SendFlags = 1; }
// make it spectatable
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, { CS(it).clientdata.SendFlags = 1; });
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e,
+ {
+ entity cd = CS(it).clientdata;
+ if (cd) { cd.SendFlags = 1; }
+ });
}
void SetSpectatee(entity this, entity spectatee);
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;
+ Player_SetTeamIndex(this, -1);
+ this.frags = FRAGS_SPECTATOR;
PlayerScore_Clear(this); // clear scores when needed
}
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
if(!CS(this).just_joined)
- LogTeamchange(this.playerid, -1, 4);
+ LogTeamchange(this.playerid, -1, TEAM_CHANGE_SPECTATOR);
else
CS(this).just_joined = false;
}
this.revival_time = 0;
this.items = 0;
- this.weapons = '0 0 0';
+ STAT(WEAPONS, this) = '0 0 0';
this.drawonlytoclient = this;
this.viewloc = NULL;
accuracy_resend(this);
if (this.team < 0)
- JoinBestTeam(this, true);
+ TeamBalance_JoinBestTeam(this, true);
entity spot = SelectSpawnPoint(this, false);
if (!spot) {
this.ammo_fuel = warmup_start_ammo_fuel;
this.health = warmup_start_health;
this.armorvalue = warmup_start_armorvalue;
- this.weapons = WARMUP_START_WEAPONS;
+ STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
} else {
this.ammo_shells = start_ammo_shells;
this.ammo_nails = start_ammo_nails;
this.ammo_fuel = start_ammo_fuel;
this.health = start_health;
this.armorvalue = start_armorvalue;
- this.weapons = start_weapons;
+ STAT(WEAPONS, this) = start_weapons;
if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
{
GiveRandomWeapons(this, random_start_weapons_count,
PS(this).dual_weapons = '0 0 0';
- this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
+ this.superweapons_finished = (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
this.items = start_items;
{
if(this.killindicator_teamchange == -1)
{
- JoinBestTeam( this, true );
+ TeamBalance_JoinBestTeam(this, true);
}
else if(this.killindicator_teamchange == -2)
{
}
#endif
+string GetClientVersionMessage(entity this)
+{
+ if (CS(this).version_mismatch) {
+ if(CS(this).version < autocvar_gameversion) {
+ return strcat("This is Xonotic ", autocvar_g_xonoticversion,
+ "\n^3Your client version is outdated.\n\n\n### YOU WON'T BE ABLE TO PLAY ON THIS SERVER ###\n\n\nPlease update!!!^8");
+ } else {
+ return strcat("This is Xonotic ", autocvar_g_xonoticversion,
+ "\n^3This server is using an outdated Xonotic version.\n\n\n ### THIS SERVER IS INCOMPATIBLE AND THUS YOU CANNOT JOIN ###.^8");
+ }
+ } else {
+ return strcat("Welcome to Xonotic ", autocvar_g_xonoticversion);
+ }
+}
+
+string getwelcomemessage(entity this)
+{
+ MUTATOR_CALLHOOK(BuildMutatorsPrettyString, "");
+ string modifications = M_ARGV(0, string);
+
+ if(g_weaponarena)
+ {
+ if(g_weaponarena_random)
+ modifications = strcat(modifications, ", ", ftos(g_weaponarena_random), " of ", g_weaponarena_list, " Arena");
+ else
+ modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena");
+ }
+ else if(cvar("g_balance_blaster_weaponstartoverride") == 0)
+ modifications = strcat(modifications, ", No start weapons");
+ if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
+ modifications = strcat(modifications, ", Low gravity");
+ if(g_weapon_stay && !g_cts)
+ modifications = strcat(modifications, ", Weapons stay");
+ if(g_jetpack)
+ modifications = strcat(modifications, ", Jet pack");
+ if(autocvar_g_powerups == 0)
+ modifications = strcat(modifications, ", No powerups");
+ if(autocvar_g_powerups > 0)
+ modifications = strcat(modifications, ", Powerups");
+ modifications = substring(modifications, 2, strlen(modifications) - 2);
+
+ string versionmessage = GetClientVersionMessage(this);
+ string s = strcat(versionmessage, "^8\n^8\nmatch type is ^1", gamemode_name, "^8\n");
+
+ if(modifications != "")
+ s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
+
+ if(cache_lastmutatormsg != autocvar_g_mutatormsg)
+ {
+ strcpy(cache_lastmutatormsg, autocvar_g_mutatormsg);
+ strcpy(cache_mutatormsg, cache_lastmutatormsg);
+ }
+
+ if (cache_mutatormsg != "") {
+ s = strcat(s, "\n\n^8special gameplay tips: ^7", cache_mutatormsg);
+ }
+
+ string mutator_msg = "";
+ MUTATOR_CALLHOOK(BuildGameplayTipsString, mutator_msg);
+ mutator_msg = M_ARGV(0, string);
+
+ s = strcat(s, mutator_msg); // trust that the mutator will do proper formatting
+
+ string motd = autocvar_sv_motd;
+ if (motd != "") {
+ s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd));
+ }
+ return s;
+}
+
/**
=============
ClientConnect
int playerid_save = this.playerid;
this.playerid = 0; // silent
- JoinBestTeam(this, false); // if the team number is valid, keep it
+ TeamBalance_JoinBestTeam(this, false); // if the team number is valid, keep it
this.playerid = playerid_save;
if (autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0) {
if (autocvar_sv_eventlog)
GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", playername(this, false)));
- LogTeamchange(this.playerid, this.team, 1);
+ LogTeamchange(this.playerid, this.team, TEAM_CHANGE_CONNECT);
CS(this).just_joined = true; // stop spamming the eventlog with additional lines when the client connects
// notify about available teams
if (teamplay)
{
- CheckAllowedTeams(this);
- int t = 0;
- if (c1 >= 0) t |= BIT(0);
- if (c2 >= 0) t |= BIT(1);
- if (c3 >= 0) t |= BIT(2);
- if (c4 >= 0) t |= BIT(3);
+ entity balance = TeamBalance_CheckAllowedTeams(this);
+ int t = TeamBalance_GetAllowedTeams(balance);
+ TeamBalance_Destroy(balance);
stuffcmd(this, sprintf("set _teams_available %d\n", t));
}
else
Fire_ApplyDamage(this);
Fire_ApplyEffect(this);
- if (!autocvar_g_instagib)
+ if (!MUTATOR_IS_ENABLED(mutator_instagib))
{
if (this.items & ITEM_Strength.m_itemid)
{
}
if (this.items & IT_SUPERWEAPON)
{
- if (!(this.weapons & WEPSET_SUPERWEAPONS))
+ if (!(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
{
this.superweapons_finished = 0;
this.items = this.items - (this.items & IT_SUPERWEAPON);
if (time > this.superweapons_finished)
{
this.items = this.items - (this.items & IT_SUPERWEAPON);
- this.weapons &= ~WEPSET_SUPERWEAPONS;
+ STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
//Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_BROKEN, this.netname);
Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
}
}
}
- else if(this.weapons & WEPSET_SUPERWEAPONS)
+ else if(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)
{
if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS))
{
else
{
this.superweapons_finished = 0;
- this.weapons &= ~WEPSET_SUPERWEAPONS;
+ STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
}
}
else
this.invincible_finished = spectatee.invincible_finished;
this.superweapons_finished = spectatee.superweapons_finished;
STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
- this.weapons = spectatee.weapons;
+ STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
this.punchangle = spectatee.punchangle;
this.view_ofs = spectatee.view_ofs;
this.velocity = spectatee.velocity;
if(!this.team_selected)
if(autocvar_g_campaign || autocvar_g_balance_teams)
- JoinBestTeam(this, true);
+ TeamBalance_JoinBestTeam(this, true);
if(autocvar_g_campaign)
campaign_bots_may_start = 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);
+ {
+ //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);
this.team_selected = false;
if (CS(this).version_mismatch) return false;
if (!nJoinAllowed(this, this)) return false;
if (teamplay && lockteams) return false;
- if (ShowTeamSelection(this)) return false;
if (MUTATOR_CALLHOOK(ForbidSpawn, this)) return false;
+ if (ShowTeamSelection(this)) return false;
return true;
}
return true;
}
+ .bool would_spectate;
void ObserverThink(entity this)
{
if ( CS(this).impulse )
if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) {
this.flags &= ~FL_JUMPRELEASED;
this.flags |= FL_SPAWNING;
- } else if(PHYS_INPUT_BUTTON_ATCK(this) && !CS(this).version_mismatch) {
+ } else if(PHYS_INPUT_BUTTON_ATCK(this) && !CS(this).version_mismatch || this.would_spectate) {
this.flags &= ~FL_JUMPRELEASED;
if(SpectateNext(this)) {
TRANSMUTE(Spectator, this);
}
CS(this).impulse = 0;
} else if (PHYS_INPUT_BUTTON_ATCK2(this)) {
+ this.would_spectate = false;
this.flags &= ~FL_JUMPRELEASED;
TRANSMUTE(Observer, this);
PutClientInServer(this);
} else {
if(!SpectateUpdate(this))
- PutObserverInServer(this);
+ {
+ if(!SpectateNext(this))
+ {
+ PutObserverInServer(this);
+ this.would_spectate = true;
+ }
+ }
}
} else {
if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))) {
if (caller.ready) // toggle
{
caller.ready = false;
- bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
+ if(IS_PLAYER(caller) || caller.caplayer == 1)
+ bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
}
else
{
caller.ready = true;
- bprint(playername(caller, false), "^2 is ready\n");
+ if(IS_PLAYER(caller) || caller.caplayer == 1)
+ bprint(playername(caller, false), "^2 is ready\n");
}
// cannot reset the game while a timeout is active!
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)
+ entity balance = TeamBalance_CheckAllowedTeams(caller);
+ TeamBalance_GetTeamCounts(balance, caller);
+ if ((Team_IndexToBit(Team_TeamToIndex(selection)) &
+ TeamBalance_FindBestTeams(balance, caller, false)) == 0)
{
Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
+ TeamBalance_Destroy(balance);
return;
}
+ TeamBalance_Destroy(balance);
}
ClientKill_TeamChange(caller, selection);
if (!IS_PLAYER(caller))
void UpdateFrags(entity player, int f);
.float totalfrags;
-float team1_score, team2_score, team3_score, team4_score;
-
// flag set on worldspawn so that the code knows if it is dedicated or not
float server_is_dedicated;
// WEAPONTODO: remove this
//WepSet weaponsInMap;
- #define weapons _STAT(WEAPONS)
-
.float respawn_countdown; // next number to count
float bot_waypoints_for_items;
// WEAPONTODO
#define DMG_NOWEP (weaponentities[0])
-float lockteams;
-
float sv_maxidle;
float sv_maxidle_spectatorsareidle;
int sv_maxidle_slots;
.float vortex_charge;
.float vortex_charge_rottime;
.float vortex_chargepool_ammo;
+ .float oknex_charge;
+ .float oknex_charge_rottime;
+ .float oknex_chargepool_ammo;
.int hagar_load;
.int grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
// these can contain player IDs, so better hide
BADPREFIX("g_forced_team_");
BADCVAR("sv_muteban_list");
+ BADCVAR("sv_voteban_list");
BADCVAR("sv_allow_customplayermodels_idlist");
BADCVAR("sv_allow_customplayermodels_speciallist");
}
}
+void default_delayedinit(entity this)
+{
+ if(!scores_initialized)
+ ScoreRules_generic();
+}
+
+void InitGameplayMode()
+{
+ VoteReset();
+
+ // find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
+ get_mi_min_max(1);
+ // assign reflectively to avoid "assignment to world" warning
+ int done = 0; for (int i = 0, n = numentityfields(); i < n; ++i) {
+ string k = entityfieldname(i); vector v = (k == "mins") ? mi_min : (k == "maxs") ? mi_max : '0 0 0';
+ if (v) {
+ putentityfieldstring(i, world, sprintf("%v", v));
+ if (++done == 2) break;
+ }
+ }
+ // currently, NetRadiant's limit is 131072 qu for each side
+ // distance from one corner of a 131072qu cube to the opposite corner is approx. 227023 qu
+ // set the distance according to map size but don't go over the limit to avoid issues with float precision
+ // in case somebody makes extremely large maps
+ max_shot_distance = min(230000, vlen(world.maxs - world.mins));
+
+ MapInfo_LoadMapSettings(mapname);
+ GameRules_teams(false);
+
+ if (!cvar_value_issafe(world.fog))
+ {
+ LOG_INFO("The current map contains a potentially harmful fog setting, ignored");
+ world.fog = string_null;
+ }
+ if(MapInfo_Map_fog != "")
+ if(MapInfo_Map_fog == "none")
+ world.fog = string_null;
+ else
+ world.fog = strzone(MapInfo_Map_fog);
+ clientstuff = strzone(MapInfo_Map_clientstuff);
+
+ MapInfo_ClearTemps();
+
+ gamemode_name = MapInfo_Type_ToText(MapInfo_LoadedGametype);
+
+ cache_mutatormsg = strzone("");
+ cache_lastmutatormsg = strzone("");
+
+ InitializeEntity(NULL, default_delayedinit, INITPRIO_GAMETYPE_FALLBACK);
+}
+
void Map_MarkAsRecent(string m);
float world_already_spawned;
void Nagger_Init();
if(teamplay)
{
- team1_score = TeamScore_GetCompareValue(NUM_TEAM_1);
- team2_score = TeamScore_GetCompareValue(NUM_TEAM_2);
- team3_score = TeamScore_GetCompareValue(NUM_TEAM_3);
- team4_score = TeamScore_GetCompareValue(NUM_TEAM_4);
+ for (int i = 1; i < 5; ++i)
+ {
+ Team_SetTeamScore(Team_GetTeamFromIndex(i),
+ TeamScore_GetCompareValue(Team_IndexToTeam(i)));
+ }
}
ClearWinners();
if(!some_spawn_has_been_used)
return WINNING_NO;
- team1_score = team2_score = team3_score = team4_score = 0;
-
- FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
- switch(it.team)
+ for (int i = 1; i < 5; ++i)
+ {
+ Team_SetTeamScore(Team_GetTeamFromIndex(i), 0);
+ }
+
+ FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
+ {
+ if (Team_IsValidTeam(it.team))
{
- case NUM_TEAM_1: team1_score = 1; break;
- case NUM_TEAM_2: team2_score = 1; break;
- case NUM_TEAM_3: team3_score = 1; break;
- case NUM_TEAM_4: team4_score = 1; break;
+ Team_SetTeamScore(Team_GetTeam(it.team), 1);
}
});
IL_EACH(g_spawnpoints, true,
{
- switch(it.team)
+ if (Team_IsValidTeam(it.team))
{
- case NUM_TEAM_1: team1_score = 1; break;
- case NUM_TEAM_2: team2_score = 1; break;
- case NUM_TEAM_3: team3_score = 1; break;
- case NUM_TEAM_4: team4_score = 1; break;
+ Team_SetTeamScore(Team_GetTeam(it.team), 1);
}
});
ClearWinners();
+ float team1_score = Team_GetTeamScore(Team_GetTeamFromIndex(1));
+ float team2_score = Team_GetTeamScore(Team_GetTeamFromIndex(2));
+ float team3_score = Team_GetTeamScore(Team_GetTeamFromIndex(3));
+ float team4_score = Team_GetTeamScore(Team_GetTeamFromIndex(4));
if(team1_score + team2_score + team3_score + team4_score == 0)
{
checkrules_equality = true;
{
float t, i;
if(team1_score)
- t = NUM_TEAM_1;
+ t = 1;
else if(team2_score)
- t = NUM_TEAM_2;
+ t = 2;
else if(team3_score)
- t = NUM_TEAM_3;
+ t = 3;
else // if(team4_score)
- t = NUM_TEAM_4;
- CheckAllowedTeams(NULL);
+ t = 4;
+ entity balance = TeamBalance_CheckAllowedTeams(NULL);
for(i = 0; i < MAX_TEAMSCORE; ++i)
{
- if(t != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000);
- if(t != NUM_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(NUM_TEAM_2, i, -1000);
- if(t != NUM_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(NUM_TEAM_3, i, -1000);
- if(t != NUM_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(NUM_TEAM_4, i, -1000);
+ for (int j = 1; j <= NUM_TEAMS; ++j)
+ {
+ if (t == j)
+ {
+ continue;
+ }
+ if (!TeamBalance_IsTeamAllowed(balance, j))
+ {
+ continue;
+ }
+ TeamScore_AddToTeam(Team_IndexToTeam(j), i, -1000);
+ }
}
AddWinners(team, t);
/** called when the match ends */
MUTATOR_HOOKABLE(MatchEnd, EV_NO_ARGS);
-/** allows adjusting allowed teams */
-#define EV_CheckAllowedTeams(i, o) \
+/** Allows adjusting allowed teams. Return true to use the bitmask value and set
+ * non-empty string to use team entity name. Both behaviors can be active at the
+ * same time and will stack allowed teams.
+ */
+#define EV_TeamBalance_CheckAllowedTeams(i, o) \
/** mask of teams */ i(float, MUTATOR_ARGV_0_float) \
/**/ o(float, MUTATOR_ARGV_0_float) \
/** team entity name */ i(string, MUTATOR_ARGV_1_string) \
/**/ o(string, MUTATOR_ARGV_1_string) \
/** player checked */ i(entity, MUTATOR_ARGV_2_entity) \
/**/
-MUTATOR_HOOKABLE(CheckAllowedTeams, EV_CheckAllowedTeams);
+MUTATOR_HOOKABLE(TeamBalance_CheckAllowedTeams,
+ EV_TeamBalance_CheckAllowedTeams);
/** return true to manually override team counts */
-MUTATOR_HOOKABLE(GetTeamCounts, EV_NO_ARGS);
+MUTATOR_HOOKABLE(TeamBalance_GetTeamCounts, EV_NO_ARGS);
-/** allow overriding of team counts */
-#define EV_GetTeamCount(i, o) \
- /** team to count */ i(float, MUTATOR_ARGV_0_float) \
+/** allows overriding of team counts */
+#define EV_TeamBalance_GetTeamCount(i, o) \
+ /** team index to count */ i(float, MUTATOR_ARGV_0_float) \
/** player to ignore */ i(entity, MUTATOR_ARGV_1_entity) \
- /** number of players in a team */ i(float, MUTATOR_ARGV_2_float) \
- /**/ o(float, MUTATOR_ARGV_2_float) \
- /** number of bots in a team */ i(float, MUTATOR_ARGV_3_float) \
- /**/ o(float, MUTATOR_ARGV_3_float) \
- /** lowest scoring human in a team */ i(entity, MUTATOR_ARGV_4_entity) \
- /**/ o(entity, MUTATOR_ARGV_4_entity) \
- /** lowest scoring bot in a team */ i(entity, MUTATOR_ARGV_5_entity) \
- /**/ o(entity, MUTATOR_ARGV_5_entity) \
- /**/
-MUTATOR_HOOKABLE(GetTeamCount, EV_GetTeamCount);
-
-/** allows overriding best teams */
-#define EV_FindBestTeams(i, o) \
+ /** number of players in a team */ o(float, MUTATOR_ARGV_2_float) \
+ /** number of bots in a team */ o(float, MUTATOR_ARGV_3_float) \
+ /**/
+MUTATOR_HOOKABLE(TeamBalance_GetTeamCount, EV_TeamBalance_GetTeamCount);
+
+/** allows overriding the teams that will make the game most balanced if the
+ * player joins any of them.
+ */
+#define EV_TeamBalance_FindBestTeams(i, o) \
/** player checked */ i(entity, MUTATOR_ARGV_0_entity) \
/** bitmask of teams */ o(float, MUTATOR_ARGV_1_float) \
/**/
-MUTATOR_HOOKABLE(FindBestTeams, EV_FindBestTeams);
+MUTATOR_HOOKABLE(TeamBalance_FindBestTeams, EV_TeamBalance_FindBestTeams);
+
+/** Called during autobalance. Return true to override the player that will be
+switched. */
+#define EV_TeamBalance_GetPlayerForTeamSwitch(i, o) \
+ /** source team index */ i(int, MUTATOR_ARGV_0_int) \
+ /** destination team index */ i(int, MUTATOR_ARGV_1_int) \
+ /** is looking for bot */ i(bool, MUTATOR_ARGV_2_bool) \
+ /** player to switch */ o(entity, MUTATOR_ARGV_3_entity) \
+ /**/
+MUTATOR_HOOKABLE(TeamBalance_GetPlayerForTeamSwitch,
+ EV_TeamBalance_GetPlayerForTeamSwitch);
/** copies variables for spectating "spectatee" to "this" */
#define EV_SpectateCopy(i, o) \
MUTATOR_HOOKABLE(FilterItemDefinition, EV_FilterItemDefinition);
/**
- * checks if the current item may be spawned (.items and .weapons may be read and written to, as well as the ammo_ fields)
+ * checks if the current item may be spawned (.items may be read and written to, as well as the ammo_ fields)
* return error to request removal
*/
#define EV_FilterItem(i, o) \
/** mirrordamage */ i(float, MUTATOR_ARGV_5_float) \
/** mirrordamage */ o(float, MUTATOR_ARGV_5_float) \
/** force */ i(vector, MUTATOR_ARGV_6_vector) \
- /** force */ o(vector, MUTATOR_ARGV_6_vector) \
+ /** force */ o(vector, MUTATOR_ARGV_6_vector) \
+ /** weapon entity */ i(entity, MUTATOR_ARGV_7_entity) \
/**/
MUTATOR_HOOKABLE(Damage_Calculate, EV_Damage_Calculate);
* Called before player changes their team. Return true to block team change.
*/
#define EV_Player_ChangeTeam(i, o) \
- /** player */ i(entity, MUTATOR_ARGV_0_entity) \
- /** current team */ i(float, MUTATOR_ARGV_1_float) \
- /** new team */ i(float, MUTATOR_ARGV_2_float) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** current team index */ i(float, MUTATOR_ARGV_1_float) \
+ /** new team index */ i(float, MUTATOR_ARGV_2_float) \
/**/
MUTATOR_HOOKABLE(Player_ChangeTeam, EV_Player_ChangeTeam);
* Called after player has changed their team.
*/
#define EV_Player_ChangedTeam(i, o) \
- /** player */ i(entity, MUTATOR_ARGV_0_entity) \
- /** old team */ i(float, MUTATOR_ARGV_1_float) \
- /** current team */ i(float, MUTATOR_ARGV_2_float) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** old team index */ i(float, MUTATOR_ARGV_1_float) \
+ /** current team index */ i(float, MUTATOR_ARGV_2_float) \
/**/
MUTATOR_HOOKABLE(Player_ChangedTeam, EV_Player_ChangedTeam);
void CA_count_alive_players()
{
- total_players = redalive = bluealive = yellowalive = pinkalive = 0;
- FOREACH_CLIENT(IS_PLAYER(it), {
- switch(it.team)
+ total_players = 0;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ Team_SetNumberOfAlivePlayers(Team_GetTeamFromIndex(i), 0);
+ }
+ FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it),
+ {
+ ++total_players;
+ if (IS_DEAD(it))
{
- case NUM_TEAM_1: ++total_players; if(!IS_DEAD(it)) ++redalive; break;
- case NUM_TEAM_2: ++total_players; if(!IS_DEAD(it)) ++bluealive; break;
- case NUM_TEAM_3: ++total_players; if(!IS_DEAD(it)) ++yellowalive; break;
- case NUM_TEAM_4: ++total_players; if(!IS_DEAD(it)) ++pinkalive; break;
+ continue;
}
+ entity team_ = Entity_GetTeam(it);
+ int num_alive = Team_GetNumberOfAlivePlayers(team_);
+ ++num_alive;
+ Team_SetNumberOfAlivePlayers(team_, num_alive);
});
- FOREACH_CLIENT(IS_REAL_CLIENT(it), {
- STAT(REDALIVE, it) = redalive;
- STAT(BLUEALIVE, it) = bluealive;
- STAT(YELLOWALIVE, it) = yellowalive;
- STAT(PINKALIVE, it) = pinkalive;
+ FOREACH_CLIENT(IS_REAL_CLIENT(it),
+ {
+ STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(
+ 1));
+ STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(
+ Team_GetTeamFromIndex(2));
+ STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(
+ Team_GetTeamFromIndex(3));
+ STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(
+ Team_GetTeamFromIndex(4));
});
}
-float CA_GetWinnerTeam()
+int CA_GetWinnerTeam()
{
- float winner_team = 0;
- if(redalive >= 1)
- winner_team = NUM_TEAM_1;
- if(bluealive >= 1)
+ int winner_team = 0;
+ if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1)) >= 1)
{
- if(winner_team) return 0;
- winner_team = NUM_TEAM_2;
+ winner_team = NUM_TEAM_1;
}
- if(yellowalive >= 1)
+ for (int i = 2; i <= NUM_TEAMS; ++i)
{
- if(winner_team) return 0;
- winner_team = NUM_TEAM_3;
+ if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) >= 1)
+ {
+ if (winner_team != 0)
+ {
+ return 0;
+ }
+ winner_team = Team_IndexToTeam(i);
+ }
}
- if(pinkalive >= 1)
+ if (winner_team)
{
- if(winner_team) return 0;
- winner_team = NUM_TEAM_4;
- }
- if(winner_team)
return winner_team;
+ }
return -1; // no player left
}
void nades_Clear(entity player);
-#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
+#define CA_ALIVE_TEAMS_OK() (Team_GetNumberOfAliveTeams() == NumTeams(ca_teams))
float CA_CheckWinner()
{
if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
}
CA_count_alive_players();
- if(CA_ALIVE_TEAMS() > 1)
+ if (Team_GetNumberOfAliveTeams() > 1)
+ {
return 0;
+ }
int winner_team = CA_GetWinnerTeam();
if(winner_team > 0)
return false;
}
int missing_teams_mask = 0;
- if(ca_teams & BIT(0))
- missing_teams_mask += (!redalive) * 1;
- if(ca_teams & BIT(1))
- missing_teams_mask += (!bluealive) * 2;
- if(ca_teams & BIT(2))
- missing_teams_mask += (!yellowalive) * 4;
- if(ca_teams & BIT(3))
- missing_teams_mask += (!pinkalive) * 8;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ if ((ca_teams & Team_IndexToBit(i)) &&
+ (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) == 0))
+ {
+ missing_teams_mask |= Team_IndexToBit(i);
+ }
+ }
if(prev_missing_teams_mask != missing_teams_mask)
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
return true;
}
-MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ca, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(0, float) = ca_teams;
+ return true;
}
entity ca_LastPlayerForTeam(entity this)
if (!allowed_to_spawn)
{
frag_target.respawn_flags = RESPAWN_SILENT;
- // prevent unwanted sudden rejoin as spectator and move of spectator camera
+ // prevent unwanted sudden rejoin as spectator and movement of spectator camera
frag_target.respawn_time = time + 2;
}
+ frag_target.respawn_flags |= RESPAWN_FORCE;
if (!warmup_stage)
eliminatedPlayers.SendFlags |= 1;
if(IS_BOT_CLIENT(frag_target))
}
}
-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
- if (!SetPlayerTeamSimple(client, team_colour))
- {
- return false;
- }
- Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, DMG_NOWEP, 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 */
void dedicated_print(string input)
{
if (privatesay && source && !IS_PLAYER(source))
{
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)) && ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage)))
ret = -1; // just hide the message completely
}