djcev.com

//

Git Repos / fte_dogmode / qc / misc / model.qc

Last update to this file was on 2025-08-13 at 05:20.

Show model.qc

//==============================================================================
// misc_model -- Joshua Skelton -- misc_model.qc requires math.qc
// Author: Joshua Skelton joshua.skelton@gmail.com
// Edited by: Inky 20201219 Minor changes for a better integration with their
// own code
// Edited by: bmFbr for solid and gravity spawnflags and custom bbox sizes
// Edited by: dumptruck_ds to add start and stop animations
//==============================================================================

//======================================================================
// constants
//======================================================================

#ifdef SSQC
//----------------------------------------------------------------------
// base_misc_model spawnflags -- CEV
//----------------------------------------------------------------------
typedef enumflags
{
SPAWNFLAG_BASE_MISC_MODEL_GRAVITY = 1,
SPAWNFLAG_BASE_MISC_MODEL_SOLID = 2,
SPAWNFLAG_BASE_MISC_MODEL_BACK_AND_FORTH = 4,
SPAWNFLAG_BASE_MISC_MODEL_ONLY_ONCE = 8,
SPAWNFLAG_BASE_MISC_MODEL_PLAY_COUNT = 16,
SPAWNFLAG_BASE_MISC_MODEL_STARTOFF = 32
// SPAWNFLAG_NOT_ON_EASY = 256, // see base_entities.qc -- CEV
// SPAWNFLAG_NOT_ON_NORMAL = 512,
// SPAWNFLAG_NOT_ON_HARD_OR_NIGHTMARE = 1024,
// SPAWNFLAG_NOT_IN_DEATHMATCH = 2048,
// SPAWNFLAG_NOT_IN_COOP = 4096,
// SPAWNFLAG_NOT_IN_SP = 8192,
// SPAWNFLAG_NOT_ON_SKILL2 = 32768, // see base_entities.qc -- CEV
// SPAWNFLAG_NOT_ON_SKILL3 = 65536, // see base_entities.qc -- CEV
// SPAWNFLAG_CENTERPRINTALL = 131072 // see base_entities.qc -- CEV
} base_misc_model_spawnflags;
#endif

#if defined(CSQC) || defined(SSQC)
//----------------------------------------------------------------------
// generic misc_model networking flags -- CEV
//----------------------------------------------------------------------
typedef enumflags
{
NETFLAG_MISC_MODEL_ORIGIN, // origin has changed
NETFLAG_MISC_MODEL_SIZE, // model size has changed
NETFLAG_MISC_MODEL_MODEL, // .model has changed
NETFLAG_MISC_MODEL_FRAME, // frame has changed
NETFLAG_MISC_MODEL_STATEFLAGS // active, inactive
} base_misc_model_netflags;

const float NETFLAG_MISC_MODEL_FULLSEND = NETFLAG_MISC_MODEL_ORIGIN |
NETFLAG_MISC_MODEL_SIZE | NETFLAG_MISC_MODEL_MODEL |
NETFLAG_MISC_MODEL_FRAME | NETFLAG_MISC_MODEL_STATEFLAGS;
#endif

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

#if defined(CSQC) || defined(SSQC)
.float first_frame; // The starting frame of the animation
.float last_frame; // The ending frame of the animation
#endif

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

// base_misc_model
#ifdef CSQC
void(float isnew) base_misc_model_netreceive;
float() base_misc_model_predraw;
#endif
#ifdef SSQC
float(entity to, float netflags) base_misc_model_netsend;
void() base_misc_model_think;
void() base_misc_model_use;
#endif
#if defined(CSQC) || defined(SSQC)
void(entity e) base_misc_model_init;
#endif

// misc_model
#ifdef SSQC
void(string key, string value) misc_model_init_field;
#endif
#if defined(CSQC) || defined(SSQC)
void(entity e) misc_model_init;
#endif
#ifdef SSQC
void() misc_model;
#endif

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

//----------------------------------------------------------------------
// class base_misc_model: base_mapentity
// {
#ifdef CSQC
//--------------------------------------------------------------
void(float isnew) base_misc_model_netreceive =
{
local float newframe = 0;
local float netflags = ReadByte ();

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

if (netflags & NETFLAG_MISC_MODEL_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 & NETFLAG_MISC_MODEL_MODEL)
self.modelindex = ReadShort ();

if (netflags & NETFLAG_MISC_MODEL_FRAME)
newframe = ReadByte ();

if (netflags & NETFLAG_MISC_MODEL_STATEFLAGS)
{
local float s1 = ReadByte ();
if (s1 & STATE_INACTIVE)
self.stateflags |= STATE_INACTIVE;
else
self.stateflags &= ~STATE_INACTIVE;
}

if (isnew && !(self.predraw))
if (self.classtype == CT_MISC_MODEL)
misc_model_init (self);

if (newframe != self.frame || isnew)
{
self.frame2 = self.frame;
self.lerptime = time;
self.frame = newframe;
}
};

//--------------------------------------------------------------
float() base_misc_model_predraw =
{
// interpolate frame
if (self.lerptime)
self.lerpfrac = 1 - (time - self.lerptime) * 10;

if (!(self.stateflags & STATE_INACTIVE))
addentity (self);

return PREDRAW_NEXT;
};
#endif

#ifdef SSQC
//--------------------------------------------------------------
float(entity to, float netflags) base_misc_model_netsend =
{
BASE_ENTITY_WRITECLASSTYPE ()

if (netflags > NETFLAG_MISC_MODEL_FULLSEND)
netflags = NETFLAG_MISC_MODEL_FULLSEND;

WriteByte (MSG_ENTITY, netflags);

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

if (netflags & NETFLAG_MISC_MODEL_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 & NETFLAG_MISC_MODEL_MODEL)
WriteShort (MSG_ENTITY, self.modelindex);

if (netflags & NETFLAG_MISC_MODEL_FRAME)
WriteByte (MSG_ENTITY, self.frame);

if (netflags & NETFLAG_MISC_MODEL_STATEFLAGS)
{
local float s1 = 0;
if (self.stateflags & STATE_INACTIVE)
s1 |= STATE_INACTIVE;
WriteByte (MSG_ENTITY, s1);
}

return TRUE;
};

//--------------------------------------------------------------
// misc_model_think -- Handles animation for misc_model entity.
//--------------------------------------------------------------
void() base_misc_model_think =
{
self.nextthink = time + fabs (self.speed);

if (self.stateflags & STATE_INACTIVE)
return;

if (self.frame < 0)
self.frame += -1;
else
self.frame += 1;

if (self.spawnflags &
SPAWNFLAG_BASE_MISC_MODEL_BACK_AND_FORTH &&
self.frame < self.first_frame)
{
self.speed *= -1;
self.frame += 2;
}
else if (self.spawnflags &
SPAWNFLAG_BASE_MISC_MODEL_BACK_AND_FORTH &&
self.frame > self.last_frame)
{
self.speed *= -1;
self.frame -= 2;
}
else
{
self.frame = wrap (self.frame, self.first_frame,
self.last_frame);
}

// signal CSQC that the frame has changed -- CEV
self.SendFlags |= NETFLAG_MISC_MODEL_FRAME;

if (self.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_ONLY_ONCE &&
self.frame == self.last_frame &&
self.last_frame != self.first_frame)
{
self.nextthink = -1;
}

if (self.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_PLAY_COUNT &&
self.frame == self.last_frame &&
self.last_frame != self.first_frame)
{
if !(self.count)
objerror ("Error: set count to the number of "
" animation cycles!");
self.cnt = self.cnt + 1;
dprint (ftos(self.cnt));
dprint ("\n");
if (self.cnt != self.count)
return FALSE;
else
self.nextthink = -1;
}
};

//--------------------------------------------------------------
void() base_misc_model_use =
{
if (self.stateflags & STATE_INACTIVE)
{
// become active -- CEV
if (self.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_SOLID)
self.solid = SOLID_BBOX;

self.model = self.mdl;
setmodel (self, self.model);
setorigin (self, self.origin);

self.stateflags &= ~STATE_INACTIVE;
}
else
{
// become inactive -- CEV
if (self.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_SOLID)
self.solid = SOLID_NOT;

self.model = "";
setmodel (self, self.model);
setorigin (self, self.origin);

self.stateflags |= STATE_INACTIVE;
}

// update CSQC
self.SendFlags |= NETFLAG_MISC_MODEL_STATEFLAGS;
};
#endif

#if defined(CSQC) || defined(SSQC)
//--------------------------------------------------------------
void(entity e) base_misc_model_init =
{
base_mapentity_init (e);
};
#endif
// };

/*QUAKED misc_model (0 0.5 0.8) (-8 -8 -8) (8 8 8) X X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ({"path" : mdl, "skin" : skin, "frame": frame});
}
An entity for displaying models. A frame range can be given to animate the
model.

mdl: The model to display. Can be of type mdl, bsp, or spr.

frame: The frame to display. Can be used to offset the animation.

first_frame: The starting frame of the animation.

last_frame: The last frame of the animation.
*/
//----------------------------------------------------------------------
// class misc_model: base_misc_model
// {
#ifdef SSQC
//--------------------------------------------------------------
void(string key, string value) misc_model_init_field =
{
switch (key)
{
// rewrite bmFbr's misc_model fields; will be
// consumed in misc_model_init below -- CEV
case "centeroffset":
self.finaldest = stov (value);
break;
case "mdlsz":
self.finalangle = stov (value);
break;
}
};
#endif

#if defined(CSQC) || defined(SSQC)
//--------------------------------------------------------------
void(entity e) misc_model_init =
{
e.classname = "misc_model";
e.classtype = CT_MISC_MODEL;
base_misc_model_init (e);

#ifdef CSQC
// only SOLID_BBOX misc_model entities are sent to CSQC -- CEV
e.movetype = MOVETYPE_NONE;
e.solid = SOLID_BBOX;
setmodelindex (e, e.modelindex);
setorigin (e, e.origin);
setsize (e, e.mins, e.maxs);
e.drawmask = DRAWMASK_NORMAL;
e.predraw = base_misc_model_predraw;
#endif

#ifdef SSQC
if (known_release == KNOWN_RELEASE_QUAKE3 ||
known_release == KNOWN_RELEASE_CPMA ||
known_release == KNOWN_RELEASE_QUAKELIVE)
{
e.mdl = e.model;
}

if (!e.mdl || e.mdl == "")
objerror ("Model not defined");

if (!e.pos1 && !e.pos2)
{
if (e.finaldest || e.finalangle)
{
// bmFbr's fields (rewritten above) -- CEV
e.pos1.x = e.finaldest.x - (e.finalangle.x / 2);
e.pos1.y = e.finaldest.y - (e.finalangle.y / 2);
e.pos1.z = e.finaldest.z - (e.finalangle.z / 2);

e.pos2.x = e.finaldest.x + (e.finalangle.x / 2);
e.pos2.y = e.finaldest.y + (e.finalangle.y / 2);
e.pos2.z = e.finaldest.z + (e.finalangle.z / 2);

// clear the borrowed fields -- CEV
e.finaldest = '0 0 0';
e.finalangle = '0 0 0';
}
else
{
// set a default size -- CEV
e.pos1 = '-16 -16 -16';
e.pos2 = '16 16 16';
}
}

precache_model (e.mdl);
setmodel (e, e.mdl);
setsize (e, e.pos1, e.pos2);

if (e.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_SOLID)
e.solid = SOLID_BBOX;
else
e.solid = SOLID_NOT;

if (e.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_GRAVITY)
e.movetype = MOVETYPE_TOSS;
else
e.movetype = MOVETYPE_NONE;

if (!e.frame)
e.frame = e.first_frame;

// Make static (not animate) if not given a frame range, and
// not affected by gravity; also remains active if it has a
// targetname (so it can be killtargeted/toggled)
if (!e.last_frame && !e.targetname && !e.targetname2 &&
!(e.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_GRAVITY) &&
!(e.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_SOLID))
{
makestatic (e);
return;
}

// if it has a custom animation range
if (e.last_frame)
{
// Default animation speed to 10 fps
if (!e.speed)
e.speed = 0.1;
e.think = base_misc_model_think;
e.nextthink = time + e.speed;
}

// set state to the reverse of expected 'cause model_use
// is going to toggle it -- CEV
if (e.spawnflags & SPAWNFLAG_BASE_MISC_MODEL_STARTOFF)
e.stateflags &= ~STATE_INACTIVE;
else
e.stateflags |= STATE_INACTIVE;

sub_runvoidas (e, base_misc_model_use);

// network solid misc_model entities to CSQC -- CEV
if (e.solid == SOLID_BBOX)
{
e.SendEntity = base_misc_model_netsend;
e.SendFlags = NETFLAG_MISC_MODEL_FULLSEND;
}
#endif
};
#endif

#ifdef SSQC
//--------------------------------------------------------------
void() misc_model =
{
base_mapentity_init_spawndata (misc_model_init_field);

// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

misc_model_init (self);
};
#endif
// };

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

Log model.qc

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