#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;
}
this.angles_z = 0;
this.fixangle = true;
// offset it so that the spectator spawns higher off the ground, looks better this way
- setorigin(this, spot.origin + STAT(PL_VIEW_OFS, this));
+ setorigin(this, spot.origin + STAT(PL_VIEW_OFS, NULL));
this.prevorigin = this.origin;
if (IS_REAL_CLIENT(this))
{
// needed for player sounds
this.model = "";
FixPlayermodel(this);
- }
+ }
setmodel(this, MDL_Null);
- setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this));
+ 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)
this.drawonlytoclient = NULL;
this.crouch = false;
- this.view_ofs = STAT(PL_VIEW_OFS, this);
- setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
+ this.view_ofs = STAT(PL_VIEW_OFS, NULL);
+ setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
this.spawnorigin = spot.origin;
setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
// don't reset back to last position, even if new position is stuck in solid
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(this.killindicator_teamchange)
ClientKill_Now_TeamChange(this);
- if(IS_PLAYER(this))
+ if(!IS_SPEC(this) && !IS_OBSERVER(this))
Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0');
// now I am sure the player IS dead
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;
}
setorigin(it.killindicator, '0 0 52');
setthink(it.killindicator, KillIndicator_Think);
it.killindicator.nextthink = starttime + (it.lip) * 0.05;
- clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
+ //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
it.killindicator.cnt = ceil(killtime);
});
this.lip = 0;
if (!sv_foginterval && world.fog != "")
stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
- if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)))
+ if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2))
if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
send_CSQC_teamnagger();
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);
this.hud = spectatee.hud;
if(spectatee.vehicle)
{
- this.fixangle = false;
+ this.angles = spectatee.v_angle;
+
+ //this.fixangle = false;
//this.velocity = spectatee.vehicle.velocity;
this.vehicle_health = spectatee.vehicle_health;
this.vehicle_shield = spectatee.vehicle_shield;
this.vehicle_reload1 = spectatee.vehicle_reload1;
this.vehicle_reload2 = spectatee.vehicle_reload2;
- msg_entity = this;
+ //msg_entity = this;
- WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
- WriteAngle(MSG_ONE, spectatee.v_angle.x);
- WriteAngle(MSG_ONE, spectatee.v_angle.y);
- WriteAngle(MSG_ONE, spectatee.v_angle.z);
+ // WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+ //WriteAngle(MSG_ONE, spectatee.v_angle.x);
+ // WriteAngle(MSG_ONE, spectatee.v_angle.y);
+ // WriteAngle(MSG_ONE, spectatee.v_angle.z);
//WriteByte (MSG_ONE, SVC_SETVIEW);
// WriteEntity(MSG_ONE, this);
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) {
{
if(!it.team || SAME_TEAM(this, it))
Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER);
- }
- else if(autocvar_g_vehicles_steal)
- {
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
+ else if(autocvar_g_vehicles_steal)
+ Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
}
});
if (frametime) player_anim(this);
bool button_pressed = (PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this));
- if (this.deadflag == DEAD_DYING) {
- if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) {
- this.deadflag = DEAD_RESPAWNING;
- } else if (!button_pressed) {
- this.deadflag = DEAD_DEAD;
- }
- } else if (this.deadflag == DEAD_DEAD) {
- if (button_pressed) {
- this.deadflag = DEAD_RESPAWNABLE;
- } else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)) {
- this.deadflag = DEAD_RESPAWNING;
- }
- } else if (this.deadflag == DEAD_RESPAWNABLE) {
- if (!button_pressed) {
- this.deadflag = DEAD_RESPAWNING;
- }
- } else if (this.deadflag == DEAD_RESPAWNING) {
- if (time > this.respawn_time) {
- this.respawn_time = time + 1; // only retry once a second
- this.respawn_time_max = this.respawn_time;
- respawn(this);
+ switch(this.deadflag)
+ {
+ case DEAD_DYING:
+ {
+ if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
+ this.deadflag = DEAD_RESPAWNING;
+ else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+ this.deadflag = DEAD_DEAD;
+ break;
+ }
+ case DEAD_DEAD:
+ {
+ if (button_pressed)
+ this.deadflag = DEAD_RESPAWNABLE;
+ else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))
+ this.deadflag = DEAD_RESPAWNING;
+ break;
+ }
+ case DEAD_RESPAWNABLE:
+ {
+ if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+ this.deadflag = DEAD_RESPAWNING;
+ break;
+ }
+ case DEAD_RESPAWNING:
+ {
+ if (time > this.respawn_time)
+ {
+ this.respawn_time = time + 1; // only retry once a second
+ this.respawn_time_max = this.respawn_time;
+ respawn(this);
+ }
+ break;
}
}
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))