Networking improvements. Make player entities and NPC networking

conditional. Only changed fields are networked. This is because the overall
design seems mature enough.
This commit is contained in:
Marco Cawthorne 2019-09-07 21:01:05 +02:00
parent 31750420be
commit 44479cd637
12 changed files with 708 additions and 277 deletions

View file

@ -99,7 +99,6 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
/* Game specific inits */
HUD_Init();
Scores_Init();
Client_Init(apilevel, enginename, engineversion);
DSP_Init();
@ -210,6 +209,10 @@ CSQC_UpdateView(float w, float h, float focus)
} else {
setsensitivityscaler(pl.viewzoom);
}
if (pl.viewzoom <= 0.0f) {
setsensitivityscaler(1.0f);
}
pl.viewzoom = oldzoom;

View file

@ -17,7 +17,6 @@
class monster_npc
{
int body;
int inited;
float frame_last;
virtual float() predraw;
@ -26,12 +25,6 @@ class monster_npc
float
monster_npc::predraw(void)
{
/* Only do this once whenever the ent pops into view */
if (!inited) {
setcustomskin(this, "", sprintf("geomset 1 %i\n", body));
inited = TRUE;
}
if (lerpfrac > 0) {
lerpfrac -= frametime * 5;
if (lerpfrac < 0) {
@ -58,28 +51,50 @@ monster_npc::predraw(void)
void
NPC_ReadEntity(float new)
{
float fl;
monster_npc pl = (monster_npc)self;
if (new == TRUE) {
if (new) {
spawnfunc_monster_npc();
pl.classname = "npc";
pl.solid = SOLID_SLIDEBOX;
pl.movetype = MOVETYPE_NONE;
pl.drawmask = MASK_ENGINE;
pl.customphysics = Empty;
setsize( pl, VEC_HULL_MIN, VEC_HULL_MAX );
setsize(pl, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
}
/* TODO: make these conditional */
pl.modelindex = readshort();
pl.origin[0] = readcoord();
pl.origin[1] = readcoord();
pl.origin[2] = readcoord();
pl.angles[1] = readfloat();
pl.angles[2] = readfloat();
pl.velocity[0] = readcoord();
pl.velocity[1] = readcoord();
pl.velocity[2] = readcoord();
pl.frame = readbyte();
pl.skin = readbyte();
pl.body = readbyte();
fl = readshort();
if (fl & NPC_MODELINDEX)
pl.modelindex = readshort();
if (fl & NPC_ORIGIN_X)
pl.origin[0] = readcoord();
if (fl & NPC_ORIGIN_Y)
pl.origin[1] = readcoord();
if (fl & NPC_ORIGIN_Z)
pl.origin[2] = readcoord();
if (fl & NPC_ANGLES_X)
pl.angles[0] = readfloat();
if (fl & NPC_ANGLES_Y)
pl.angles[1] = readfloat();
if (fl & NPC_ANGLES_Z)
pl.angles[2] = readfloat();
if (fl & NPC_VELOCITY_X)
pl.velocity[0] = readcoord();
if (fl & NPC_VELOCITY_Y)
pl.velocity[1] = readcoord();
if (fl & NPC_VELOCITY_Z)
pl.velocity[2] = readcoord();
if (fl & NPC_FRAME)
pl.frame = readbyte();
if (fl & NPC_SKIN)
pl.skin = readbyte();
if (fl & NPC_BODY)
pl.body = readbyte();
if (new) {
setcustomskin(pl, "", sprintf("geomset 1 %i\n", pl.body));
}
}

View file

@ -14,29 +14,19 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//FOR DEBUGGING ONLY, remove when prediction is trusted (along with the extra network bloat).
static void warnifdiff(string name, __inout float expected, float got)
{
//this should only fire from prediction misses.
//this hopefully only happens when the server's anti-time-banking logic does its thing, or for things caused by other players/ents getting in the way.
//if (expected != got)
//print(sprintf("%s differs, expected %g, got %g\n", name, expected, got));
//enable the following line if you want to see if it actually makes a difference.
//expected = got;
}
void Player_ReadEntity(float flIsNew)
void
Player_ReadEntity(float new)
{
float fl;
player pl = (player)self;
if ( flIsNew == TRUE ) {
if (new == TRUE) {
spawnfunc_player();
pl.classname = "player";
pl.solid = SOLID_SLIDEBOX;
pl.drawmask = MASK_ENGINE;
pl.customphysics = Empty;
setsize( pl, VEC_HULL_MIN, VEC_HULL_MAX );
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
} else {
int i;
//FIXME: splitscreen
@ -56,36 +46,58 @@ void Player_ReadEntity(float flIsNew)
}
}
pl.sequence = servercommandframe;
pl.modelindex = readshort(); // TODO: make conditional
pl.origin[0] = readcoord();
pl.origin[1] = readcoord();
pl.origin[2] = readcoord(); // TODO: make conditional
pl.pitch = readfloat();
pl.angles[1] = readfloat();
pl.angles[2] = readfloat();
pl.velocity[0] = readcoord();
pl.velocity[1] = readcoord();
pl.velocity[2] = readcoord();
pl.flags = readfloat(); //make mostly conditional
pl.activeweapon = readbyte(); // TODO: make conditional
warnifdiff("weapontime", pl.weapontime, readfloat()); //remove
pl.g_items = readfloat(); // TODO: make conditional
pl.health = readbyte(); // TODO: make conditional
pl.armor = readbyte(); // TODO: make conditional
pl.movetype = readbyte(); // TODO: make conditional
pl.view_ofs[2] = readfloat(); // TODO: make conditional
pl.viewzoom = readfloat(); //remove? or make conditional
warnifdiff("jumptime", pl.jumptime, readfloat()); //remove
warnifdiff("teletime", pl.teleport_time, readfloat()); //remove
pl.baseframe = readbyte(); // TODO: make conditional
pl.frame = readbyte(); // TODO: make conditional
pl.sequence = servercommandframe;
pl.a_ammo1 = readbyte(); // TODO: make conditional
pl.a_ammo2 = readbyte(); // TODO: make conditional
pl.a_ammo3 = readbyte(); // TODO: make conditional
warnifdiff("attack_next", pl.w_attack_next, readfloat()); //remove
warnifdiff("idle_next", pl.w_idle_next, readfloat()); //remove
setorigin( pl, pl.origin );
fl = readfloat();
if (fl & PLAYER_MODELINDEX)
pl.modelindex = readshort();
if (fl & PLAYER_ORIGIN) {
pl.origin[0] = readcoord();
pl.origin[1] = readcoord();
}
if (fl & PLAYER_ORIGIN_Z)
pl.origin[2] = readcoord();
if (fl & PLAYER_ANGLES_X)
pl.pitch = readfloat();
if (fl & PLAYER_ANGLES_Y)
pl.angles[1] = readfloat();
if (fl & PLAYER_ANGLES_Z)
pl.angles[2] = readfloat();
if (fl & PLAYER_VELOCITY) {
pl.velocity[0] = readcoord();
pl.velocity[1] = readcoord();
}
if (fl & PLAYER_VELOCITY_Z)
pl.velocity[2] = readcoord();
if (fl & PLAYER_FLAGS)
pl.flags = readfloat();
if (fl & PLAYER_WEAPON)
pl.activeweapon = readbyte();
if (fl & PLAYER_ITEMS)
pl.g_items = readfloat();
if (fl & PLAYER_HEALTH)
pl.health = readbyte();
if (fl & PLAYER_ARMOR)
pl.armor = readbyte();
if (fl & PLAYER_MOVETYPE)
pl.movetype = readbyte();
if (fl & PLAYER_VIEWOFS)
pl.view_ofs[2] = readfloat();
if (fl & PLAYER_BASEFRAME)
pl.baseframe = readbyte();
if (fl & PLAYER_FRAME)
pl.frame = readbyte();
if (fl & PLAYER_AMMO1)
pl.a_ammo1 = readbyte();
if (fl & PLAYER_AMMO2)
pl.a_ammo2 = readbyte();
if (fl & PLAYER_AMMO3)
pl.a_ammo3 = readbyte();
setorigin(pl, pl.origin);
}

View file

@ -24,23 +24,24 @@ class item_suit:CBaseTrigger
void item_suit::touch(void)
{
if (other.classname == "player") {
player pl = (player)other;
/*if (pl.g_items & ITEM_SUIT) {
return;
}*/
sound(other, CHAN_ITEM, "items/tr_kevlar.wav", 1, ATTN_NORM);
/*pl.g_items |= ITEM_SUIT;*/
if (other.classname != "player") {
return;
}
player pl = (player)other;
/*if (pl.g_items & ITEM_SUIT) {
return;
}*/
sound(other, CHAN_ITEM, "items/tr_kevlar.wav", 1, ATTN_NORM);
/*pl.g_items |= ITEM_SUIT;*/
CBaseTrigger::UseTargets();
CBaseTrigger::UseTargets();
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 30.0f;
}
}
@ -54,7 +55,6 @@ void item_suit::Respawn(void)
think = __NULL__;
nextthink = -1;
sound(this, CHAN_ITEM, "items/suitchargeok1.wav", 1, ATTN_NORM, 150);
}
void item_suit::item_suit(void)

View file

@ -55,8 +55,70 @@ void Game_PlayerPreThink(void)
}
void Game_PlayerPostThink(void)
{
player pl = (player)self;
Animation_PlayerUpdate();
self.SendFlags = 1;
if (pl.old_modelindex != pl.modelindex)
pl.SendFlags |= PLAYER_MODELINDEX;
if (pl.old_origin[0] != pl.origin[0])
pl.SendFlags |= PLAYER_ORIGIN;
if (pl.old_origin[1] != pl.origin[1])
pl.SendFlags |= PLAYER_ORIGIN;
if (pl.old_origin[2] != pl.origin[2])
pl.SendFlags |= PLAYER_ORIGIN_Z;
if (pl.old_angles[0] != pl.angles[0])
pl.SendFlags |= PLAYER_ANGLES_X;
if (pl.old_angles[1] != pl.angles[1])
pl.SendFlags |= PLAYER_ANGLES_Y;
if (pl.old_angles[2] != pl.angles[2])
pl.SendFlags |= PLAYER_ANGLES_Z;
if (pl.old_velocity[0] != pl.velocity[0])
pl.SendFlags |= PLAYER_VELOCITY;
if (pl.old_velocity[1] != pl.velocity[1])
pl.SendFlags |= PLAYER_VELOCITY;
if (pl.old_velocity[2] != pl.velocity[2])
pl.SendFlags |= PLAYER_VELOCITY_Z;
if (pl.old_flags != pl.flags)
pl.SendFlags |= PLAYER_FLAGS;
if (pl.old_activeweapon != pl.activeweapon)
pl.SendFlags |= PLAYER_WEAPON;
if (pl.old_items != pl.g_items)
pl.SendFlags |= PLAYER_ITEMS;
if (pl.old_health != pl.health)
pl.SendFlags |= PLAYER_HEALTH;
if (pl.old_armor != pl.armor)
pl.SendFlags |= PLAYER_ARMOR;
if (pl.old_movetype != pl.movetype)
pl.SendFlags |= PLAYER_MOVETYPE;
if (pl.old_viewofs != pl.view_ofs[2])
pl.SendFlags |= PLAYER_VIEWOFS;
if (pl.old_baseframe != pl.baseframe)
pl.SendFlags |= PLAYER_BASEFRAME;
if (pl.old_frame != pl.frame)
pl.SendFlags |= PLAYER_FRAME;
if (pl.old_a_ammo1 != pl.a_ammo1)
pl.SendFlags |= PLAYER_AMMO1;
if (pl.old_a_ammo2 != pl.a_ammo2)
pl.SendFlags |= PLAYER_AMMO2;
if (pl.old_a_ammo3 != pl.a_ammo3)
pl.SendFlags |= PLAYER_AMMO3;
pl.old_modelindex = pl.modelindex;
pl.old_origin = pl.origin;
pl.old_angles = pl.angles;
pl.old_velocity = pl.velocity;
pl.old_flags = pl.flags;
pl.old_activeweapon = pl.activeweapon;
pl.old_items = pl.g_items;
pl.old_health = pl.health;
pl.old_armor = pl.armor;
pl.old_movetype = pl.movetype;
pl.old_viewofs = pl.view_ofs[2];
pl.old_baseframe = pl.baseframe;
pl.old_frame = pl.frame;
pl.old_a_ammo1 = pl.a_ammo1;
pl.old_a_ammo2 = pl.a_ammo2;
pl.old_a_ammo3 = pl.a_ammo3;
}
void Game_RunClientCommand(void)
{
@ -106,7 +168,6 @@ void Game_PutClientInServer(void)
pl.classname = "player";
pl.health = self.max_health = 100;
//forceinfokey(self, "*dead", "0");
pl.takedamage = DAMAGE_YES;
pl.solid = SOLID_SLIDEBOX;
pl.movetype = MOVETYPE_WALK;
@ -115,19 +176,40 @@ void Game_PutClientInServer(void)
pl.model = "models/player.mdl";
string mymodel = infokey(pl, "model");
if (mymodel) {
mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel);
if (whichpack(mymodel)) {
pl.model = mymodel;
}
}
setmodel(pl, pl.model);
if (mymodel) {
mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel);
if (whichpack(mymodel)) {
pl.model = mymodel;
}
}
setmodel(pl, pl.model);
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
pl.view_ofs = VEC_PLAYER_VIEWPOS;
pl.velocity = [0,0,0];
pl.frame = 1;
pl.SendEntity = Player_SendEntity;
pl.SendFlags = PLAYER_MODELINDEX |
PLAYER_ORIGIN |
PLAYER_ORIGIN_Z |
PLAYER_ANGLES_X |
PLAYER_ANGLES_Y |
PLAYER_ANGLES_Z |
PLAYER_VELOCITY |
PLAYER_VELOCITY_Z |
PLAYER_FLAGS |
PLAYER_WEAPON |
PLAYER_ITEMS |
PLAYER_HEALTH |
PLAYER_ARMOR |
PLAYER_MOVETYPE |
PLAYER_VIEWOFS |
PLAYER_BASEFRAME |
PLAYER_FRAME |
PLAYER_AMMO1 |
PLAYER_AMMO2 |
PLAYER_AMMO3;
pl.customphysics = Empty;
pl.vPain = Player_Pain;
pl.vDeath = Player_Death;

View file

@ -301,7 +301,7 @@ string sci_sndidle[] = {
class monster_scientist:CBaseEntity
{
int m_iBody;
int body;
vector m_vecLastUserPos;
entity m_eUser;
entity m_eRescuer;
@ -313,6 +313,15 @@ class monster_scientist:CBaseEntity
float m_flTraceTime;
float m_flPitch;
int m_iFlags;
int old_modelindex;
vector old_origin;
vector old_angles;
vector old_velocity;
int old_frame;
int old_skin;
int old_body;
void() monster_scientist;
virtual void() touch;
@ -337,18 +346,35 @@ float monster_scientist::SendEntity(entity ePEnt, float fChanged)
}
WriteByte(MSG_ENTITY, ENT_NPC);
WriteShort(MSG_ENTITY, modelindex);
WriteCoord(MSG_ENTITY, origin[0]);
WriteCoord(MSG_ENTITY, origin[1]);
WriteCoord(MSG_ENTITY, origin[2]);
WriteFloat(MSG_ENTITY, angles[1]);
WriteFloat(MSG_ENTITY, angles[2]);
WriteCoord(MSG_ENTITY, velocity[0]);
WriteCoord(MSG_ENTITY, velocity[1]);
WriteCoord(MSG_ENTITY, velocity[2]);
WriteByte(MSG_ENTITY, frame);
WriteByte(MSG_ENTITY, skin);
WriteByte(MSG_ENTITY, m_iBody);
WriteShort(MSG_ENTITY, fChanged);
if (fChanged & NPC_MODELINDEX)
WriteShort(MSG_ENTITY, modelindex);
if (fChanged & NPC_ORIGIN_X)
WriteCoord(MSG_ENTITY, origin[0]);
if (fChanged & NPC_ORIGIN_Y)
WriteCoord(MSG_ENTITY, origin[1]);
if (fChanged & NPC_ORIGIN_Z)
WriteCoord(MSG_ENTITY, origin[2]);
if (fChanged & NPC_ANGLES_X)
WriteFloat(MSG_ENTITY, angles[0]);
if (fChanged & NPC_ANGLES_Y)
WriteFloat(MSG_ENTITY, angles[1]);
if (fChanged & NPC_ANGLES_Z)
WriteFloat(MSG_ENTITY, angles[2]);
if (fChanged & NPC_VELOCITY_X)
WriteCoord(MSG_ENTITY, velocity[0]);
if (fChanged & NPC_VELOCITY_Y)
WriteCoord(MSG_ENTITY, velocity[1]);
if (fChanged & NPC_VELOCITY_Z)
WriteCoord(MSG_ENTITY, velocity[2]);
if (fChanged & NPC_FRAME)
WriteByte(MSG_ENTITY, frame);
if (fChanged & NPC_SKIN)
WriteByte(MSG_ENTITY, skin);
if (fChanged & NPC_BODY)
WriteByte(MSG_ENTITY, body);
return TRUE;
}
@ -546,7 +572,41 @@ void monster_scientist::Physics(void)
runstandardplayerphysics(this);
Footsteps_Update();
SendFlags = 1;
if (modelindex != old_modelindex)
SendFlags |= NPC_MODELINDEX;
if (origin[0] != old_origin[0])
SendFlags |= NPC_ORIGIN_X;
if (origin[1] != old_origin[1])
SendFlags |= NPC_ORIGIN_Y;
if (origin[2] != old_origin[2])
SendFlags |= NPC_ORIGIN_Z;
if (angles[0] != old_angles[0])
SendFlags |= NPC_ANGLES_X;
if (angles[1] != old_angles[1])
SendFlags |= NPC_ANGLES_Y;
if (angles[2] != old_angles[2])
SendFlags |= NPC_ANGLES_Z;
if (velocity[0] != old_velocity[0])
SendFlags |= NPC_VELOCITY_X;
if (velocity[1] != old_velocity[1])
SendFlags |= NPC_VELOCITY_Y;
if (velocity[2] != old_velocity[2])
SendFlags |= NPC_VELOCITY_Z;
if (frame != old_frame)
SendFlags |= NPC_FRAME;
if (skin != old_skin)
SendFlags |= NPC_SKIN;
if (body != old_body)
SendFlags |= NPC_BODY;
old_modelindex = modelindex;
old_origin = origin;
old_angles = angles,
old_velocity = velocity,
old_frame = frame;
old_skin = skin;
old_body = body;
if (!(flags & FL_ONGROUND) && velocity[2] < -100) {
if (!(m_iFlags & SCIF_FALLING)) {
@ -624,7 +684,7 @@ void monster_scientist::vDeath(int iHitBody)
think = Respawn;
nextthink = time + 10.0f;
SendFlags = 1;
SendFlags |= NPC_FRAME;
m_eUser = world;
customphysics = __NULL__;
m_iFlags = 0x0;
@ -676,6 +736,7 @@ void monster_scientist::Respawn(void)
health = 50;
velocity = [0,0,0];
m_iFlags = 0x0;
SendFlags = 0xff;
if (autocvar_sh_scialert) {
m_iFlags |= SCIF_FEAR;
@ -713,8 +774,8 @@ void monster_scientist::monster_scientist(void)
/* This stuff needs to be persistent because we can't guarantee that
* the client-side geomset refresh happens. Don't shove this into Respawn */
m_iBody = floor(random(1,5));
switch (m_iBody) {
body = floor(random(1,5));
switch (body) {
case 1:
m_flPitch = 105;
netname = "Walter";

View file

@ -14,25 +14,30 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void Game_ClientConnect(void)
var int autocvar_sv_networkeverything = FALSE;
void
Game_ClientConnect(void)
{
entity a;
bprint(PRINT_HIGH, sprintf("%s connected\n", self.netname));
int playercount = 0;
for (entity eFind = world; (eFind = find(eFind, classname, "player"));) {
for (a = world; (a = find(a, classname, "player"));) {
playercount++;
}
/* We're the first. */
/* we're the first. respawn all entities? */
if (playercount == 0) {
for (entity a = world; (a = findfloat(a, gflags, GF_CANRESPAWN));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
}
for (a = world; (a = findfloat(a, gflags, GF_CANRESPAWN));) {
CBaseEntity caw = (CBaseEntity)a;
caw.Respawn();
}
}
}
void Game_ClientDisconnect(void)
void
Game_ClientDisconnect(void)
{
bprint(PRINT_HIGH, sprintf("%s disconnected\n", self.netname));
@ -45,28 +50,117 @@ void Game_ClientDisconnect(void)
self.SendFlags = 1;
}
void Game_ClientKill(void)
void
Game_ClientKill(void)
{
Damage_Apply(self, self, self.health, self.origin, TRUE);
}
void Game_PlayerPreThink(void)
void
Game_PlayerPreThink(void)
{
}
void Game_PlayerPostThink(void)
void
Game_PlayerPostThink(void)
{
player pl = (player)self;
Animation_PlayerUpdate();
self.SendFlags = 1;
if (pl.old_modelindex != pl.modelindex) {
pl.SendFlags |= PLAYER_MODELINDEX;
}
if (pl.old_origin[0] != pl.origin[0]) {
pl.SendFlags |= PLAYER_ORIGIN;
}
if (pl.old_origin[1] != pl.origin[1]) {
pl.SendFlags |= PLAYER_ORIGIN;
}
if (pl.old_origin[2] != pl.origin[2]) {
pl.SendFlags |= PLAYER_ORIGIN_Z;
}
if (pl.old_angles[0] != pl.angles[0]) {
pl.SendFlags |= PLAYER_ANGLES_X;
}
if (pl.old_angles[1] != pl.angles[1]) {
pl.SendFlags |= PLAYER_ANGLES_Y;
}
if (pl.old_angles[2] != pl.angles[2]) {
pl.SendFlags |= PLAYER_ANGLES_Z;
}
if (pl.old_velocity[0] != pl.velocity[0]) {
pl.SendFlags |= PLAYER_VELOCITY;
}
if (pl.old_velocity[1] != pl.velocity[1]) {
pl.SendFlags |= PLAYER_VELOCITY;
}
if (pl.old_velocity[2] != pl.velocity[2]) {
pl.SendFlags |= PLAYER_VELOCITY_Z;
}
if (pl.old_flags != pl.flags) {
pl.SendFlags |= PLAYER_FLAGS;
}
if (pl.old_activeweapon != pl.activeweapon) {
pl.SendFlags |= PLAYER_WEAPON;
}
if (pl.old_items != pl.g_items) {
pl.SendFlags |= PLAYER_ITEMS;
}
if (pl.old_health != pl.health) {
pl.SendFlags |= PLAYER_HEALTH;
}
if (pl.old_armor != pl.armor) {
pl.SendFlags |= PLAYER_ARMOR;
}
if (pl.old_movetype != pl.movetype) {
pl.SendFlags |= PLAYER_MOVETYPE;
}
if (pl.old_viewofs != pl.view_ofs[2]) {
pl.SendFlags |= PLAYER_VIEWOFS;
}
if (pl.old_baseframe != pl.baseframe) {
pl.SendFlags |= PLAYER_BASEFRAME;
}
if (pl.old_frame != pl.frame) {
pl.SendFlags |= PLAYER_FRAME;
}
if (pl.old_a_ammo1 != pl.a_ammo1) {
pl.SendFlags |= PLAYER_AMMO1;
}
if (pl.old_a_ammo2 != pl.a_ammo2) {
pl.SendFlags |= PLAYER_AMMO2;
}
if (pl.old_a_ammo3 != pl.a_ammo3) {
pl.SendFlags |= PLAYER_AMMO3;
}
pl.old_modelindex = pl.modelindex;
pl.old_origin = pl.origin;
pl.old_angles = pl.angles;
pl.old_velocity = pl.velocity;
pl.old_flags = pl.flags;
pl.old_activeweapon = pl.activeweapon;
pl.old_items = pl.g_items;
pl.old_health = pl.health;
pl.old_armor = pl.armor;
pl.old_movetype = pl.movetype;
pl.old_viewofs = pl.view_ofs[2];
pl.old_baseframe = pl.baseframe;
pl.old_frame = pl.frame;
pl.old_a_ammo1 = pl.a_ammo1;
pl.old_a_ammo2 = pl.a_ammo2;
pl.old_a_ammo3 = pl.a_ammo3;
}
void Game_RunClientCommand(void)
void
Game_RunClientCommand(void)
{
Footsteps_Update();
QPhysics_Run(self);
}
void Game_DecodeChangeParms(void)
void
Game_DecodeChangeParms(void)
{
player pl = (player)self;
g_landmarkpos[0] = parm1;
@ -81,7 +175,8 @@ void Game_DecodeChangeParms(void)
pl.g_items = parm10;
pl.activeweapon = parm11;
}
void Game_SetChangeParms(void)
void
Game_SetChangeParms(void)
{
player pl = (player)self;
parm1 = g_landmarkpos[0];
@ -97,7 +192,8 @@ void Game_SetChangeParms(void)
parm11 = pl.activeweapon;
}
void Game_PutClientInServer(void)
void
Game_PutClientInServer(void)
{
if (self.classname != "player") {
spawnfunc_player();
@ -107,7 +203,7 @@ void Game_PutClientInServer(void)
entity spot;
pl.classname = "player";
pl.health = self.max_health = 100;
//forceinfokey(self, "*dead", "0");
pl.takedamage = DAMAGE_YES;
pl.solid = SOLID_SLIDEBOX;
pl.movetype = MOVETYPE_WALK;
@ -116,7 +212,7 @@ void Game_PutClientInServer(void)
pl.model = "models/player.mdl";
string mymodel = infokey(pl, "model");
if (mymodel) {
mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel);
if (whichpack(mymodel)) {
@ -124,7 +220,7 @@ void Game_PutClientInServer(void)
}
}
setmodel(pl, pl.model);
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
pl.view_ofs = VEC_PLAYER_VIEWPOS;
pl.velocity = [0,0,0];
@ -141,7 +237,6 @@ void Game_PutClientInServer(void)
Game_DecodeChangeParms();
if (startspot != "") {
print(sprintf("[LEVEL] Startspot is \"%s\"\n", startspot));
setorigin(pl, Landmark_GetSpot());
} else {
spot = find(world, classname, "info_player_start");
@ -162,40 +257,48 @@ void Game_PutClientInServer(void)
}
}
void SV_SendChat(entity eSender, string sMessage, entity eEnt, float fType)
void
SV_SendChat(entity sender, string msg, entity eEnt, float fType)
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, fType == 0 ? EV_CHAT:EV_CHAT_TEAM);
WriteByte(MSG_MULTICAST, num_for_edict(eSender) - 1);
WriteByte(MSG_MULTICAST, eSender.team);
WriteString(MSG_MULTICAST, sMessage);
WriteByte(MSG_MULTICAST, num_for_edict(sender) - 1);
WriteByte(MSG_MULTICAST, sender.team);
WriteString(MSG_MULTICAST, msg);
if (eEnt) {
msg_entity = eEnt;
multicast([0,0,0], MULTICAST_ONE);
} else {
multicast([0,0,0], MULTICAST_ALL);
}
localcmd(sprintf("echo [SERVER] %s: %s\n", sender.netname, msg));
}
void Game_ParseClientCommand(string cmd)
void
Game_ParseClientCommand(string cmd)
{
tokenize(cmd);
if (argv(1) == "timeleft") {
float fTimeLeft = cvar("mp_timelimit") - (time / 60);
Vox_Singlecast(self, sprintf("we have %s minutes remaining", Vox_TimeToString(fTimeLeft)));
string msg;
string timestring;
float timeleft;
timeleft = cvar("mp_timelimit") - (time / 60);
timestring = Vox_TimeToString(timeleft);
msg = sprintf("we have %s minutes remaining", timestring);
Vox_Singlecast(self, msg);
return;
}
if (argv(0) == "say") {
localcmd(sprintf("echo [SERVER] %s: %s\n", self.netname, argv(1)));
SV_SendChat(self, argv(1), world, 0);
return;
} else if (argv(0) == "say_team") {
localcmd(sprintf("echo [TEAM %d] %s: %s\n", self.team, self.netname, argv(1)));
for (entity eFind = world; (eFind = find(eFind, classname, "player"));) {
if (eFind.team == self.team) {
SV_SendChat(self, argv(1), eFind, 1);
entity a;
for (a = world; (a = find(a, classname, "player"));) {
if (a.team == self.team) {
SV_SendChat(self, argv(1), a, 1);
}
}
return;
@ -204,7 +307,8 @@ void Game_ParseClientCommand(string cmd)
clientcommand(self, cmd);
}
void Game_SetNewParms(void)
void
Game_SetNewParms(void)
{
}

View file

@ -120,36 +120,72 @@ float Player_SendEntity(entity ePEnt, float fChanged)
}
WriteByte(MSG_ENTITY, ENT_PLAYER);
WriteShort(MSG_ENTITY, pl.modelindex);
WriteCoord(MSG_ENTITY, pl.origin[0]);
WriteCoord(MSG_ENTITY, pl.origin[1]);
WriteCoord(MSG_ENTITY, pl.origin[2]);
WriteFloat(MSG_ENTITY, pl.v_angle[0]);
WriteFloat(MSG_ENTITY, pl.angles[1]);
WriteFloat(MSG_ENTITY, pl.angles[2]);
WriteCoord(MSG_ENTITY, pl.velocity[0]);
WriteCoord(MSG_ENTITY, pl.velocity[1]);
WriteCoord(MSG_ENTITY, pl.velocity[2]);
WriteFloat(MSG_ENTITY, pl.flags);
WriteByte(MSG_ENTITY, pl.activeweapon);
WriteFloat(MSG_ENTITY, pl.weapontime);
WriteFloat(MSG_ENTITY, pl.g_items);
WriteByte(MSG_ENTITY, pl.health);
WriteByte(MSG_ENTITY, pl.armor);
WriteByte(MSG_ENTITY, pl.movetype);
WriteFloat(MSG_ENTITY, pl.view_ofs[2]);
WriteFloat(MSG_ENTITY, pl.viewzoom);
WriteFloat(MSG_ENTITY, pl.jumptime);
WriteFloat(MSG_ENTITY, pl.teleport_time);
WriteFloat(MSG_ENTITY, fChanged);
WriteByte(MSG_ENTITY, pl.baseframe);
WriteByte(MSG_ENTITY, pl.frame);
/* really trying to get our moneys worth with 23 bits of mantissa */
if (fChanged & PLAYER_MODELINDEX) {
WriteShort(MSG_ENTITY, pl.modelindex);
}
if (fChanged & PLAYER_ORIGIN) {
WriteCoord(MSG_ENTITY, pl.origin[0]);
WriteCoord(MSG_ENTITY, pl.origin[1]);
}
if (fChanged & PLAYER_ORIGIN_Z) {
WriteCoord(MSG_ENTITY, pl.origin[2]);
}
if (fChanged & PLAYER_ANGLES_X) {
WriteFloat(MSG_ENTITY, pl.v_angle[0]);
}
if (fChanged & PLAYER_ANGLES_Y) {
WriteFloat(MSG_ENTITY, pl.angles[1]);
}
if (fChanged & PLAYER_ANGLES_Z) {
WriteFloat(MSG_ENTITY, pl.angles[2]);
}
if (fChanged & PLAYER_VELOCITY) {
WriteCoord(MSG_ENTITY, pl.velocity[0]);
WriteCoord(MSG_ENTITY, pl.velocity[1]);
}
if (fChanged & PLAYER_VELOCITY_Z) {
WriteCoord(MSG_ENTITY, pl.velocity[2]);
}
if (fChanged & PLAYER_FLAGS) {
WriteFloat(MSG_ENTITY, pl.flags);
}
if (fChanged & PLAYER_WEAPON) {
WriteByte(MSG_ENTITY, pl.activeweapon);
}
if (fChanged & PLAYER_ITEMS) {
WriteFloat(MSG_ENTITY, pl.g_items);
}
if (fChanged & PLAYER_HEALTH) {
WriteByte(MSG_ENTITY, pl.health);
}
if (fChanged & PLAYER_ARMOR) {
WriteByte(MSG_ENTITY, pl.armor);
}
if (fChanged & PLAYER_MOVETYPE) {
WriteByte(MSG_ENTITY, pl.movetype);
}
if (fChanged & PLAYER_VIEWOFS) {
WriteFloat(MSG_ENTITY, pl.view_ofs[2]);
}
if (fChanged & PLAYER_BASEFRAME) {
WriteByte(MSG_ENTITY, pl.baseframe);
}
if (fChanged & PLAYER_FRAME) {
WriteByte(MSG_ENTITY, pl.frame);
}
if (fChanged & PLAYER_AMMO1) {
WriteByte(MSG_ENTITY, pl.a_ammo1);
}
if (fChanged & PLAYER_AMMO2) {
WriteByte(MSG_ENTITY, pl.a_ammo2);
}
if (fChanged & PLAYER_AMMO3) {
WriteByte(MSG_ENTITY, pl.a_ammo3);
}
WriteByte(MSG_ENTITY, pl.a_ammo1);
WriteByte(MSG_ENTITY, pl.a_ammo2);
WriteByte(MSG_ENTITY, pl.a_ammo3);
WriteFloat(MSG_ENTITY, pl.w_attack_next);
WriteFloat(MSG_ENTITY, pl.w_idle_next);
return TRUE;
}

View file

@ -25,3 +25,43 @@ enum {
#endif
ENT_DECAL
};
/* entity update flags */
enumflags {
NPC_MODELINDEX,
NPC_ORIGIN_X,
NPC_ORIGIN_Y,
NPC_ORIGIN_Z,
NPC_ANGLES_X,
NPC_ANGLES_Y,
NPC_ANGLES_Z,
NPC_VELOCITY_X,
NPC_VELOCITY_Y,
NPC_VELOCITY_Z,
NPC_FRAME,
NPC_SKIN,
NPC_BODY
};
enumflags {
PLAYER_MODELINDEX,
PLAYER_ORIGIN,
PLAYER_ORIGIN_Z,
PLAYER_ANGLES_X,
PLAYER_ANGLES_Y,
PLAYER_ANGLES_Z,
PLAYER_VELOCITY,
PLAYER_VELOCITY_Z,
PLAYER_FLAGS,
PLAYER_WEAPON,
PLAYER_ITEMS,
PLAYER_HEALTH,
PLAYER_ARMOR,
PLAYER_MOVETYPE,
PLAYER_VIEWOFS,
PLAYER_BASEFRAME,
PLAYER_FRAME,
PLAYER_AMMO1,
PLAYER_AMMO2,
PLAYER_AMMO3
};

View file

@ -91,5 +91,23 @@ class player
int ammo_tripmine;
int ammo_snark;
int ammo_hornet;
/* conditional networking */
int old_modelindex;
vector old_origin;
vector old_angles;
vector old_velocity;
int old_flags;
int old_activeweapon;
int old_items;
int old_health;
int old_armor;
int old_movetype;
int old_viewofs;
int old_baseframe;
int old_frame;
int old_a_ammo1;
int old_a_ammo2;
int old_a_ammo3;
#endif
};

View file

@ -89,6 +89,24 @@ class player
int ammo_tripmine;
int ammo_snark;
int ammo_hornet;
/* conditional networking */
int old_modelindex;
vector old_origin;
vector old_angles;
vector old_velocity;
int old_flags;
int old_activeweapon;
int old_items;
int old_health;
int old_armor;
int old_movetype;
int old_viewofs;
int old_baseframe;
int old_frame;
int old_a_ammo1;
int old_a_ammo2;
int old_a_ammo3;
#endif
};

View file

@ -16,18 +16,19 @@
enum
{
CROWBAR_IDLE,
CROWBAR_DRAW,
CROWBAR_HOLSTER,
CROWBAR_ATTACK1HIT,
CROWBAR_ATTACK1MISS,
CROWBAR_ATTACK2MISS,
CROWBAR_ATTACK2HIT,
CROWBAR_ATTACK3MISS,
CROWBAR_ATTACK3HIT
CBAR_IDLE,
CBAR_DRAW,
CBAR_HOLSTER,
CBAR_ATTACK1HIT,
CBAR_ATTACK1MISS,
CBAR_ATTACK2MISS,
CBAR_ATTACK2HIT,
CBAR_ATTACK3MISS,
CBAR_ATTACK3HIT
};
void w_crowbar_precache(void)
void
w_crowbar_precache(void)
{
precache_sound("weapons/cbar_miss1.wav");
precache_sound("weapons/cbar_hit1.wav");
@ -40,162 +41,203 @@ void w_crowbar_precache(void)
precache_model("models/p_crowbar.mdl");
}
void w_crowbar_updateammo(player pl)
void
w_crowbar_updateammo(player pl)
{
#ifdef SSQC
Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__);
#endif
}
string w_crowbar_wmodel(void)
string
w_crowbar_wmodel(void)
{
return "models/w_crowbar.mdl";
}
string w_crowbar_pmodel(void)
string
w_crowbar_pmodel(void)
{
return "models/p_crowbar.mdl";
}
string w_crowbar_deathmsg(void)
string
w_crowbar_deathmsg(void)
{
return "%s was assaulted by %s's Crowbar.";
}
void w_crowbar_draw(void)
void
w_CBAR_DRAW(void)
{
Weapons_SetModel("models/v_crowbar.mdl");
Weapons_ViewAnimation(CROWBAR_DRAW);
Weapons_ViewAnimation(CBAR_DRAW);
}
void w_crowbar_holster(void)
void
w_CBAR_HOLSTER(void)
{
Weapons_ViewAnimation(CROWBAR_HOLSTER);
Weapons_ViewAnimation(CBAR_HOLSTER);
}
void w_crowbar_primary(void)
void
w_crowbar_primary(void)
{
int anim = 0;
vector src;
player pl = (player)self;
if (pl.w_attack_next) {
return;
}
Weapons_MakeVectors();
vector src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
int r = (float)input_sequence%3;
switch (r) {
case 0:
Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK1MISS:CROWBAR_ATTACK1HIT);
break;
case 1:
Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK2MISS:CROWBAR_ATTACK2HIT);
break;
default:
Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK3MISS:CROWBAR_ATTACK3HIT);
}
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
} else {
pl.w_attack_next = 0.25f;
}
#ifdef SSQC
if (pl.flags & FL_CROUCHING)
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
else
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM);
int r = (float)input_sequence % 3;
switch (r) {
case 0:
anim = trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT;
break;
case 1:
anim = trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT;
break;
default:
anim = trace_fraction >= 1 ? CBAR_ATTACK3MISS:CBAR_ATTACK3HIT;
}
Weapons_ViewAnimation(anim);
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
} else {
pl.w_attack_next = 0.25f;
}
pl.w_idle_next = 2.5f;
#ifdef SSQC
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f);
}
sound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM);
if (trace_fraction >= 1.0) {
return;
}
/* don't bother with decals, we got squibs */
if (trace_ent.iBleeds) {
Effect_CreateBlood(trace_endpos, [0,0,0]);
} else {
Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal);
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, self, 10, trace_endpos, FALSE );
// TODO: Better way to find if it bleeds?
if (trace_ent.iBleeds == 1) {
if (random() < 0.33) {
Weapons_PlaySound(pl, 8, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM);
} else if (random() < 0.66) {
Weapons_PlaySound(pl, 8, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM);
} else {
Weapons_PlaySound(pl, 8, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM);
}
}
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, self, 10, trace_endpos, FALSE );
if (!trace_ent.iBleeds) {
return;
}
if (random() < 0.33) {
sound(pl, 8, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM);
} else if (random() < 0.66) {
sound(pl, 8, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM);
} else {
if (random() < 0.5) {
Weapons_PlaySound(pl, 8, "weapons/cbar_hit1.wav", 1, ATTN_NORM);
} else {
Weapons_PlaySound(pl, 8, "weapons/cbar_hit2.wav", 1, ATTN_NORM);
}
sound(pl, 8, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM);
}
} else {
if (random() < 0.5) {
sound(pl, 8, "weapons/cbar_hit1.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/cbar_hit2.wav", 1, ATTN_NORM);
}
}
#endif
pl.w_idle_next = 2.5f;
}
void w_crowbar_secondary(void)
{
}
void w_crowbar_reload(void)
{
}
void w_crowbar_release(void)
void
w_crowbar_release(void)
{
player pl = (player)self;
if (pl.w_idle_next) {
return;
}
Weapons_ViewAnimation(CROWBAR_IDLE);
Weapons_ViewAnimation(CBAR_IDLE);
pl.w_idle_next = 15.0f;
}
float w_crowbar_aimanim(void)
float
w_crowbar_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void w_crowbar_hudpic(int s, vector pos)
void
w_crowbar_hudpic(int selected, vector pos)
{
#ifdef CSQC
if (s) {
drawsubpic(pos, [170,45], "sprites/640hud4.spr_0.tga", [0,0], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE);
if (selected) {
drawsubpic(
pos,
[170,45],
"sprites/640hud4.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
} else {
drawsubpic(pos, [170,45], "sprites/640hud1.spr_0.tga", [0,0], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE);
drawsubpic(
pos,
[170,45],
"sprites/640hud1.spr_0.tga",
[0,0],
[170/256,45/256],
g_hud_color,
1.0f,
DRAWFLAG_ADDITIVE
);
}
#endif
}
weapon_t w_crowbar =
{
ITEM_CROWBAR,
0,
0,
"sprites/640hud1.spr_0.tga",
[48,16],
[192,0],
w_crowbar_draw,
w_crowbar_holster,
w_crowbar_primary,
w_crowbar_secondary,
w_crowbar_reload,
w_crowbar_release,
__NULL__,
w_crowbar_precache,
__NULL__,
w_crowbar_updateammo,
w_crowbar_wmodel,
w_crowbar_pmodel,
w_crowbar_deathmsg,
w_crowbar_aimanim,
w_crowbar_hudpic
.id = ITEM_CROWBAR,
.slot = 0,
.slot_pos = 0,
.ki_spr = "sprites/640hud1.spr_0.tga",
.ki_size = [48,16],
.ki_xy = [192,0],
.draw = w_CBAR_DRAW,
.holster = w_CBAR_HOLSTER,
.primary = w_crowbar_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = w_crowbar_release,
.crosshair = __NULL__,
.precache = w_crowbar_precache,
.pickup = __NULL__,
.updateammo = w_crowbar_updateammo,
.wmodel = w_crowbar_wmodel,
.pmodel = w_crowbar_pmodel,
.deathmsg = w_crowbar_deathmsg,
.aimanim = w_crowbar_aimanim,
.hudpic = w_crowbar_hudpic
};
/* entity definitions for pickups */
#ifdef SSQC
void weapon_crowbar(void) {
void
weapon_crowbar(void)
{
Weapons_InitItem(WEAPON_CROWBAR);
}
#endif