#include "handicap.qh"
#include "g_hook.qh"
#include "command/common.qh"
+#include "command/vote.qh"
#include "cheats.qh"
#include "g_world.qh"
#include "race.qh"
#include <common/effects/qc/globalsound.qh>
-#include "../common/triggers/func/conveyor.qh"
-#include "../common/triggers/teleporters.qh"
-#include "../common/triggers/target/spawnpoint.qh"
+#include "../common/mapobjects/func/conveyor.qh"
+#include "../common/mapobjects/teleporters.qh"
+#include "../common/mapobjects/target/spawnpoint.qh"
#include "../common/vehicles/all.qh"
#include "../common/net_linked.qh"
#include "../common/physics/player.qh"
+#include <common/vehicles/sv_vehicles.qh>
+
#include "../common/items/_mod.qh"
#include "../common/mutators/mutator/waypoints/all.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
+#include <common/gamemodes/_mod.qh>
-#include "../common/triggers/subs.qh"
-#include "../common/triggers/triggers.qh"
-#include "../common/triggers/trigger/secret.qh"
+#include "../common/mapobjects/subs.qh"
+#include "../common/mapobjects/triggers.qh"
+#include "../common/mapobjects/trigger/secret.qh"
#include "../common/minigames/sv_minigames.qh"
#include "../lib/warpzone/server.qh"
+#include <common/mutators/mutator/overkill/oknex.qh>
+
STATIC_METHOD(Client, Add, void(Client this, int _team))
{
ClientConnect(this);
PutClientInServer(this);
}
-void PutObserverInServer(entity this);
-
STATIC_METHOD(Client, Remove, void(Client this))
{
TRANSMUTE(Observer, 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);
-void SetSpectatee_status(entity this, int spectatee_num);
-
/*
=============
UpdatePlayerSounds(e);
}
-void FixPlayermodel(entity player);
/** putting a client as observer in the server */
void PutObserverInServer(entity this)
{
this.revival_time = 0;
this.items = 0;
- this.weapons = '0 0 0';
+ STAT(WEAPONS, this) = '0 0 0';
this.drawonlytoclient = this;
this.viewloc = NULL;
this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
if (warmup_stage) {
- this.ammo_shells = warmup_start_ammo_shells;
- this.ammo_nails = warmup_start_ammo_nails;
- this.ammo_rockets = warmup_start_ammo_rockets;
- this.ammo_cells = warmup_start_ammo_cells;
- this.ammo_plasma = warmup_start_ammo_plasma;
- this.ammo_fuel = warmup_start_ammo_fuel;
+ SetResourceAmount(this, RESOURCE_SHELLS, warmup_start_ammo_shells);
+ SetResourceAmount(this, RESOURCE_BULLETS, warmup_start_ammo_nails);
+ SetResourceAmount(this, RESOURCE_ROCKETS, warmup_start_ammo_rockets);
+ SetResourceAmount(this, RESOURCE_CELLS, warmup_start_ammo_cells);
+ SetResourceAmount(this, RESOURCE_PLASMA, warmup_start_ammo_plasma);
+ SetResourceAmount(this, RESOURCE_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_rockets = start_ammo_rockets;
- this.ammo_cells = start_ammo_cells;
- this.ammo_plasma = start_ammo_plasma;
- this.ammo_fuel = start_ammo_fuel;
+ SetResourceAmount(this, RESOURCE_SHELLS, start_ammo_shells);
+ SetResourceAmount(this, RESOURCE_BULLETS, start_ammo_nails);
+ SetResourceAmount(this, RESOURCE_ROCKETS, start_ammo_rockets);
+ SetResourceAmount(this, RESOURCE_CELLS, start_ammo_cells);
+ SetResourceAmount(this, RESOURCE_PLASMA, start_ammo_plasma);
+ SetResourceAmount(this, RESOURCE_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;
}
}
-void ClientInit_misc(entity this);
-
// TODO do we need all these fields, or should we stop autodetecting runtime
// changes and just have a console command to update this?
bool ClientInit_SendEntity(entity this, entity to, int sf)
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) {
- TRANSMUTE(Observer, this);
- } else {
- if (!teamplay || autocvar_g_balance_teams) {
- TRANSMUTE(Player, this);
- campaign_bots_may_start = true;
- } else {
- TRANSMUTE(Observer, this); // do it anyway
- }
- }
+ TRANSMUTE(Observer, this);
PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
=============
*/
.entity chatbubbleentity;
-void ReadyCount();
void ClientDisconnect(entity this)
{
assert(IS_CLIENT(this), return);
PutClientInServer(this);
}
+void PrintToChat(entity client, string text)
+{
+ text = strcat("\{1}^7", text, "\n");
+ sprint(client, text);
+}
+
+void DebugPrintToChat(entity client, string text)
+{
+ if (autocvar_developer)
+ {
+ PrintToChat(client, text);
+ }
+}
+
+void PrintToChatAll(string text)
+{
+ text = strcat("\{1}^7", text, "\n");
+ bprint(text);
+}
+
+void DebugPrintToChatAll(string text)
+{
+ if (autocvar_developer)
+ {
+ PrintToChatAll(text);
+ }
+}
+
+void PrintToChatTeam(int team_num, string text)
+{
+ text = strcat("\{1}^7", text, "\n");
+ FOREACH_CLIENT(IS_REAL_CLIENT(it),
+ {
+ if (it.team == team_num)
+ {
+ sprint(it, text);
+ }
+ });
+}
+
+void DebugPrintToChatTeam(int team_num, string text)
+{
+ if (autocvar_developer)
+ {
+ PrintToChatTeam(team_num, text);
+ }
+}
+
void play_countdown(entity this, float finished, Sound samp)
{
TC(Sound, samp);
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
PS(this) = PS(spectatee);
this.armortype = spectatee.armortype;
this.armorvalue = spectatee.armorvalue;
- this.ammo_cells = spectatee.ammo_cells;
+ this.ammo_cells = spectatee.ammo_cells; // TODO: these will be a part of inventory, so no need to worry about setting them later!
this.ammo_plasma = spectatee.ammo_plasma;
this.ammo_shells = spectatee.ammo_shells;
this.ammo_nails = spectatee.ammo_nails;
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;
}
}
+const int MIN_SPEC_TIME = 1;
bool joinAllowed(entity this)
{
if (CS(this).version_mismatch) return false;
+ if (time < CS(this).jointime + MIN_SPEC_TIME) 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))) {
this.flags |= FL_CLIENT | FL_NOTARGET;
}
-void vehicles_enter (entity pl, entity veh);
void PlayerUseKey(entity this)
{
if (!IS_PLAYER(this))
PrintWelcomeMessage(this);
if (IS_PLAYER(this)) {
+ if (IS_REAL_CLIENT(this) && time < CS(this).jointime + MIN_SPEC_TIME)
+ error("Client can't be spawned as player on connection!");
if(!PlayerThink(this))
return;
}
IntermissionThink(this);
return;
}
+ else if (IS_REAL_CLIENT(this) && !CS(this).autojoin_checked && time >= CS(this).jointime + MIN_SPEC_TIME)
+ {
+ CS(this).autojoin_checked = true;
+ // 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)
+ && (!teamplay || autocvar_g_balance_teams)))
+ {
+ campaign_bots_may_start = true;
+ Join(this);
+ return;
+ }
+ }
else if (IS_OBSERVER(this)) {
ObserverThink(this);
}