#include "campaign.qh"
#include "command/common.qh"
-#include "bot/bot.qh"
-#include "bot/navigation.qh"
+#include "bot/api.qh"
#include "../common/ent_cs.qh"
#include <common/state.qh>
WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
}
+int CountSpectators(entity player, entity to)
+{
+ if(!player) { return 0; } // not sure how, but best to be safe
+
+ int spec_count = 0;
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ spec_count++;
+ });
+
+ return spec_count;
+}
+
+void WriteSpectators(entity player, entity to)
+{
+ if(!player) { return; } // not sure how, but best to be safe
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ WriteByte(MSG_ENTITY, num_for_edict(it));
+ });
+}
+
bool ClientData_Send(entity this, entity to, int sf)
{
assert(to == this.owner, return false);
if (to.spectatee_status) sf |= 2; // spectator ent number follows
if (e.zoomstate) sf |= 4; // zoomed
if (e.porto_v_angle_held) sf |= 8; // angles held
+ if (autocvar_sv_showspectators) sf |= 16; // show spectators
WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
WriteByte(MSG_ENTITY, sf);
WriteAngle(MSG_ENTITY, e.v_angle.x);
WriteAngle(MSG_ENTITY, e.v_angle.y);
}
+
+ if(sf & 16)
+ {
+ float specs = CountSpectators(e, to);
+ WriteByte(MSG_ENTITY, specs);
+ WriteSpectators(e, to);
+ }
+
return true;
}
void ClientData_Detach(entity this)
{
- remove(this.clientdata);
+ delete(this.clientdata);
this.clientdata = NULL;
}
// needed for player sounds
this.model = "";
FixPlayermodel(this);
- }
+ }
setmodel(this, MDL_Null);
setsize(this, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL));
this.view_ofs = '0 0 0';
RemoveGrapplingHook(this);
Portal_ClearAll(this);
Unfreeze(this);
+ SetSpectatee(this, NULL);
if (this.alivetime)
{
this.health = FRAGS_SPECTATOR;
this.takedamage = DAMAGE_NO;
this.solid = SOLID_NOT;
- this.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink
+ set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
this.flags = FL_CLIENT | FL_NOTARGET;
this.armorvalue = 666;
this.effects = 0;
this.oldvelocity = this.velocity;
this.fire_endtime = -1;
this.event_damage = func_null;
+
+ STAT(ACTIVEWEAPON, this) = WEP_Null.m_id;
+ STAT(SWITCHINGWEAPON, this) = WEP_Null.m_id;
+ STAT(SWITCHWEAPON, this) = WEP_Null.m_id;
}
int player_getspecies(entity this)
if (IS_OBSERVER(this)) {
PutObserverInServer(this);
} else if (IS_PLAYER(this)) {
+ if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
+
PlayerState_attach(this);
accuracy_resend(this);
this.iscreature = true;
this.teleportable = TELEPORT_NORMAL;
this.damagedbycontents = true;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
this.solid = SOLID_SLIDEBOX;
this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
if (autocvar_g_playerclip_collisions)
if (autocvar_spawn_debug)
{
sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
- remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
+ delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
}
PS(this).m_switchweapon = w_getbestweapon(this);
}
if(this.killindicator && !wasfreed(this.killindicator))
- remove(this.killindicator);
+ delete(this.killindicator);
this.killindicator = NULL;
if (gameover)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
if (this.owner.alpha < 0 && !this.owner.vehicle)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
+ SetSpectatee(this, NULL);
+
MUTATOR_CALLHOOK(ClientDisconnect, this);
ClientState_detach(this);
this.flags &= ~FL_CLIENT;
- if (this.chatbubbleentity) remove(this.chatbubbleentity);
- if (this.killindicator) remove(this.killindicator);
+ if (this.chatbubbleentity) delete(this.chatbubbleentity);
+ if (this.killindicator) delete(this.killindicator);
WaypointSprite_PlayerGone(this);
if (this.netname_previous) strunzone(this.netname_previous);
if (this.clientstatus) strunzone(this.clientstatus);
if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
- if (this.personal) remove(this.personal);
+ if (this.personal) delete(this.personal);
this.playerid = 0;
ReadyCount();
{
if(this.owner) // but why can that ever be NULL?
this.owner.chatbubbleentity = NULL;
- remove(this);
+ delete(this);
return;
}
{
this.solid = SOLID_NOT;
this.takedamage = DAMAGE_NO;
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
this.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed;
this.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3;
this.effects |= CSQCMODEL_EF_RESPAWNGHOST;
this.angles = spectatee.v_angle;
STAT(FROZEN, this) = STAT(FROZEN, spectatee);
this.revive_progress = spectatee.revive_progress;
- if(!PHYS_INPUT_BUTTON_USE(this))
+ if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
this.fixangle = true;
setorigin(this, spectatee.origin);
setsize(this, spectatee.mins, spectatee.maxs);
if(!IS_PLAYER(this.enemy))
return false;
+ ClientData_Touch(this.enemy);
+
msg_entity = this;
WriteByte(MSG_ONE, SVC_SETVIEW);
WriteEntity(MSG_ONE, this.enemy);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
accuracy_resend(this);
if(!SpectateUpdate(this))
// WEAPONTODO
// these are required to fix the spectator bug with arc
- if(old_spectatee && old_spectatee.arc_beam) { old_spectatee.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
- if(this.enemy && this.enemy.arc_beam) { this.enemy.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
+ if(old_spectatee)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(old_spectatee.(weaponentity).arc_beam)
+ old_spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+ }
+ }
+ if(this.enemy)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(this.enemy.(weaponentity).arc_beam)
+ this.enemy.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+ }
+ }
+
+ // needed to update spectator list
+ if(old_spectatee) { ClientData_Touch(old_spectatee); }
}
bool Spectate(entity this, entity pl)
{
TRANSMUTE(Player, this);
+ SetSpectatee(this, NULL);
+
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(this, false, true); }
MinigameImpulse(this, this.impulse);
this.impulse = 0;
}
- float prefered_movetype;
if (this.flags & FL_JUMPRELEASED) {
if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
this.flags &= ~FL_JUMPRELEASED;
TRANSMUTE(Spectator, this);
}
} else {
- prefered_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
- if (this.movetype != prefered_movetype)
- this.movetype = prefered_movetype;
+ int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+ set_movetype(this, preferred_movetype);
}
} else {
if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))) {
{
if(MinigameImpulse(this, this.impulse))
this.impulse = 0;
+
+ if (this.impulse == IMP_weapon_drop.impulse)
+ {
+ STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3;
+ this.impulse = 0;
+ return;
+ }
}
if (this.flags & FL_JUMPRELEASED) {
if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
this.prevorigin = this.origin;
bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
if (this.hook.state) {
do_crouch = false;
+ } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+ do_crouch = false;
} else if (this.vehicle) {
do_crouch = false;
} else if (STAT(FROZEN, this)) {
do_crouch = false;
- } else if ((PS(this).m_weapon == WEP_SHOTGUN || PS(this).m_weapon == WEP_SHOCKWAVE) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) {
- // WEAPONTODO: predict
- do_crouch = false;
}
if (do_crouch) {
{
this.items &= ~this.items_added;
- W_WeaponFrame(this);
+ //for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ //{
+ //.entity weaponentity = weaponentities[slot];
+ //W_WeaponFrame(this, weaponentity);
+ //}
+ .entity weaponentity = weaponentities[0]; // TODO
+ W_WeaponFrame(this, weaponentity);
this.items_added = 0;
if (this.items & ITEM_Jetpack.m_itemid && (this.items & ITEM_JetpackRegen.m_itemid || this.ammo_fuel >= 0.01))
entity e = this.teamkill_soundsource;
entity oldpusher = e.pusher;
e.pusher = this;
- PlayerSound(e, playersound_teamshoot, CH_VOICE, VOICETYPE_LASTATTACKER_ONLY);
+ PlayerSound(e, playersound_teamshoot, CH_VOICE, VOL_BASEVOICE, VOICETYPE_LASTATTACKER_ONLY);
e.pusher = oldpusher;
}
if (this.taunt_soundtime && time > this.taunt_soundtime) {
this.taunt_soundtime = 0;
- PlayerSound(this, playersound_taunt, CH_VOICE, VOICETYPE_AUTOTAUNT);
+ PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT);
}
target_voicescript_next(this);
if (this.waterlevel != WATERLEVEL_SUBMERGED || this.vehicle)
{
if(this.air_finished < time)
- PlayerSound(this, playersound_gasp, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+ PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
this.air_finished = time + autocvar_g_balance_contents_drowndelay;
this.dmg = 2;
}
}
}
+.bool move_qcphysics;
+
+void Player_Physics(entity this)
+{
+ set_movetype(this, ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype));
+
+ if(!this.move_qcphysics)
+ return;
+
+ int mt = this.move_movetype;
+
+ if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
+ {
+ this.move_qcphysics = false;
+ set_movetype(this, mt);
+ return;
+ }
+
+ if(!frametime && !this.pm_frametime)
+ return;
+
+ Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true);
+
+ this.pm_frametime = 0;
+}
+
/*
=============
PlayerPostThink
.float idlekick_lasttimeleft;
void PlayerPostThink (entity this)
{
+ Player_Physics(this);
+
if (sv_maxidle > 0)
if (frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
if (IS_REAL_CLIENT(this))