mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-22 12:41:21 +00:00
game: sync ctf g_{chase,func,items,misc,weapon}
This commit is contained in:
parent
c41b72125a
commit
9947744114
14 changed files with 751 additions and 11851 deletions
12
Makefile
12
Makefile
|
@ -1481,12 +1481,12 @@ CTF_OBJS_ = \
|
|||
src/common/shared/rand.o \
|
||||
src/common/shared/shared.o \
|
||||
src/ctf/g_ai.o \
|
||||
src/ctf/g_chase.o \
|
||||
src/game/g_chase.o \
|
||||
src/ctf/g_cmds.o \
|
||||
src/ctf/g_combat.o \
|
||||
src/game/g_ctf.o \
|
||||
src/ctf/g_func.o \
|
||||
src/ctf/g_items.o \
|
||||
src/game/g_func.o \
|
||||
src/game/g_items.o \
|
||||
src/game/g_newai.o \
|
||||
src/game/g_newdm.o \
|
||||
src/game/g_newfnc.o \
|
||||
|
@ -1494,8 +1494,8 @@ CTF_OBJS_ = \
|
|||
src/game/g_newtrig.o \
|
||||
src/game/g_newweap.o \
|
||||
src/ctf/g_main.o \
|
||||
src/ctf/g_misc.o \
|
||||
src/ctf/g_monster.o \
|
||||
src/game/g_misc.o \
|
||||
src/game/g_monster.o \
|
||||
src/ctf/g_phys.o \
|
||||
src/ctf/g_save.o \
|
||||
src/game/g_sphere.o \
|
||||
|
@ -1543,7 +1543,7 @@ CTF_OBJS_ = \
|
|||
src/ctf/player/hud.o \
|
||||
src/ctf/player/trail.o \
|
||||
src/ctf/player/view.o \
|
||||
src/ctf/player/weapon.o
|
||||
src/game/player/weapon.o
|
||||
|
||||
# ----------
|
||||
|
||||
|
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Chase cam.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/local.h"
|
||||
|
||||
void
|
||||
UpdateChaseCam(edict_t *ent)
|
||||
{
|
||||
vec3_t o, ownerv, goal;
|
||||
edict_t *targ;
|
||||
vec3_t forward, right;
|
||||
trace_t trace;
|
||||
int i;
|
||||
vec3_t angles;
|
||||
|
||||
/* is our chase target gone? */
|
||||
if (!ent->client->chase_target->inuse)
|
||||
{
|
||||
ent->client->chase_target = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
targ = ent->client->chase_target;
|
||||
|
||||
VectorCopy(targ->s.origin, ownerv);
|
||||
ownerv[2] += targ->viewheight;
|
||||
VectorCopy(targ->client->v_angle, angles);
|
||||
|
||||
if (angles[PITCH] > 56)
|
||||
{
|
||||
angles[PITCH] = 56;
|
||||
}
|
||||
|
||||
AngleVectors(angles, forward, right, NULL);
|
||||
VectorNormalize(forward);
|
||||
VectorMA(ownerv, -30, forward, o);
|
||||
|
||||
if (o[2] < targ->s.origin[2] + 20)
|
||||
{
|
||||
o[2] = targ->s.origin[2] + 20;
|
||||
}
|
||||
|
||||
/* jump animation lifts */
|
||||
if (!targ->groundentity)
|
||||
{
|
||||
o[2] += 16;
|
||||
}
|
||||
|
||||
trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
|
||||
VectorCopy(trace.endpos, goal);
|
||||
|
||||
VectorMA(goal, 2, forward, goal);
|
||||
|
||||
/* pad for floors and ceilings */
|
||||
VectorCopy(goal, o);
|
||||
o[2] += 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] -= 6;
|
||||
}
|
||||
|
||||
VectorCopy(goal, o);
|
||||
o[2] -= 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] += 6;
|
||||
}
|
||||
|
||||
ent->client->ps.pmove.pm_type = PM_FREEZE;
|
||||
|
||||
VectorCopy(goal, ent->s.origin);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(
|
||||
targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
|
||||
}
|
||||
|
||||
VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
|
||||
VectorCopy(targ->client->v_angle, ent->client->v_angle);
|
||||
|
||||
ent->viewheight = 0;
|
||||
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||||
gi.linkentity(ent);
|
||||
|
||||
if ((!ent->client->showscores && !ent->client->menu &&
|
||||
!ent->client->showinventory && !ent->client->showhelp &&
|
||||
!(level.framenum & 31)) || ent->client->update_chase)
|
||||
{
|
||||
char s[1024];
|
||||
|
||||
ent->client->update_chase = false;
|
||||
sprintf(s, "xv 0 yb -68 string2 \"Chasing %s\"",
|
||||
targ->client->pers.netname);
|
||||
gi.WriteByte(svc_layout);
|
||||
gi.WriteString(s);
|
||||
gi.unicast(ent, false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChaseNext(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
|
||||
do
|
||||
{
|
||||
i++;
|
||||
|
||||
if (i > maxclients->value)
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
|
||||
e = g_edicts + i;
|
||||
|
||||
if (!e->inuse)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->solid != SOLID_NOT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void
|
||||
ChasePrev(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
|
||||
do
|
||||
{
|
||||
i--;
|
||||
|
||||
if (i < 1)
|
||||
{
|
||||
i = maxclients->value;
|
||||
}
|
||||
|
||||
e = g_edicts + i;
|
||||
|
||||
if (!e->inuse)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->solid != SOLID_NOT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
2584
src/ctf/g_func.c
2584
src/ctf/g_func.c
File diff suppressed because it is too large
Load diff
2911
src/ctf/g_items.c
2911
src/ctf/g_items.c
File diff suppressed because it is too large
Load diff
2466
src/ctf/g_misc.c
2466
src/ctf/g_misc.c
File diff suppressed because it is too large
Load diff
1480
src/ctf/g_monster.c
1480
src/ctf/g_monster.c
File diff suppressed because it is too large
Load diff
485
src/ctf/g_phys.c
485
src/ctf/g_phys.c
|
@ -27,6 +27,24 @@
|
|||
|
||||
#include "header/local.h"
|
||||
|
||||
#define STOP_EPSILON 0.1
|
||||
#define MAX_CLIP_PLANES 5
|
||||
#define FRICTION 6
|
||||
#define WATERFRICTION 1
|
||||
|
||||
void SV_Physics_NewToss(edict_t *ent);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
edict_t *ent;
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
float deltayaw;
|
||||
} pushed_t;
|
||||
|
||||
static pushed_t pushed[MAX_EDICTS], *pushed_p;
|
||||
static edict_t *obstacle;
|
||||
|
||||
/*
|
||||
* pushmove objects do not obey gravity, and do not interact with each other or
|
||||
* trigger fields, but block normal movement and push normal objects when they move.
|
||||
|
@ -164,11 +182,10 @@ SV_Impact(edict_t *e1, trace_t *trace)
|
|||
|
||||
/*
|
||||
* Slide off of the impacting object
|
||||
* returns the blocked flags (1 = floor,
|
||||
* 2 = step / wall)
|
||||
* returns the blocked flags:
|
||||
* 1 = floor
|
||||
* 2 = step / wall
|
||||
*/
|
||||
#define STOP_EPSILON 0.1
|
||||
|
||||
int
|
||||
ClipVelocity(vec3_t in, vec3_t normal, vec3_t out, float overbounce)
|
||||
{
|
||||
|
@ -205,13 +222,15 @@ ClipVelocity(vec3_t in, vec3_t normal, vec3_t out, float overbounce)
|
|||
}
|
||||
|
||||
/*
|
||||
* The basic solid body movement clip that slides along multiple planes
|
||||
* Returns the clipflags if the velocity was modified (hit something solid)
|
||||
* The basic solid body movement clip
|
||||
* that slides along multiple planes
|
||||
* Returns the clipflags if the velocity
|
||||
* was modified (hit something solid)
|
||||
*
|
||||
* 1 = floor
|
||||
* 2 = wall / step
|
||||
* 4 = dead stop
|
||||
*/
|
||||
#define MAX_CLIP_PLANES 5
|
||||
int
|
||||
SV_FlyMove(edict_t *ent, float time, int mask)
|
||||
{
|
||||
|
@ -228,6 +247,11 @@ SV_FlyMove(edict_t *ent, float time, int mask)
|
|||
float time_left;
|
||||
int blocked;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
numbumps = 4;
|
||||
|
||||
blocked = 0;
|
||||
|
@ -307,14 +331,15 @@ SV_FlyMove(edict_t *ent, float time, int mask)
|
|||
VectorCopy(trace.plane.normal, planes[numplanes]);
|
||||
numplanes++;
|
||||
|
||||
/* modify original_velocity so it parallels all of the clip planes */
|
||||
/* modify original_velocity so it
|
||||
parallels all of the clip planes */
|
||||
for (i = 0; i < numplanes; i++)
|
||||
{
|
||||
ClipVelocity(original_velocity, planes[i], new_velocity, 1);
|
||||
|
||||
for (j = 0; j < numplanes; j++)
|
||||
{
|
||||
if (j != i)
|
||||
if ((j != i) && !VectorCompare(planes[i], planes[j]))
|
||||
{
|
||||
if (DotProduct(new_velocity, planes[j]) < 0)
|
||||
{
|
||||
|
@ -336,7 +361,6 @@ SV_FlyMove(edict_t *ent, float time, int mask)
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* go along the crease */
|
||||
if (numplanes != 2)
|
||||
{
|
||||
|
@ -349,8 +373,9 @@ SV_FlyMove(edict_t *ent, float time, int mask)
|
|||
VectorScale(dir, d, ent->velocity);
|
||||
}
|
||||
|
||||
/* if original velocity is against the original velocity,
|
||||
stop dead to avoid tiny occilations in sloping corners */
|
||||
/* if original velocity is against the original
|
||||
velocity, stop dead to avoid tiny occilations
|
||||
in sloping corners */
|
||||
if (DotProduct(ent->velocity, primal_velocity) <= 0)
|
||||
{
|
||||
VectorCopy(vec3_origin, ent->velocity);
|
||||
|
@ -364,7 +389,20 @@ SV_FlyMove(edict_t *ent, float time, int mask)
|
|||
void
|
||||
SV_AddGravity(edict_t *ent)
|
||||
{
|
||||
ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->gravityVector[2] > 0)
|
||||
{
|
||||
VectorMA(ent->velocity, ent->gravity * sv_gravity->value * FRAMETIME,
|
||||
ent->gravityVector, ent->velocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -384,6 +422,11 @@ RealBoundingBox(edict_t *ent, vec3_t mins, vec3_t maxs)
|
|||
vec3_t p[8];
|
||||
int i, j, k, j2, k4;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
k4 = k * 4;
|
||||
|
@ -479,13 +522,9 @@ RealBoundingBox(edict_t *ent, vec3_t mins, vec3_t maxs)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ===============================================================================
|
||||
*
|
||||
* PUSHMOVE
|
||||
*
|
||||
* ===============================================================================
|
||||
*/
|
||||
/* ================================================================== */
|
||||
|
||||
/* PUSHMOVE */
|
||||
|
||||
/*
|
||||
* Does not change the entities velocity at all
|
||||
|
@ -514,6 +553,17 @@ retry:
|
|||
|
||||
trace = gi.trace(start, ent->mins, ent->maxs, end, ent, mask);
|
||||
|
||||
/* startsolid treats different-content volumes
|
||||
as continuous, like the bbox of a monster/player
|
||||
and the floor of an elevator. So do another trace
|
||||
that only collides with BSP so that we make a best
|
||||
effort to keep these entities inside non-solid space
|
||||
*/
|
||||
if (trace.startsolid && (mask & ~MASK_SOLID))
|
||||
{
|
||||
trace = gi.trace (start, ent->mins, ent->maxs, end, ent, MASK_SOLID);
|
||||
}
|
||||
|
||||
VectorCopy(trace.endpos, ent->s.origin);
|
||||
gi.linkentity(ent);
|
||||
|
||||
|
@ -537,7 +587,8 @@ retry:
|
|||
{
|
||||
SV_Impact(ent, &trace);
|
||||
|
||||
/* if the pushed entity went away and the pusher is still there */
|
||||
/* if the pushed entity went away
|
||||
and the pusher is still there */
|
||||
if (!trace.ent->inuse && ent->inuse)
|
||||
{
|
||||
/* move the pusher back and try again */
|
||||
|
@ -547,6 +598,8 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
ent->gravity = 1.0;
|
||||
|
||||
if (ent->inuse)
|
||||
{
|
||||
G_TouchTriggers(ent);
|
||||
|
@ -555,17 +608,6 @@ retry:
|
|||
return trace;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
edict_t *ent;
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
float deltayaw;
|
||||
} pushed_t;
|
||||
|
||||
pushed_t pushed[MAX_EDICTS], *pushed_p;
|
||||
edict_t *obstacle;
|
||||
|
||||
/*
|
||||
* Objects need to be moved back on a failed push,
|
||||
* otherwise riders would continue to slide.
|
||||
|
@ -579,6 +621,11 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
|
|||
vec3_t org, org2, move2, forward, right, up;
|
||||
vec3_t realmins, realmaxs;
|
||||
|
||||
if (!pusher)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* clamp the move to 1/8 units, so the position will
|
||||
be accurate for client side prediction */
|
||||
for (i = 0; i < 3; i++)
|
||||
|
@ -623,7 +670,8 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
|
|||
rotating brush models. */
|
||||
RealBoundingBox(pusher, realmins, realmaxs);
|
||||
|
||||
/* see if any solid entities are inside the final position */
|
||||
/* see if any solid entities
|
||||
are inside the final position */
|
||||
check = g_edicts + 1;
|
||||
|
||||
for (e = 1; e < globals.num_edicts; e++, check++)
|
||||
|
@ -646,7 +694,8 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
|
|||
continue; /* not linked in anywhere */
|
||||
}
|
||||
|
||||
/* if the entity is standing on the pusher, it will definitely be moved */
|
||||
/* if the entity is standing on the pusher,
|
||||
it will definitely be moved */
|
||||
if (check->groundentity != pusher)
|
||||
{
|
||||
/* see if the ent needs to be tested */
|
||||
|
@ -660,7 +709,8 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* see if the ent's bbox is inside the pusher's final position */
|
||||
/* see if the ent's bbox is inside
|
||||
the pusher's final position */
|
||||
if (!SV_TestEntityPosition(check))
|
||||
{
|
||||
continue;
|
||||
|
@ -702,13 +752,16 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
|
|||
|
||||
if (!block)
|
||||
{
|
||||
/* pushed ok */
|
||||
/* pushed ok */
|
||||
gi.linkentity(check);
|
||||
|
||||
/* impact? */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if it is ok to leave in the old position, do it
|
||||
this is only relevent for riding entities, not pushed */
|
||||
this is only relevent for riding entities, not
|
||||
pushed */
|
||||
VectorSubtract(check->s.origin, move, check->s.origin);
|
||||
block = SV_TestEntityPosition(check);
|
||||
|
||||
|
@ -719,11 +772,12 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
|
|||
}
|
||||
}
|
||||
|
||||
/* save off the obstacle so we can call the block function */
|
||||
/* save off the obstacle so we can
|
||||
call the block function */
|
||||
obstacle = check;
|
||||
|
||||
/* move back any entities we already moved
|
||||
go backwards, so if the same entity was pushed/
|
||||
go backwards, so if the same entity was pushed
|
||||
twice, it goes back to the original position */
|
||||
for (p = pushed_p - 1; p >= pushed; p--)
|
||||
{
|
||||
|
@ -760,15 +814,21 @@ SV_Physics_Pusher(edict_t *ent)
|
|||
vec3_t move, amove;
|
||||
edict_t *part, *mv;
|
||||
|
||||
/* if not a team captain, so movement will be handled elsewhere */
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if not a team captain, so movement
|
||||
will be handled elsewhere */
|
||||
if (ent->flags & FL_TEAMSLAVE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure all team slaves can move before commiting any moves
|
||||
or calling any think functions if the move is blocked, all
|
||||
moved objects will be backed out */
|
||||
/* make sure all team slaves can move before commiting
|
||||
any moves or calling any think functions if the move
|
||||
is blocked, all moved objects will be backed out */
|
||||
pushed_p = pushed;
|
||||
|
||||
for (part = ent; part; part = part->teamchain)
|
||||
|
@ -787,14 +847,15 @@ SV_Physics_Pusher(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
if (pushed_p > &pushed[MAX_EDICTS-1])
|
||||
if (pushed_p > &pushed[MAX_EDICTS - 1])
|
||||
{
|
||||
gi.error("pushed_p > &pushed[MAX_EDICTS-1], memory corrupted");
|
||||
gi.error("pushed_p > &pushed[MAX_EDICTS - 1], memory corrupted");
|
||||
}
|
||||
|
||||
if (part)
|
||||
{
|
||||
/* the move failed, bump all nextthink times and back out moves */
|
||||
/* the move failed, bump all nextthink
|
||||
times and back out moves */
|
||||
for (mv = ent; mv; mv = mv->teamchain)
|
||||
{
|
||||
if (mv->nextthink > 0)
|
||||
|
@ -816,7 +877,11 @@ SV_Physics_Pusher(edict_t *ent)
|
|||
/* the move succeeded, so call all think functions */
|
||||
for (part = ent; part; part = part->teamchain)
|
||||
{
|
||||
SV_RunThink(part);
|
||||
/* prevent entities that are on trains that have gone away from thinking! */
|
||||
if (part->inuse)
|
||||
{
|
||||
SV_RunThink(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -829,6 +894,11 @@ SV_Physics_Pusher(edict_t *ent)
|
|||
void
|
||||
SV_Physics_None(edict_t *ent)
|
||||
{
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* regular thinking */
|
||||
SV_RunThink(ent);
|
||||
}
|
||||
|
@ -839,6 +909,11 @@ SV_Physics_None(edict_t *ent)
|
|||
void
|
||||
SV_Physics_Noclip(edict_t *ent)
|
||||
{
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* regular thinking */
|
||||
if (!SV_RunThink(ent))
|
||||
{
|
||||
|
@ -851,16 +926,13 @@ SV_Physics_Noclip(edict_t *ent)
|
|||
gi.linkentity(ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* TOSS / BOUNCE
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
/* ================================================================== */
|
||||
|
||||
/* TOSS / BOUNCE */
|
||||
|
||||
/*
|
||||
* Toss, bounce, and fly movement. When onground, do nothing.
|
||||
* Toss, bounce, and fly movement.
|
||||
* When onground, do nothing.
|
||||
*/
|
||||
void
|
||||
SV_Physics_Toss(edict_t *ent)
|
||||
|
@ -873,10 +945,22 @@ SV_Physics_Toss(edict_t *ent)
|
|||
qboolean isinwater;
|
||||
vec3_t old_origin;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* regular thinking */
|
||||
SV_RunThink(ent);
|
||||
|
||||
/* if not a team captain, so movement will be handled elsewhere */
|
||||
/* entities are very often freed during thinking */
|
||||
if (!ent->inuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if not a team captain, so movement
|
||||
will be handled elsewhere */
|
||||
if (ent->flags & FL_TEAMSLAVE)
|
||||
{
|
||||
return;
|
||||
|
@ -897,7 +981,7 @@ SV_Physics_Toss(edict_t *ent)
|
|||
}
|
||||
|
||||
/* if onground, return without moving */
|
||||
if (ent->groundentity)
|
||||
if (ent->groundentity && (ent->gravity > 0.0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -908,7 +992,8 @@ SV_Physics_Toss(edict_t *ent)
|
|||
|
||||
/* add gravity */
|
||||
if ((ent->movetype != MOVETYPE_FLY) &&
|
||||
(ent->movetype != MOVETYPE_FLYMISSILE))
|
||||
(ent->movetype != MOVETYPE_FLYMISSILE)
|
||||
&& (ent->movetype != MOVETYPE_WALLBOUNCE))
|
||||
{
|
||||
SV_AddGravity(ent);
|
||||
}
|
||||
|
@ -927,7 +1012,11 @@ SV_Physics_Toss(edict_t *ent)
|
|||
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
if (ent->movetype == MOVETYPE_BOUNCE)
|
||||
if (ent->movetype == MOVETYPE_WALLBOUNCE)
|
||||
{
|
||||
backoff = 2.0;
|
||||
}
|
||||
else if (ent->movetype == MOVETYPE_BOUNCE)
|
||||
{
|
||||
backoff = 1.5;
|
||||
}
|
||||
|
@ -938,8 +1027,14 @@ SV_Physics_Toss(edict_t *ent)
|
|||
|
||||
ClipVelocity(ent->velocity, trace.plane.normal, ent->velocity, backoff);
|
||||
|
||||
if (ent->movetype == MOVETYPE_WALLBOUNCE)
|
||||
{
|
||||
vectoangles(ent->velocity, ent->s.angles);
|
||||
}
|
||||
|
||||
/* stop if on ground */
|
||||
if (trace.plane.normal[2] > 0.7)
|
||||
if ((trace.plane.normal[2] > 0.7) &&
|
||||
(ent->movetype != MOVETYPE_WALLBOUNCE))
|
||||
{
|
||||
if ((ent->velocity[2] < 60) || (ent->movetype != MOVETYPE_BOUNCE))
|
||||
{
|
||||
|
@ -967,8 +1062,12 @@ SV_Physics_Toss(edict_t *ent)
|
|||
|
||||
if (!wasinwater && isinwater)
|
||||
{
|
||||
gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO,
|
||||
gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
/* don't play splash sound for entities already in water on level start */
|
||||
if (level.framenum > 3)
|
||||
{
|
||||
gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO,
|
||||
gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
}
|
||||
}
|
||||
else if (wasinwater && !isinwater)
|
||||
{
|
||||
|
@ -984,34 +1083,32 @@ SV_Physics_Toss(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ===============================================================================
|
||||
*
|
||||
* STEPPING MOVEMENT
|
||||
*
|
||||
* ===============================================================================
|
||||
*/
|
||||
/* ================================================================== */
|
||||
|
||||
/* STEPPING MOVEMENT */
|
||||
|
||||
/*
|
||||
* Monsters freefall when they don't have a ground entity, otherwise
|
||||
* all movement is done with discrete steps.
|
||||
* Monsters freefall when they don't have a ground
|
||||
* entity, otherwise all movement is done with
|
||||
* discrete steps.
|
||||
*
|
||||
* This is also used for objects that have become still on the ground, but
|
||||
* will fall if the floor is pulled out from under them.
|
||||
* This is also used for objects that have become
|
||||
* still on the ground, but will fall if the floor
|
||||
* is pulled out from under them.
|
||||
*/
|
||||
|
||||
#define sv_stopspeed 100
|
||||
#define sv_friction 6
|
||||
#define sv_waterfriction 1
|
||||
|
||||
void
|
||||
SV_AddRotationalFriction(edict_t *ent)
|
||||
{
|
||||
int n;
|
||||
float adjustment;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VectorMA(ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
|
||||
adjustment = FRAMETIME * sv_stopspeed * sv_friction;
|
||||
adjustment = FRAMETIME * sv_stopspeed->value * FRICTION;
|
||||
|
||||
for (n = 0; n < 3; n++)
|
||||
{
|
||||
|
@ -1046,6 +1143,13 @@ SV_Physics_Step(edict_t *ent)
|
|||
float friction;
|
||||
edict_t *groundentity;
|
||||
int mask;
|
||||
vec3_t oldorig;
|
||||
trace_t tr;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* airborn monsters should always check for ground */
|
||||
if (!ent->groundentity)
|
||||
|
@ -1072,8 +1176,8 @@ SV_Physics_Step(edict_t *ent)
|
|||
}
|
||||
|
||||
/* add gravity except:
|
||||
flying monsters
|
||||
swimming monsters who are in the water */
|
||||
- flying monsters
|
||||
- swimming monsters who are in the water */
|
||||
if (!wasonground)
|
||||
{
|
||||
if (!(ent->flags & FL_FLY))
|
||||
|
@ -1097,8 +1201,8 @@ SV_Physics_Step(edict_t *ent)
|
|||
if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
|
||||
{
|
||||
speed = fabs(ent->velocity[2]);
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
friction = sv_friction / 3;
|
||||
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
|
||||
friction = FRICTION / 3;
|
||||
newspeed = speed - (FRAMETIME * control * friction);
|
||||
|
||||
if (newspeed < 0)
|
||||
|
@ -1114,9 +1218,8 @@ SV_Physics_Step(edict_t *ent)
|
|||
if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
|
||||
{
|
||||
speed = fabs(ent->velocity[2]);
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
newspeed = speed -
|
||||
(FRAMETIME * control * sv_waterfriction * ent->waterlevel);
|
||||
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
|
||||
newspeed = speed - (FRAMETIME * control * WATERFRICTION * ent->waterlevel);
|
||||
|
||||
if (newspeed < 0)
|
||||
{
|
||||
|
@ -1129,7 +1232,7 @@ SV_Physics_Step(edict_t *ent)
|
|||
|
||||
if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
|
||||
{
|
||||
/* apply friction let dead monsters who
|
||||
/* apply friction: let dead monsters who
|
||||
aren't completely onground slide */
|
||||
if ((wasonground) || (ent->flags & (FL_SWIM | FL_FLY)))
|
||||
{
|
||||
|
@ -1140,9 +1243,9 @@ SV_Physics_Step(edict_t *ent)
|
|||
|
||||
if (speed)
|
||||
{
|
||||
friction = sv_friction;
|
||||
friction = FRICTION;
|
||||
|
||||
control = speed < sv_stopspeed ? sv_stopspeed : speed;
|
||||
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
|
||||
newspeed = speed - FRAMETIME * control * friction;
|
||||
|
||||
if (newspeed < 0)
|
||||
|
@ -1167,11 +1270,33 @@ SV_Physics_Step(edict_t *ent)
|
|||
mask = MASK_SOLID;
|
||||
}
|
||||
|
||||
VectorCopy(ent->s.origin, oldorig);
|
||||
SV_FlyMove(ent, FRAMETIME, mask);
|
||||
|
||||
/* Evil hack to work around dead parasites (and maybe other monster)
|
||||
falling through the worldmodel into the void. We copy the current
|
||||
origin (see above) and after the SV_FlyMove() was performend we
|
||||
checl if we're stuck in the world model. If yes we're undoing the
|
||||
move. */
|
||||
if (!VectorCompare(ent->s.origin, oldorig))
|
||||
{
|
||||
tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
|
||||
|
||||
if (tr.startsolid)
|
||||
{
|
||||
VectorCopy(oldorig, ent->s.origin);
|
||||
}
|
||||
}
|
||||
|
||||
gi.linkentity(ent);
|
||||
ent->gravity = 1.0;
|
||||
G_TouchTriggers(ent);
|
||||
|
||||
if (!ent->inuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->groundentity)
|
||||
{
|
||||
if (!wasonground)
|
||||
|
@ -1184,15 +1309,39 @@ SV_Physics_Step(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
if (!ent->inuse) /* g_touchtrigger free problem */
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* regular thinking */
|
||||
SV_RunThink(ent);
|
||||
}
|
||||
|
||||
/* ============================================================================ */
|
||||
/* ================================================================== */
|
||||
|
||||
void
|
||||
G_RunEntity(edict_t *ent)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t previous_origin;
|
||||
qboolean saved_origin;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->movetype == MOVETYPE_STEP)
|
||||
{
|
||||
VectorCopy(ent->s.origin, previous_origin);
|
||||
saved_origin = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
saved_origin = false;
|
||||
}
|
||||
|
||||
if (ent->prethink)
|
||||
{
|
||||
ent->prethink(ent);
|
||||
|
@ -1217,10 +1366,166 @@ G_RunEntity(edict_t *ent)
|
|||
case MOVETYPE_BOUNCE:
|
||||
case MOVETYPE_FLY:
|
||||
case MOVETYPE_FLYMISSILE:
|
||||
case MOVETYPE_WALLBOUNCE:
|
||||
SV_Physics_Toss(ent);
|
||||
break;
|
||||
case MOVETYPE_NEWTOSS:
|
||||
SV_Physics_NewToss(ent);
|
||||
break;
|
||||
default:
|
||||
gi.error("SV_Physics: bad movetype %i", (int)ent->movetype);
|
||||
}
|
||||
|
||||
/* if we moved, check and fix origin if needed */
|
||||
/* also check inuse since entities are very often freed while thinking */
|
||||
if (saved_origin && ent->inuse && !VectorCompare(ent->s.origin, previous_origin))
|
||||
{
|
||||
trace = gi.trace(ent->s.origin, ent->mins, ent->maxs,
|
||||
previous_origin, ent, MASK_MONSTERSOLID);
|
||||
|
||||
if (trace.allsolid || trace.startsolid)
|
||||
{
|
||||
VectorCopy(previous_origin, ent->s.origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Toss, bounce, and fly movement. When on ground and
|
||||
* no velocity, do nothing. With velocity, slide.
|
||||
*/
|
||||
void
|
||||
SV_Physics_NewToss(edict_t *ent)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t move;
|
||||
edict_t *slave;
|
||||
qboolean wasinwater;
|
||||
qboolean isinwater;
|
||||
float speed, newspeed;
|
||||
vec3_t old_origin;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* regular thinking */
|
||||
SV_RunThink(ent);
|
||||
|
||||
/* if not a team captain, so movement will be handled elsewhere */
|
||||
if (ent->flags & FL_TEAMSLAVE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* find out what we're sitting on. */
|
||||
VectorCopy(ent->s.origin, move);
|
||||
move[2] -= 0.25;
|
||||
trace = gi.trace(ent->s.origin, ent->mins, ent->maxs,
|
||||
move, ent, ent->clipmask);
|
||||
|
||||
if (ent->groundentity && ent->groundentity->inuse)
|
||||
{
|
||||
ent->groundentity = trace.ent;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->groundentity = NULL;
|
||||
}
|
||||
|
||||
/* if we're sitting on something flat and have no velocity of our own, return. */
|
||||
if (ent->groundentity && (trace.plane.normal[2] == 1.0) &&
|
||||
!ent->velocity[0] && !ent->velocity[1] && !ent->velocity[2])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* store the old origin */
|
||||
VectorCopy(ent->s.origin, old_origin);
|
||||
|
||||
SV_CheckVelocity(ent);
|
||||
|
||||
/* add gravity */
|
||||
SV_AddGravity(ent);
|
||||
|
||||
if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
|
||||
{
|
||||
SV_AddRotationalFriction(ent);
|
||||
}
|
||||
|
||||
/* add friction */
|
||||
speed = VectorLength(ent->velocity);
|
||||
|
||||
if (ent->waterlevel) /* friction for water movement */
|
||||
{
|
||||
newspeed = speed - (WATERFRICTION * 6 * ent->waterlevel);
|
||||
|
||||
if (newspeed < 0)
|
||||
{
|
||||
newspeed = 0;
|
||||
}
|
||||
|
||||
newspeed /= speed;
|
||||
VectorScale(ent->velocity, newspeed, ent->velocity);
|
||||
}
|
||||
else if (!ent->groundentity) /* friction for air movement */
|
||||
{
|
||||
newspeed = speed - ((FRICTION));
|
||||
|
||||
if (newspeed < 0)
|
||||
{
|
||||
newspeed = 0;
|
||||
}
|
||||
|
||||
newspeed /= speed;
|
||||
VectorScale(ent->velocity, newspeed, ent->velocity);
|
||||
}
|
||||
else /* use ground friction */
|
||||
{
|
||||
newspeed = speed - (FRICTION * 6);
|
||||
|
||||
if (newspeed < 0)
|
||||
{
|
||||
newspeed = 0;
|
||||
}
|
||||
|
||||
newspeed /= speed;
|
||||
VectorScale(ent->velocity, newspeed, ent->velocity);
|
||||
}
|
||||
|
||||
SV_FlyMove(ent, FRAMETIME, ent->clipmask);
|
||||
gi.linkentity(ent);
|
||||
|
||||
G_TouchTriggers(ent);
|
||||
|
||||
/* check for water transition */
|
||||
wasinwater = (ent->watertype & MASK_WATER);
|
||||
ent->watertype = gi.pointcontents(ent->s.origin);
|
||||
isinwater = ent->watertype & MASK_WATER;
|
||||
|
||||
if (isinwater)
|
||||
{
|
||||
ent->waterlevel = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->waterlevel = 0;
|
||||
}
|
||||
|
||||
if (!wasinwater && isinwater)
|
||||
{
|
||||
gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
}
|
||||
else if (wasinwater && !isinwater)
|
||||
{
|
||||
gi.positioned_sound(ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
|
||||
}
|
||||
|
||||
/* move teamslaves */
|
||||
for (slave = ent->teamchain; slave; slave = slave->teamchain)
|
||||
{
|
||||
VectorCopy(ent->s.origin, slave->s.origin);
|
||||
gi.linkentity(slave);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -143,6 +143,20 @@ UpdateChaseCam(edict_t *ent)
|
|||
ent->viewheight = 0;
|
||||
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||||
gi.linkentity(ent);
|
||||
|
||||
if ((!ent->client->showscores && !ent->client->menu &&
|
||||
!ent->client->showinventory && !ent->client->showhelp &&
|
||||
!(level.framenum & 31)) || ent->client->update_chase)
|
||||
{
|
||||
char s[1024];
|
||||
|
||||
ent->client->update_chase = false;
|
||||
sprintf(s, "xv 0 yb -68 string2 \"Chasing %s\"",
|
||||
targ->client->pers.netname);
|
||||
gi.WriteByte(svc_layout);
|
||||
gi.WriteString(s);
|
||||
gi.unicast(ent, false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -179,6 +193,11 @@ ChaseNext(edict_t *ent)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (e->solid != SOLID_NOT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!e->client->resp.spectator)
|
||||
{
|
||||
break;
|
||||
|
@ -224,11 +243,17 @@ ChasePrev(edict_t *ent)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (e->solid != SOLID_NOT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!e->client->resp.spectator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
|
|
|
@ -147,6 +147,11 @@ Killed(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
return;
|
||||
}
|
||||
|
||||
if (targ->health < -999)
|
||||
{
|
||||
targ->health = -999;
|
||||
}
|
||||
|
||||
/* Reset AI flag for being ducked. This fixes a corner case
|
||||
were the monster is ressurected by a medic and get's stuck
|
||||
in the next frame for mmove_t not matching the AI state. */
|
||||
|
@ -660,6 +665,15 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
qboolean
|
||||
CheckTeamDamage(edict_t *targ, edict_t *attacker)
|
||||
{
|
||||
if (ctf->value && targ->client && attacker->client)
|
||||
{
|
||||
if ((targ->client->resp.ctf_team == attacker->client->resp.ctf_team) &&
|
||||
(targ != attacker))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -786,6 +786,7 @@ plat_spawn_inside_trigger(edict_t *ent)
|
|||
|
||||
tmin[0] = ent->mins[0] + 25;
|
||||
tmin[1] = ent->mins[1] + 25;
|
||||
tmin[2] = ent->mins[2];
|
||||
|
||||
tmax[0] = ent->maxs[0] - 25;
|
||||
tmax[1] = ent->maxs[1] - 25;
|
||||
|
@ -1701,7 +1702,11 @@ SP_func_rotating(edict_t *ent)
|
|||
}
|
||||
|
||||
ent->use = rotating_use;
|
||||
ent->blocked = rotating_blocked;
|
||||
|
||||
if (ent->dmg)
|
||||
{
|
||||
ent->blocked = rotating_blocked;
|
||||
}
|
||||
|
||||
if (ent->spawnflags & 1)
|
||||
{
|
||||
|
|
|
@ -163,14 +163,25 @@ DoRespawn(edict_t *ent)
|
|||
|
||||
master = ent->teammaster;
|
||||
|
||||
for (count = 0, ent = master; ent; ent = ent->chain, count++)
|
||||
/* in ctf, when we are weapons stay, only the master
|
||||
of a team of weapons is spawned */
|
||||
if (ctf->value &&
|
||||
((int)dmflags->value & DF_WEAPONS_STAY) &&
|
||||
master->item && (master->item->flags & IT_WEAPON))
|
||||
{
|
||||
ent = master;
|
||||
}
|
||||
|
||||
choice = count ? randk() % count : 0;
|
||||
|
||||
for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
|
||||
else
|
||||
{
|
||||
for (count = 0, ent = master; ent; ent = ent->chain, count++)
|
||||
{
|
||||
}
|
||||
|
||||
choice = count ? randk() % count : 0;
|
||||
|
||||
for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,6 +257,20 @@ Pickup_Powerup(edict_t *ent, edict_t *other)
|
|||
{
|
||||
SetRespawn(ent, ent->item->quantity);
|
||||
}
|
||||
|
||||
if (((int)dmflags->value & DF_INSTANT_ITEMS) ||
|
||||
((ent->item->use == Use_Quad) &&
|
||||
(ent->spawnflags & DROPPED_PLAYER_ITEM)))
|
||||
{
|
||||
if ((ent->item->use == Use_Quad) &&
|
||||
(ent->spawnflags & DROPPED_PLAYER_ITEM))
|
||||
{
|
||||
quad_drop_timeout_hack =
|
||||
(ent->nextthink - level.time) / FRAMETIME;
|
||||
}
|
||||
|
||||
ent->item->use(other, ent->item);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1030,7 +1055,8 @@ Use_Invulnerability(edict_t *ent, gitem_t *item)
|
|||
ent->client->invincible_framenum = level.framenum + 300;
|
||||
}
|
||||
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"items/protect.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
@ -1279,7 +1305,8 @@ MegaHealth_think(edict_t *self)
|
|||
return;
|
||||
}
|
||||
|
||||
if (self->owner->health > self->owner->max_health)
|
||||
if ((self->owner->health > self->owner->max_health)
|
||||
&& !CTFHasRegeneration(self->owner))
|
||||
{
|
||||
self->nextthink = level.time + 1;
|
||||
self->owner->health -= 1;
|
||||
|
@ -1312,8 +1339,18 @@ Pickup_Health(edict_t *ent, edict_t *other)
|
|||
}
|
||||
}
|
||||
|
||||
if ((other->health >= 250) && (ent->count > 25))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
other->health += ent->count;
|
||||
|
||||
if ((other->health > 250) && (ent->count > 25))
|
||||
{
|
||||
other->health = 250;
|
||||
}
|
||||
|
||||
if (!(ent->style & HEALTH_IGNORE_MAX))
|
||||
{
|
||||
if (other->health > other->max_health)
|
||||
|
@ -1322,7 +1359,7 @@ Pickup_Health(edict_t *ent, edict_t *other)
|
|||
}
|
||||
}
|
||||
|
||||
if (ent->style & HEALTH_TIMED)
|
||||
if ((ent->style & HEALTH_TIMED) && !CTFHasRegeneration(other))
|
||||
{
|
||||
ent->think = MegaHealth_think;
|
||||
ent->nextthink = level.time + 5;
|
||||
|
@ -1623,6 +1660,11 @@ Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane /* unused */, csurface_
|
|||
return; /* not a grabbable item? */
|
||||
}
|
||||
|
||||
if (CTFMatchSetup())
|
||||
{
|
||||
return; /* can't pick stuff up right now */
|
||||
}
|
||||
|
||||
taken = ent->item->pickup(ent, other);
|
||||
|
||||
if (taken)
|
||||
|
@ -2251,6 +2293,14 @@ SpawnItem(edict_t *ent, gitem_t *item)
|
|||
item->drop = NULL;
|
||||
}
|
||||
|
||||
/* Don't spawn the flags unless enabled */
|
||||
if (!ctf->value && ((strcmp(ent->classname, "item_flag_team1") == 0) ||
|
||||
(strcmp(ent->classname, "item_flag_team2") == 0)))
|
||||
{
|
||||
G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
ent->item = item;
|
||||
ent->nextthink = level.time + 2 * FRAMETIME; /* items start after other solids */
|
||||
ent->think = droptofloor;
|
||||
|
@ -2262,6 +2312,13 @@ SpawnItem(edict_t *ent, gitem_t *item)
|
|||
gi.modelindex(ent->model);
|
||||
}
|
||||
|
||||
/* flags are server animated and have special handling */
|
||||
if ((strcmp(ent->classname, "item_flag_team1") == 0) ||
|
||||
(strcmp(ent->classname, "item_flag_team2") == 0))
|
||||
{
|
||||
ent->think = CTFFlagSetup;
|
||||
}
|
||||
|
||||
if (ent->spawnflags & 1)
|
||||
{
|
||||
SetTriggeredSpawn(ent);
|
||||
|
@ -2420,6 +2477,32 @@ static const gitem_t gameitemlist[] = {
|
|||
"misc/power2.wav misc/power1.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* weapon_grapple (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* always owned, never in the world
|
||||
*/
|
||||
{
|
||||
"weapon_grapple",
|
||||
NULL,
|
||||
Use_Weapon,
|
||||
NULL,
|
||||
CTFWeapon_Grapple,
|
||||
"misc/w_pkup.wav",
|
||||
NULL, 0,
|
||||
"models/weapons/grapple/tris.md2",
|
||||
"w_grapple",
|
||||
"Grapple",
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
IT_WEAPON,
|
||||
WEAP_GRAPPLE,
|
||||
NULL,
|
||||
0,
|
||||
|
||||
"weapons/grapple/grfire.wav weapons/grapple/grpull.wav weapons/grapple/grhang.wav weapons/grapple/grreset.wav weapons/grapple/grhit.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* always owned, never in the world
|
||||
|
@ -3903,6 +3986,142 @@ static const gitem_t gameitemlist[] = {
|
|||
"items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_flag_team1 (1 0.2 0) (-16 -16 -24) (16 16 32)
|
||||
*/
|
||||
{
|
||||
"item_flag_team1",
|
||||
CTFPickup_Flag,
|
||||
NULL,
|
||||
CTFDrop_Flag,
|
||||
NULL,
|
||||
"ctf/flagtk.wav",
|
||||
"players/male/flag1.md2", EF_FLAG1,
|
||||
NULL,
|
||||
"i_ctf1",
|
||||
"Red Flag",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"ctf/flagcap.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_flag_team2 (1 0.2 0) (-16 -16 -24) (16 16 32)
|
||||
*/
|
||||
{
|
||||
"item_flag_team2",
|
||||
CTFPickup_Flag,
|
||||
NULL,
|
||||
CTFDrop_Flag,
|
||||
NULL,
|
||||
"ctf/flagtk.wav",
|
||||
"players/male/flag2.md2", EF_FLAG2,
|
||||
NULL,
|
||||
"i_ctf2",
|
||||
"Blue Flag",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"ctf/flagcap.wav"
|
||||
},
|
||||
|
||||
/* Resistance Tech */
|
||||
{
|
||||
"item_tech1",
|
||||
CTFPickup_Tech,
|
||||
NULL,
|
||||
CTFDrop_Tech,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/ctf/resistance/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"tech1",
|
||||
"Disruptor Shield",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
IT_TECH,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"ctf/tech1.wav"
|
||||
},
|
||||
|
||||
/* Strength Tech */
|
||||
{
|
||||
"item_tech2",
|
||||
CTFPickup_Tech,
|
||||
NULL,
|
||||
CTFDrop_Tech,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/ctf/strength/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"tech2",
|
||||
"Power Amplifier",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
IT_TECH,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"ctf/tech2.wav ctf/tech2x.wav"
|
||||
},
|
||||
|
||||
/* Haste Tech */
|
||||
{
|
||||
"item_tech3",
|
||||
CTFPickup_Tech,
|
||||
NULL,
|
||||
CTFDrop_Tech,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/ctf/haste/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"tech3",
|
||||
"Time Accel",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
IT_TECH,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"ctf/tech3.wav"
|
||||
},
|
||||
|
||||
/* Regeneration Tech */
|
||||
{
|
||||
"item_tech4",
|
||||
CTFPickup_Tech,
|
||||
NULL,
|
||||
CTFDrop_Tech,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/ctf/regeneration/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"tech4",
|
||||
"AutoDoc",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
IT_TECH,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"ctf/tech4.wav"
|
||||
},
|
||||
|
||||
/* end of list marker */
|
||||
{NULL}
|
||||
};
|
||||
|
|
|
@ -567,6 +567,30 @@ BecomeExplosion1(edict_t *self)
|
|||
return;
|
||||
}
|
||||
|
||||
/* flags are important */
|
||||
if (strcmp(self->classname, "item_flag_team1") == 0)
|
||||
{
|
||||
CTFResetFlag(CTF_TEAM1); /* this will free self! */
|
||||
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
|
||||
CTFTeamName(CTF_TEAM1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(self->classname, "item_flag_team2") == 0)
|
||||
{
|
||||
CTFResetFlag(CTF_TEAM2); /* this will free self! */
|
||||
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
|
||||
CTFTeamName(CTF_TEAM2));
|
||||
return;
|
||||
}
|
||||
|
||||
/* techs are important too */
|
||||
if (self->item && (self->item->flags & IT_TECH))
|
||||
{
|
||||
CTFRespawnTech(self); /* this frees self! */
|
||||
return;
|
||||
}
|
||||
|
||||
gi.WriteByte(svc_temp_entity);
|
||||
gi.WriteByte(TE_EXPLOSION1);
|
||||
gi.WritePosition(self->s.origin);
|
||||
|
@ -819,6 +843,14 @@ TH_viewthing(edict_t *ent)
|
|||
|
||||
ent->s.frame = (ent->s.frame + 1) % 7;
|
||||
ent->nextthink = level.time + FRAMETIME;
|
||||
|
||||
if (ent->spawnflags)
|
||||
{
|
||||
if (ent->s.frame == 0)
|
||||
{
|
||||
ent->spawnflags = (ent->spawnflags + 1) % 4 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3029,6 +3061,8 @@ teleporter_touch(edict_t *self, edict_t *other, cplane_t *plane /* unused */,
|
|||
return;
|
||||
}
|
||||
|
||||
CTFPlayerResetGrapple(other);
|
||||
|
||||
/* unlink to make sure it can't possibly interfere with KillBox */
|
||||
gi.unlinkentity(other);
|
||||
|
||||
|
|
|
@ -824,8 +824,8 @@ Change_Weap_Animation(edict_t *ent)
|
|||
* A generic function to handle
|
||||
* the basics of weapon thinking
|
||||
*/
|
||||
void
|
||||
Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
||||
static void
|
||||
Weapon_Generic2(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
||||
int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames,
|
||||
int *fire_frames, void (*fire)(edict_t *ent))
|
||||
{
|
||||
|
@ -965,17 +965,22 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
|||
{
|
||||
if (ent->client->ps.gunframe == fire_frames[n])
|
||||
{
|
||||
if (ent->client->quad_framenum > level.framenum)
|
||||
if (!CTFApplyStrengthSound(ent))
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"items/damage3.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
else if (ent->client->double_framenum > level.framenum)
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"misc/ddamage3.wav"), 1, ATTN_NORM, 0);
|
||||
if (ent->client->quad_framenum > level.framenum)
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"items/damage3.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
else if (ent->client->double_framenum > level.framenum)
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"misc/ddamage3.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
}
|
||||
|
||||
CTFApplyHasteSound(ent);
|
||||
|
||||
fire(ent);
|
||||
break;
|
||||
}
|
||||
|
@ -993,6 +998,35 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
||||
int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames,
|
||||
int *fire_frames, void (*fire)(edict_t *ent))
|
||||
{
|
||||
int oldstate = ent->client->weaponstate;
|
||||
|
||||
Weapon_Generic2(ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
|
||||
FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
|
||||
fire_frames, fire);
|
||||
|
||||
/* run the weapon frame again if hasted */
|
||||
if ((Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0) &&
|
||||
(ent->client->weaponstate == WEAPON_FIRING))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((CTFApplyHaste(ent) ||
|
||||
((Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0) &&
|
||||
(ent->client->weaponstate != WEAPON_FIRING))) &&
|
||||
(oldstate == ent->client->weaponstate))
|
||||
{
|
||||
Weapon_Generic2(ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
|
||||
FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
|
||||
fire_frames, fire);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue