Git Repos / fte_dogmode / qc / triggers / push.qc
Last update to this file was on 2024-04-08 at 15:40.
Show push.qc
////////////////////////////////////////////////////////////////////////////////
// trigger_push -- id1 with additions by dumptruck_ds & CEV
////////////////////////////////////////////////////////////////////////////////
//======================================================================
// constants
//======================================================================
const float TRIGGER_PUSH_ONCE = 1; // only trigger once
const float TRIGGER_PUSH_STARTOFF = 8; // trigger will start off
const float TRIGGER_PUSH_SILENT = 16; // push silently
const float TRIGGER_PUSH_NOISE = 32; // use custom sound via noise key/value
//======================================================================
// forward declarations
//======================================================================
vector(float a, float b, float c) solve_quadratic;
// base_trigger_push
vector(vector org, entity tgt, float ht) base_trigger_push_calculatevelocity;
void() base_trigger_push_findtarget;
void() base_trigger_push_touch;
// trigger_push
// void() trigger_push_use;
void(entity e) trigger_push_init;
void() trigger_push;
// trigger_push_custom
void() trigger_push_custom_use;
void(entity e) trigger_push_custom_init;
void() trigger_push_custom;
//------------------------------------------------------------------------------
//----------------------------------------------------------------------
// solve_quadratic -- from Nexuiz source code; original can be found at
// https://github.com/smlinux/nexuiz/blob/master/data/qcsrc/common/util.qc
//----------------------------------------------------------------------
vector(float a, float b, float c) solve_quadratic =
{
// ax^2 + bx + c = 0
vector v = '0 0 0';
float D;
if (a == 0)
{
if (b != 0)
{
v_x = v_y = -c / b;
v_z = 1;
}
else
{
if (c == 0)
{
// actually, every number solves the equation!
v_z = 1;
}
}
}
else
{
D = b * b - 4 * a * c;
if (D >= 0)
{
D = sqrt (D);
if (a > 0)
{
// put the smaller solution first
v_x = ((-b) - D) / (2 * a);
v_y = ((-b) + D) / (2 * a);
}
else
{
v_x = (-b + D) / (2 * a);
v_y = (-b - D) / (2 * a);
}
v_z = 1;
}
else
{
// complex solutions!
D = sqrt (-D);
v_x = -b / (2 * a);
if (a > 0)
v_y = D / (2 * a);
else
v_y = -D / (2 * a);
v_z = 0;
}
}
return v;
};
//----------------------------------------------------------------------
// class base_trigger_push: base_trigger
// {
//--------------------------------------------------------------
// trigger_push_calculatevelocity
//
// Arguments:
// org - origin of the object which is to be pushed
// tgt - target entity (can be either a point or a model entity;
// if it is the latter, its midpoint is used)
// ht - jump height, measured from the higher one of org and tgt's
// midpoint
//
// Returns: velocity for the jump
// the global trigger_push_calculatevelocity_flighttime is set to the
// total jump time
//
// copied from Nexuiz source code; original can be found here:
// github.com/smlinux/nexuiz/blob/master/data/qcsrc/server/t_jumppads.qc
//--------------------------------------------------------------
vector(vector org, entity tgt, float ht)
base_trigger_push_calculatevelocity =
{
local float sdist, zdist, vs, vz, jumpheight;
local vector sdir, torg;
local vector solution;
local float flighttime;
torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
zdist = torg_z - org_z;
sdist = vlen (torg - org - zdist * '0 0 1');
sdir = normalize (torg - org - zdist * '0 0 1');
// how high do we need to push the player?
jumpheight = fabs (ht);
if (zdist > 0)
jumpheight = jumpheight + zdist;
/*
STOP.
You will not understand the following equations anyway...
But here is what I did to get them.
I used the functions
s(t) = t * vs
z(t) = t * vz - 1/2 grav t^2
and solved for:
s(ti) = sdist
z(ti) = zdist
max(z, ti) = jumpheight
From these three equations, you will find the three
parameters vs, vz and ti.
*/
// push him so high... NOTE: sqrt(positive)!
vz = sqrt (2 * world_gravity * jumpheight);
// we start with downwards velocity only if it's a downjump
// and the jump apex should be outside the jump!
if (ht < 0)
if (zdist < 0)
vz = -vz;
// equation "z(ti) = zdist"
solution = solve_quadratic (0.5 * world_gravity, -vz, zdist);
// ALWAYS solvable because jumpheight >= zdist
if (!solution_z)
// just in case it is not solvable due to roundoff
// errors, assume two equal solutions at their center
// (this is mainly for the usual case with ht == 0)
solution_y = solution_x;
if (zdist == 0)
// solution_x is 0 in this case, so don't use it, but
// rather use solution_y (which will be
// sqrt(0.5 * jumpheight / grav), actually)
solution_x = solution_y;
if (zdist < 0)
{
// down-jump
if (ht < 0)
{
// almost straight line type
// jump apex is before the jump
// we must take the larger one
flighttime = solution_y;
}
else
{
// regular jump
// jump apex is during the jump
// we must take the larger one too
flighttime = solution_y;
}
}
else
{
// up-jump
if (ht < 0)
{
// almost straight line type
// jump apex is after the jump
// we must take the smaller one
flighttime = solution_x;
}
else
{
// regular jump
// jump apex is during the jump
// we must take the larger one
flighttime = solution_y;
}
}
vs = sdist / flighttime;
// finally calculate the velocity
return sdir * vs + '0 0 1' * vz;
};
//--------------------------------------------------------------
void() base_trigger_push_findtarget =
{
self.enemy = find (world, targetname, self.target);
if (self.enemy)
{
local vector org;
org = (self.absmin + self.absmax) * 0.5;
org_z = self.absmax_z - -24; // - PL_MIN_z;
self.movedir = base_trigger_push_calculatevelocity (
org, self.enemy, self.height);
}
};
//--------------------------------------------------------------
void() base_trigger_push_touch =
{
if (self.estate != STATE_ACTIVE)
return;
// from Copper -- dumptruck_ds
if (other.movetype == MOVETYPE_NOCLIP)
return;
// try to find target again if necessary
if (self.target && (!self.enemy))
base_trigger_push_findtarget ();
// we have a target, set movedir accordingly
if (self.target && self.enemy)
self.movedir = base_trigger_push_calculatevelocity (
other.origin, self.enemy, self.height);
if (other.classtype == CT_PROJECTILE_GRENADE)
{
if (self.target && self.enemy)
other.velocity = self.movedir;
else
other.velocity = self.speed * self.movedir * 10;
}
else if (other.health > 0)
{
if (self.target && self.enemy)
other.velocity = self.movedir;
else
other.velocity = self.speed * self.movedir * 10;
if (other.classtype == CT_PLAYER &&
!(self.spawnflags & TRIGGER_PUSH_SILENT))
{
if (other.fly_sound < time)
{
if (!(self.spawnflags &
TRIGGER_PUSH_NOISE))
{
other.fly_sound = time + 1.5;
sound (other, CHAN_AUTO,
"ambience/windfly.wav",
1, ATTN_NORM);
}
else
{
other.fly_sound = time + 1.5;
sound (other, CHAN_AUTO,
self.noise,
1, ATTN_NORM);
}
}
}
}
if (self.spawnflags & TRIGGER_PUSH_ONCE)
remove (self);
};
// };
/*QUAKED trigger_push (.5 .5 .5) ? TRIGGER_PUSH_ONCE 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
Pushes the player
*/
//----------------------------------------------------------------------
// class trigger_push: base_trigger_push
// {
//--------------------------------------------------------------
// dumptruck_ds
//--------------------------------------------------------------
/*
void() trigger_push_use =
{
self.is_waiting = !self.is_waiting;
}
*/
//--------------------------------------------------------------
void(entity e) trigger_push_init =
{
e.classname = "trigger_push";
e.classtype = CT_TRIGGER_PUSH;
e.touch = base_trigger_push_touch;
base_trigger_init (e);
precache_sound ("ambience/windfly.wav");
if (!e.speed)
e.speed = 1000;
if (e.target != __NULL__ && e.target != "")
{
// attempt to find the target
base_trigger_push_findtarget ();
if (!e.enemy)
if (!e.movedir)
// TODO CEV is this up? I don't remember
e.movedir = '0 0 180';
}
sub_checkwaiting (e);
};
//--------------------------------------------------------------
void() trigger_push =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;
trigger_push_init (self);
};
// };
/*QUAKED trigger_push_custom (.5 .5 .5) ? TRIGGER_PUSH_ONCE TRIGGER_PUSH_STARTOFF TRIGGER_PUSH_SILENT 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
dumptruck_ds
trigger_push_custom is a new entity. This can be used to create traps,
jumppads, currents in water and more.
If TRIGGER_PUSH_STARTOFF flag is set, this disables the trigger. This can
be targeted and toggled off and on. If the TRIGGER_PUSH_SILENT flag is set
it won't make the windfly sound. Use TRIGGER_PUSH_NOISE spawnflag and the
noise key/value to use a custom push sound. Custom sounds should be "one
off" sounds NOT be looping.
Adapted from Hipnotic's func_togglewall
*/
//----------------------------------------------------------------------
// class trigger_push_custom: base_trigger_push
// {
//--------------------------------------------------------------
// dumptruck_ds was based on hipnotic blocker_use now Alkaline estate
//--------------------------------------------------------------
void() trigger_push_custom_use =
{
if (self.estate != STATE_ACTIVE)
self.estate = STATE_ACTIVE;
else
self.estate = STATE_INACTIVE;
};
//--------------------------------------------------------------
void(entity e) trigger_push_custom_init =
{
e.classname = "trigger_push_custom";
e.classtype = CT_TRIGGER_PUSH_CUSTOM;
e.touch = base_trigger_push_touch;
e.use = trigger_push_custom_use;
base_trigger_init (e);
precache_sound ("ambience/windfly.wav");
if (e.spawnflags & TRIGGER_PUSH_STARTOFF)
e.estate = STATE_INACTIVE;
if (e.noise != "")
precache_sound (e.noise);
if (!e.speed)
e.speed = 1000;
if (e.target != __NULL__ && e.target != "")
{
// attempt to find the target
base_trigger_push_findtarget ();
if (!e.enemy)
if (!e.movedir)
// TODO CEV is this up? I don't remember
e.movedir = '0 0 180';
}
sub_checkwaiting (e);
};
//--------------------------------------------------------------
void() trigger_push_custom =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;
trigger_push_custom_init (self);
};
// };
Return to the top of this page or return to the overview of this repo.
Log push.qc
Date | Commit Message | Author | + | - |
---|---|---|---|---|
2024-04-08 | Registered monsters, projectile bugfixes | cev | +1 | -1 |
2024-03-24 | 2nd pass refactor, rework QC class structure | cev | +130 | -90 |
2024-02-27 | Bullet projectile, pmove changes, misc | cev | +1 | |
2024-02-18 | Client/player, projectiles, entrypoints refactor | cev | +4 | -6 |
2024-01-31 | Class based monster refactor & start projectiles | cev | +26 | -11 |
2024-01-09 | Continue OO / Class-based refactor | cev | +32 | -37 |
2023-12-09 | Start OO / class-based refactor, work on items | cev | +229 | -225 |
2023-11-20 | changes to movement, build environment, file reorg | cev | +1 | -61 |
2023-11-16 | pmove bug fixes, moved q3 compat code, cleanup | cev | +429 |
Return to the top of this page or return to the overview of this repo.