mirror of
https://github.com/id-Software/quake-rerelease-qc.git
synced 2024-11-13 00:34:16 +00:00
285 lines
7.4 KiB
C++
285 lines
7.4 KiB
C++
/* Copyright (C) 1996-2022 id Software LLC
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
See file, 'COPYING', for details.
|
|
*/
|
|
|
|
/************\
|
|
* BreakChain *
|
|
\************/
|
|
|
|
void (entity Head) BreakChain =
|
|
{
|
|
local entity link;
|
|
|
|
link = Head.goalentity;
|
|
while (link != world)
|
|
{
|
|
Head = link.goalentity;
|
|
remove (link);
|
|
link = Head;
|
|
}
|
|
};
|
|
|
|
/*********\
|
|
* LinkPos *
|
|
\*********/
|
|
|
|
void () LinkPos =
|
|
{
|
|
makevectors (self.enemy.angles);
|
|
setorigin (self, self.owner.origin + ( ( ( self.enemy.origin +
|
|
(v_up * 16 * (!self.enemy.button2)) + (v_forward * 16) ) - self.owner.origin ) *
|
|
( self.weapon ) ) );
|
|
self.nextthink = time + 0.1;
|
|
};
|
|
|
|
/**************\
|
|
* GrappleTrail *
|
|
\**************/
|
|
|
|
void (entity head, entity tail) GrappleTrail =
|
|
{
|
|
// offset the hook beam by a bit to line up with the notch on the model
|
|
local vector start = head.origin;
|
|
makevectors(head.angles);
|
|
local vector offset = v_forward * -7;
|
|
offset.z *= -1; // z axis from makevectors is inverted
|
|
start += offset;
|
|
// draw_sphere(start, 1, 42, 0.1, 1);
|
|
|
|
// draw a line to the hook
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_BEAM);
|
|
WriteEntity (MSG_BROADCAST, head);
|
|
WriteCoord (MSG_BROADCAST, start_x);
|
|
WriteCoord (MSG_BROADCAST, start_y);
|
|
WriteCoord (MSG_BROADCAST, start_z);
|
|
WriteCoord (MSG_BROADCAST, tail.origin_x);
|
|
WriteCoord (MSG_BROADCAST, tail.origin_y);
|
|
WriteCoord (MSG_BROADCAST, tail.origin_z + 16);
|
|
};
|
|
|
|
/************\
|
|
* HookVanish *
|
|
\************/
|
|
|
|
void () HookVanish =
|
|
{
|
|
self.owner.hook_out = FALSE;
|
|
self.owner.hook_pulling = FALSE;
|
|
/*
|
|
if (self.enemy.classname == "player")
|
|
self.enemy.attack_finished = time + 0.1;
|
|
*/
|
|
// sound(self.owner, CHAN_WEAPON, "weapons/bounce2.wav", 1, ATTN_NORM);
|
|
BreakChain (self);
|
|
remove (self);
|
|
};
|
|
|
|
void() UnHookPlayer =
|
|
{
|
|
local entity oself;
|
|
|
|
if (self.hook_out) {
|
|
oself = self;
|
|
self = self.goalentity;
|
|
HookVanish();
|
|
self = oself;
|
|
}
|
|
};
|
|
|
|
/**********\
|
|
* HookPull *
|
|
\**********/
|
|
|
|
void () HookPull =
|
|
{
|
|
local vector vel, spray;
|
|
local float v, dorg;
|
|
|
|
self.owner.hook_pulling = TRUE;
|
|
|
|
if ((!self.owner.button0 && (self.owner.weapon == IT_HOOK)) ||
|
|
(self.owner.teleport_time > time ) || self.owner.deadflag ) {
|
|
HookVanish();
|
|
return;
|
|
} else {
|
|
if (self.enemy.takedamage) {
|
|
// don't hurt teammates
|
|
if (self.enemy.classname != "player" || !teamplay ||
|
|
self.enemy.lastteam != self.owner.lastteam) {
|
|
|
|
// 4.1, if we can't see our enemy, unlock
|
|
if (!CanDamage(self.enemy, self.owner)) {
|
|
HookVanish();
|
|
return;
|
|
}
|
|
|
|
sound (self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM);
|
|
T_Damage (self.enemy, self, self.owner, 1);
|
|
makevectors (self.v_angle);
|
|
spray_x = 100 * crandom();
|
|
spray_y = 100 * crandom();
|
|
spray_z = 100 * crandom() + 50;
|
|
SpawnBlood (self.origin, spray, 20);
|
|
}
|
|
if (self.enemy.solid == SOLID_SLIDEBOX) {
|
|
self.velocity = '0 0 0';
|
|
setorigin (self, self.enemy.origin +
|
|
self.enemy.mins +
|
|
(self.enemy.size * 0.5));
|
|
} else {
|
|
self.velocity = self.enemy.velocity;
|
|
}
|
|
} else {
|
|
self.velocity = self.enemy.velocity;
|
|
}
|
|
if (self.enemy.solid == SOLID_NOT) {
|
|
HookVanish();
|
|
return;
|
|
}
|
|
makevectors (self.owner.angles);
|
|
vel = self.origin - ( self.owner.origin + (v_up * 16 *
|
|
(!self.owner.button2)) + (v_forward * 16));
|
|
v = vlen (vel);
|
|
if (v <= 100)
|
|
vel = normalize(vel) * v * 10;
|
|
if ( v > 100 )
|
|
vel = normalize(vel) * 1000;
|
|
|
|
// custom assets are always enabled
|
|
dorg = vlen(self.owner.origin - self.dest);
|
|
if (dorg > 10 && self.style == 3) {
|
|
// sound(self.owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM);
|
|
self.style = 2;
|
|
}
|
|
if (dorg < 10 && self.style == 2) {
|
|
// sound(self.owner, CHAN_WEAPON, "weapons/chain3.wav", 1, ATTN_NORM);
|
|
self.style = 3;
|
|
}
|
|
|
|
self.owner.velocity = vel;
|
|
self.dest = self.owner.origin;
|
|
self.nextthink = time + 0.1;
|
|
}
|
|
};
|
|
|
|
/**************\
|
|
* T_ChainTouch *
|
|
\**************/
|
|
|
|
void() T_ChainTouch =
|
|
{
|
|
if (other == self.owner)
|
|
return; // don't attach to owner
|
|
|
|
if (pointcontents(self.origin) == CONTENT_SKY) {
|
|
HookVanish();
|
|
return;
|
|
}
|
|
|
|
if (other.classname == "player" && teamplay &&
|
|
other.team == self.owner.lastteam)
|
|
return; // just pass through teammates
|
|
|
|
if (other.takedamage) {
|
|
// don't damage teammates
|
|
if (other.classname == "player")
|
|
other.axhitme = 1; // make axe noise
|
|
else
|
|
sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
|
|
T_Damage (other, self, self.owner, 10 );
|
|
SpawnBlood (self.origin, self.velocity, 10);
|
|
} else {
|
|
sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
|
|
self.avelocity = '0 0 0';
|
|
}
|
|
|
|
if (!self.owner.button0) {
|
|
HookVanish();
|
|
return;
|
|
} else {
|
|
if (other.solid == SOLID_SLIDEBOX) {
|
|
setorigin (self, other.origin + other.mins +
|
|
(other.size * 0.5));
|
|
self.velocity = '0 0 0';
|
|
} else {
|
|
self.velocity = other.velocity;
|
|
}
|
|
self.weapon = other.nextthink - time;
|
|
// if (teamplay & TEAM_CAPTURE_CUSTOM)
|
|
// sound (self.owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM);
|
|
|
|
self.style = 2;
|
|
self.enemy = other;
|
|
self.nextthink = time + 0.1;
|
|
self.think = HookPull;
|
|
self.touch = SUB_Null;
|
|
}
|
|
};
|
|
|
|
void() T_ChainThink =
|
|
{
|
|
if (time >= self.hook_fire_time + 5) {
|
|
HookVanish();
|
|
}
|
|
|
|
if (!self.owner.button0 && self.owner.weapon == IT_HOOK) {
|
|
HookVanish();
|
|
return;
|
|
}
|
|
|
|
self.nextthink = time + 0.1;
|
|
}
|
|
|
|
/*************\
|
|
* W_FireChain *
|
|
\*************/
|
|
|
|
void() W_FireChain =
|
|
{
|
|
local entity hook;
|
|
|
|
self.hook_out = TRUE;
|
|
hook = spawn ();
|
|
hook.owner = self;
|
|
self.goalentity = hook;
|
|
hook.movetype = MOVETYPE_FLY;
|
|
hook.solid = SOLID_BBOX;
|
|
|
|
// set hook speed
|
|
|
|
makevectors (self.v_angle);
|
|
hook.velocity = aim(self, 1000);
|
|
hook.velocity = hook.velocity * 800;
|
|
hook.angles = vectoangles(hook.velocity);
|
|
hook.avelocity = '0 0 -500';
|
|
|
|
hook.touch = T_ChainTouch;
|
|
|
|
// set hook sound
|
|
hook.hook_fire_time = time;
|
|
hook.nextthink = time + 0.1;
|
|
hook.think = T_ChainThink;
|
|
|
|
setmodel (hook, "progs/star.mdl");
|
|
setsize (hook, '0 0 0', '0 0 0');
|
|
setorigin (hook, self.origin + (v_forward*16) + '0 0 16' );
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/chain1.wav", 1, ATTN_NORM);
|
|
};
|
|
|