djcev.com

//

Git Repos / fte_dogmode / qc / func / fall2.qc

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

Show fall2.qc

//==============================================================================
// func_fall2 -- code attributed to RennyC & whirledtsar
//==============================================================================

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

#ifdef SSQC
//----------------------------------------------------------------------
// func_fall2 spawnflags -- CEV
//----------------------------------------------------------------------
typedef enumflags
{
SPAWNFLAG_FUNC_FALL2_PLAYER_TRIGGERED = 1,
SPAWNFLAG_FUNC_FALL2_MONSTER_TRIGGERED = 2,
SPAWNFLAG_FUNC_FALL2_BREAKABLE = 8 // VR
// SPAWNFLAG_FUNC_FALL2_SOLID = 16; // VR
// 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
} func_fall2_spawnflags;
#endif

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

// temp_fall2_field
#ifdef SSQC
void() temp_fall2_field_touch;
entity(entity own, vector nmins, vector nmaxs) spawn_temp_fall2_field;
void(entity e) temp_fall2_field_init;
strip void() temp_fall2_field;
#endif

// func_fall2
#ifdef CSQC
void(float isnew) func_fall2_netreceive;
#endif
#ifdef SSQC
void() func_fall2_think;
void() func_fall2_touch;
void() func_fall2_use;
#endif
#ifdef SSQC
void(string key, string value) func_fall2_init_field;
#endif
#if defined(CSQC) || defined(SSQC)
void(entity e) func_fall2_init;
#endif
#ifdef SSQC
void() func_fall2;
#endif

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

//----------------------------------------------------------------------
// class temp_fall2_field: base_tempentity
// {
#ifdef SSQC
//--------------------------------------------------------------
void() temp_fall2_field_touch =
{
if (other.flags & FL_FLY)
// flying monsters shouldn't trigger falling platforms
return;

if (other.flags & FL_MONSTER)
{
if (!self.owner)
{
dprint ("temp_fall2_field_touch: no owner!\n");
remove (self);
return;
}

self.owner.think = func_fall2_use;
self.owner.nextthink = self.owner.ltime + 0.1;
remove (self);
}
};

//--------------------------------------------------------------
entity(entity own, vector nmins, vector nmaxs) spawn_temp_fall2_field =
{
local entity e = spawn ();
e.owner = own;
setsize (e, nmins, nmaxs);
setorigin (e, own.origin);
setmodel (e, own.model);
temp_fall2_field_init (e);
return e;
};

//--------------------------------------------------------------
void(entity e) temp_fall2_field_init =
{
e.classname = "temp_fall2_field";
e.classtype = CT_TEMP_FALL2_HELPER;
base_tempentity_init (e);
e.solid = SOLID_TRIGGER;
e.touch = temp_fall2_field_touch;
};

//--------------------------------------------------------------
strip void() temp_fall2_field =
{
temp_fall2_field_init (self);
};
#endif
// };

/*QUAKED func_fall2 (0 .5 .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
Falling brush by RennyC with additions from whirledtsar

wait - how long until the brush begins falling
noise - the sound to make when touched / activated
noise2 - the sound to make before it's removed, pain_finished of -1 disables noise2 as the object stays forever
cnt - 0 is default behavior (MOVETYPE_TOSS), 1 means collisions are disabled while falling (MOVETYPE_NOCLIP), 2 turns the brush into a bouncing entity (MOVETYPE_BOUNCE)
pain_finished - default of 0.01, higher value has the object/brush fade out faster thus in turn affecting how long it stays. -1 stays forever
speed - speed as to how fast something falls per game frame, default is 10, higher values mean faster falling. Only for cnt of 1 (MOVETYPE_NOCLIP).
Recommended to use lip for max fall speed on MOVETYPE_TOSS/BOUNCE entities (cnt 0 and 2) as they follow Quake's default gravity
lip - maximum fall speed that can be achieved, caps 'speed' variable. Default is -800
avelocity - have it spin when activated using X, Y, Z vector coordinates. MOVETYPE_BOUNCE ignores avelocity !Use an origin brush for proper spin!

spawnflags:
Default behavior allows anyone to activate func_fall2 on touch ONLY
1 - Player activated only
2 - Monster activated only
8 - break on impact (use style key for textures, see manual for more)
16 - fall solid; remains solid on ground

Able to .target other entities, including other func_fall2s
*/
//----------------------------------------------------------------------
// class func_fall2: base_breakable
// {
#ifdef CSQC
//--------------------------------------------------------------
void(float isnew) func_fall2_netreceive =
{
// creates the netflag variable -- CEV
BASE_FUNC_NETRECEIVE (func_fall2_init)
};
#endif

#ifdef SSQC
//--------------------------------------------------------------
void() func_fall2_think =
{
if (self.attack_finished >= time)
{
self.nextthink = self.ltime + 0.1;
return;
}

if (self.target != __NULL__ && self.target != "")
sub_useandforgettargets ();

// removed FALL_SOLID behavior -- dumptruck_ds
self.solid = SOLID_NOT;

if (self.pos1 != '0 0 0')
// apply stored avelocity vector values
self.avelocity = self.pos1;

if (self.pos2 && !self.velocity)
// Add velocity movement
self.velocity = self.pos2;

if (self.cnt >= 2)
{
self.movetype = MOVETYPE_BOUNCE;
self.velocity.z = max (self.velocity.z, self.speed2);
}
else if (self.cnt == 1)
{
self.movetype = MOVETYPE_NOCLIP;
if (self.velocity.z > self.speed2)
self.velocity.z -= self.velocity.z -
self.speed * (frametime * 100);
else
self.velocity.z = self.speed2;
}
else
{
// default behavior (cnt is 0 or less)
self.movetype = MOVETYPE_TOSS;
self.velocity.z = max (self.velocity.z, self.speed2);
}

self.SendFlags |= NETFLAG_BASE_ENTITY_SOLID;

if (self.pain_finished != -1)
{
if (self.alpha > 0.1)
{
self.alpha -= self.pain_finished;
self.SendFlags |= NETFLAG_BASE_ENTITY_ALPHA;
}
else
{
if (self.noise2 != __NULL__ && self.noise2!="")
{
sound (self, CHAN_AUTO, self.noise2,
VOL_HIGH, ATTN_NORM);
}
base_entity_remove (self);
return;
}
}
else if (self.flags & FL_ONGROUND)
{
if (self.classgroup & CG_FRAMETICK)
self.classgroup &= ~CG_FRAMETICK;

self.movetype = MOVETYPE_NONE;
self.think = sub_null;
}

if (self.flags & FL_ONGROUND &&
self.spawnflags & SPAWNFLAG_FUNC_FALL2_BREAKABLE)
{
// VR
// aka BREAKABLE_NO_MONSTERS
self.spawnflags(-)1;
// aka BREAK_EXPLODE
self.spawnflags(-)2;
// because of how debris origin is calculated
self.mins = self.absmin;
self.maxs = self.absmax;
// debris gets velocity from health
self.health = self.speed2 * 0.1;
// func_breakable uses cnt for quantity of
// debris to spawn
self.cnt = self.count;
// removes self
base_breakable_die ('0 0 0');
}

self.nextthink = self.ltime + 0.1;
};

//--------------------------------------------------------------
void() func_fall2_touch =
{
if (!other.takedamage)
return;

if (other.classtype != CT_PLAYER)
// player activated only
return;

if (self.spawnflags & SPAWNFLAG_FUNC_FALL2_MONSTER_TRIGGERED)
// disable on monster only, also fixes weird issue
return;

if (self.trigger_field)
remove (self.trigger_field);

// call use 'cause it does the same thing touch() did -- CEV
func_fall2_use ();
};

//--------------------------------------------------------------
void() func_fall2_use =
{
self.think = func_fall2_think;
self.nextthink = self.ltime + 0.1;
self.attack_finished = time + self.wait;

if (!(self.classgroup & CG_FRAMETICK))
self.classgroup |= CG_FRAMETICK;

if (self.noise != __NULL__ && self.noise != "")
sound (self, CHAN_AUTO, self.noise,
VOL_HIGH, ATTN_NORM);

// disable touch, only do this once!
self.touch = sub_null;
};

// You may have to modify your multi_touch(); command in triggers.qc
// to allow both monsters & players to activate trigger_once/multiple.
// I recommend allowing the mapper themselves to select how that
// occurs. Default behavior is player only.
#endif

//==============================================================
// Initialization
//==============================================================

#ifdef SSQC
//--------------------------------------------------------------
void(string key, string value) func_fall2_init_field =
{
switch (key)
{
case "lip":
// rewrite .lip to .speed2 -- CEV
self.speed2 = stof (value);
break;
}
};
#endif

#if defined(CSQC) || defined(SSQC)
//--------------------------------------------------------------
void(entity e) func_fall2_init =
{
e.classname = "func_fall2";
e.classtype = CT_FUNC_FALL2;

#ifdef CSQC
setmodelindex (e, e.modelindex);
setsize (e, e.mins, e.maxs);
setorigin (e, e.origin);
e.drawmask = DRAWMASK_NORMAL;
e.predraw = base_func_predraw;
#endif

#ifdef SSQC
if (e.spawnflags & SPAWNFLAG_FUNC_FALL2_BREAKABLE)
{
// dont fade if set to break -- VR
e.pain_finished = -1;

if (!e.health)
e.health = 20;
if (!e.count)
// was 6 dumptruck_ds
e.count = 5;

// will handle sound precaches -- CEV
base_breakable_init (e);
}
else
{
base_func_init (e);
}

// This is a hack to have monsters be able to trigger it
// by fake touch - Thanks to Nahuel

// Don't spawn on player only or if I'm a targetable
if (!(e.spawnflags & SPAWNFLAG_FUNC_FALL2_PLAYER_TRIGGERED) &&
!(e.targetname))
{
// Link 'em -- modified to use a helper class -- CEV
e.trigger_field = spawn_temp_fall2_field (e,
e.absmin, e.absmax + '0 0 8');
}

if (e.noise != __NULL__ && e.noise != "")
precache_sound (e.noise);
if (e.noise2 != __NULL__ && e.noise2 != "")
precache_sound (e.noise2);

e.alpha = 1.0;
e.solid = SOLID_BSP;
e.movetype = MOVETYPE_PUSH;

if (!e.pain_finished)
e.pain_finished = 0.01;

if (!e.targetname)
// .touch in this instance is for players only
e.touch = func_fall2_touch;

if (!e.speed)
e.speed = 10;

// was .lip -- CEV
if (!e.speed2)
e.speed2 = -800;

if (e.avelocity)
{
// store it
e.pos1 = e.avelocity;
e.avelocity = '0 0 0';
}

e.use = func_fall2_use;
setmodel (e, e.model);

e.tick = base_func_neteval;
e.SendEntity = base_entity_netsend;
e.SendFlags = NETFLAG_BASE_ENTITY_FULLSEND;
#endif
};
#endif

#ifdef SSQC
//--------------------------------------------------------------
void() func_fall2 =
{
BASE_FUNC_PREINIT (func_fall2_init_field)
func_fall2_init (self);
};
#endif
// };

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

Log fall2.qc

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