djcev.com

//

Git Repos / fte_dogmode / qc / base_func.qc

Last update to this file was on 2024-11-20 at 23:54.

Show base_func.qc

//==============================================================================
// base_func.qc -- func base class
//==============================================================================

//======================================================================
// Constants
//======================================================================

#if defined(CSQC) || defined(SSQC)
const float FUNC_STATE_TOP = 0; // button, door, elevator states
const float FUNC_STATE_BOTTOM = 1;
const float FUNC_STATE_UP = 2;
const float FUNC_STATE_DOWN = 3;
#endif

#if defined(CSQC) || defined(SSQC)
const float BASE_FUNC_NET_ORIGIN = 1<<0;// origin has changed
const float BASE_FUNC_NET_SIZE = 1<<1; // size (mins, maxs) has changed
const float BASE_FUNC_NET_VELOCITY = 1<<2; // velocity has changed
const float BASE_FUNC_NET_MODEL = 1<<3; // model has changed
const float BASE_FUNC_NET_SPEED = 1<<4; // speed has changed
#endif

//======================================================================
// fields
//======================================================================

#ifdef CSQC
.float movetime; // timestamp this func started moving
.vector origin_start;
#endif

#if defined(CSQC) || defined(SSQC)
.void() think1; // called by calcmove_done
.vector finaldest, finalangle;
#endif

#ifdef SSQC
.float lip; //
#endif

//======================================================================
// forward declarations
//======================================================================

// base_func
#ifdef CSQC
void(float isnew, float netflags) base_func_netreceive_read;
float() base_func_predraw_solidpush;
#endif
#ifdef SSQC
float(entity to, float netflags) base_func_netsend;
#endif
#ifdef SSQC
void() sub_calcmove_done_think;
void(entity e, vector tdest, float tspeed, void() newthink) sub_calcmove;
void() sub_calcanglemovecontroller_done;
void(entity e, vector destangle, float tspeed, void() func, entity c)
sub_calcanglemovecontroller;
#endif
#if defined(CSQC) || defined(SSQC)
void(entity e) base_func_init;
#endif
#ifdef SSQC
strip void() base_func;
#endif

//------------------------------------------------------------------------------

//----------------------------------------------------------------------
// class base_func: base_mapentity
// {
//==============================================================
// Drawing & Networking
//==============================================================

#ifdef CSQC
//--------------------------------------------------------------
// returns a FUNC_STATE to be handled by the func's netreceive
//--------------------------------------------------------------
void(float isnew, float netflags) base_func_netreceive_read =
{
if (netflags & BASE_FUNC_NET_MODEL)
self.modelindex = ReadFloat ();

if (netflags & BASE_FUNC_NET_ORIGIN)
{
self.origin_x = ReadCoord ();
self.origin_y = ReadCoord ();
self.origin_z = ReadCoord ();
}

if (netflags & BASE_FUNC_NET_VELOCITY)
{
self.velocity_x = ReadCoord ();
self.velocity_y = ReadCoord ();
self.velocity_z = ReadCoord ();
}

if (netflags & BASE_FUNC_NET_SIZE)
{
self.mins_x = ReadCoord ();
self.mins_y = ReadCoord ();
self.mins_z = ReadCoord ();
self.maxs_x = ReadCoord ();
self.maxs_y = ReadCoord ();
self.maxs_z = ReadCoord ();
}

if (netflags & BASE_FUNC_NET_SPEED)
self.speed = ReadFloat ();
};

//--------------------------------------------------------------
// manually move SOLID_BSP MOVETYPE_PUSH entities based on their
// velocity and the timestamp of the last related server message.
// interpolates and kinda- sorta- predicts the move. (hopefully.)
// does not play well in (simulated) high ping environments.
//
// this took a really long time to figure out. -- CEV
//--------------------------------------------------------------
float() base_func_predraw_solidpush =
{
if (self.movetime)
{
// calculate new origin from the last origin
// the server sent us, the rate we're moving,
// and the timestamp of that server message.
// this only works with entities that maintain
// a constant velocity while moving -- CEV
self.neworigin = self.origin_start + self.velocity *
(time - self.movetime);

// must be careful to handle speed = 0 -- CEV
local float f;
if (self.speed)
f = bound (0, frametime * (self.speed*0.2), 1);
else
f = bound (0, frametime * 30, 1);

// final origin is an interpolation of neworigin
// above and the previous calculated origin -- CEV
self.origin = self.oldorigin +
((self.neworigin - self.oldorigin) * f);

// save off oldorigin -- CEV
self.oldorigin = self.origin;

/*
dprint (sprintf("base_func_predraw_solidpush: "
"entity %g, time %g, frametime %g, "
"lerpfrac %g\n",
self.entnum, time, frametime, f));
*/

addentity (self);

// rewind to the last origin sent by the server
// for collision detection -- CEV
setorigin (self, self.origin_net);
}
else
{
addentity (self);
}

return PREDRAW_NEXT;
};
#endif

#ifdef SSQC
//--------------------------------------------------------------
float(entity to, float netflags) base_func_netsend =
{
WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & BASE_FUNC_NET_MODEL)
WriteFloat (MSG_ENTITY, self.modelindex);

if (netflags & BASE_FUNC_NET_ORIGIN)
{
WriteCoord (MSG_ENTITY, self.origin_x);
WriteCoord (MSG_ENTITY, self.origin_y);
WriteCoord (MSG_ENTITY, self.origin_z);
}

if (netflags & BASE_FUNC_NET_VELOCITY)
{
WriteCoord (MSG_ENTITY, self.velocity_x);
WriteCoord (MSG_ENTITY, self.velocity_y);
WriteCoord (MSG_ENTITY, self.velocity_z);
}

if (netflags & BASE_FUNC_NET_SIZE)
{
WriteCoord (MSG_ENTITY, self.mins_x);
WriteCoord (MSG_ENTITY, self.mins_y);
WriteCoord (MSG_ENTITY, self.mins_z);
WriteCoord (MSG_ENTITY, self.maxs_x);
WriteCoord (MSG_ENTITY, self.maxs_y);
WriteCoord (MSG_ENTITY, self.maxs_z);
}

if (netflags & BASE_FUNC_NET_SPEED)
WriteFloat (MSG_ENTITY, self.speed);

return TRUE;
};
#endif

//==============================================================
// Subs
//==============================================================

#ifdef SSQC
//--------------------------------------------------------------
void() sub_calcmove_done_think =
{
setorigin (self, self.finaldest);
self.velocity = '0 0 0';
self.nextthink = -1;

if (self.think1)
self.think1 ();
};

//--------------------------------------------------------------
// SUB_CalcMove
//--------------------------------------------------------------
void(entity e, vector tdest, float tspeed, void() newthink)
sub_calcmove =
{
local vector vdestdelta;
local float len, traveltime, localtime;

if (!tspeed)
objerror ("sub_calcmove: No speed is defined!");

if (e.movetype == MOVETYPE_PUSH)
localtime = self.ltime;
else
localtime = time;

e.think1 = newthink;
e.finaldest = tdest;
e.think = sub_calcmove_done_think;

if (tdest == self.origin)
{
e.velocity = '0 0 0';
e.nextthink = localtime + 0.1;
return;
}

// set destdelta to the vector needed to move
vdestdelta = tdest - self.origin;

// calculate length of vector
len = vlen (vdestdelta);

// divide by speed to get time to reach tdest
traveltime = len / tspeed;

if (traveltime < 0.1)
{
e.velocity = '0 0 0';
e.nextthink = localtime + 0.1;
return;
}

// set nextthink to trigger a think when d is reached
e.nextthink = localtime + traveltime;

// scale the destdelta vector by the time spent traveling
// to get velocity
// qcc won't take vec/float
e.velocity = vdestdelta * (1 / traveltime);
};

//--------------------------------------------------------------
// SUB_CalcAngleMoveDoneController
// After rotating, set angle to exact final angle
//--------------------------------------------------------------
void() sub_calcanglemovecontroller_done =
{
self.owner.angles = self.finalangle;
self.owner.avelocity = '0 0 0';
self.nextthink = -1;
if (self.think1)
sub_runvoidas (self.owner, self.think1);
};

//--------------------------------------------------------------
// SUB_CalcAngleMoveController -- Same as SUB_CalcAngleMove, but
// using a separate controller entity to not lose track of current
// think functions.
//--------------------------------------------------------------
void(entity e, vector destangle, float tspeed, void() func,
entity c) sub_calcanglemovecontroller =
{
local vector destdelta;
local float len, traveltime;

if (!tspeed)
objerror("sub_calcanglemove: No speed is defined!\n");

// set destdelta to the vector needed to move
destdelta = normalize_angles180 (destangle - e.angles);

/*
dprint (sprintf("destangle: %v\n", destangle));
dprint (sprintf("self.angles: %v\n", self.angles));
dprint (sprintf("destdelta: %v\n", destdelta));
*/

// calculate length of vector
len = vlen (destdelta);

// divide by speed to get time to reach dest
traveltime = len / tspeed;

// set nextthink to trigger a think when dest is reached
c.nextthink = time + traveltime;

// scale the destdelta vector by the time spent traveling to
// get velocity
e.avelocity = destdelta * (1 / traveltime);

// Makes sure controller.owner points to self so it can be
// referenced later in the think function
c.owner = e;
c.think1 = func;
c.finalangle = destangle;
c.think = sub_calcanglemovecontroller_done;
};
#endif

//==============================================================
// Constructor & Spawn Functions
//==============================================================

#if defined(CSQC) || defined(SSQC)
//--------------------------------------------------------------
void(entity e) base_func_init =
{
base_mapentity_init (e);
e.classgroup |= CG_FUNC;

// TODO CEV
e.flags |= FL_LAGGEDMOVE;
};
#endif

#ifdef SSQC
//--------------------------------------------------------------
strip void() base_func =
{
base_func_init (self);
};
#endif
// };

Return to the top of this page or return to the overview of this repo.

Log base_func.qc

Return to the top of this page or return to the overview of this repo.