mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-10 07:12:07 +00:00
game: sync rogue g_* files
This commit is contained in:
parent
17f223eada
commit
5103bd6f72
14 changed files with 1573 additions and 14127 deletions
10
Makefile
10
Makefile
|
@ -1465,12 +1465,12 @@ ROGUE_OBJS_ = \
|
|||
src/common/shared/flash.o \
|
||||
src/common/shared/rand.o \
|
||||
src/common/shared/shared.o \
|
||||
src/rogue/g_ai.o \
|
||||
src/rogue/g_chase.o \
|
||||
src/game/g_ai.o \
|
||||
src/game/g_chase.o \
|
||||
src/game/g_cmds.o \
|
||||
src/rogue/g_combat.o \
|
||||
src/game/g_combat.o \
|
||||
src/game/g_func.o \
|
||||
src/rogue/g_items.o \
|
||||
src/game/g_items.o \
|
||||
src/game/g_main.o \
|
||||
src/game/g_misc.o \
|
||||
src/game/g_monster.o \
|
||||
|
@ -1526,7 +1526,7 @@ ROGUE_OBJS_ = \
|
|||
src/rogue/player/hud.o \
|
||||
src/rogue/player/trail.o \
|
||||
src/rogue/player/view.o \
|
||||
src/rogue/player/weapon.o \
|
||||
src/game/player/weapon.o \
|
||||
src/rogue/savegame/savegame.o
|
||||
|
||||
# ----------
|
||||
|
|
549
src/game/g_ai.c
549
src/game/g_ai.c
|
@ -37,6 +37,8 @@ static float enemy_yaw;
|
|||
qboolean FindTarget(edict_t *self);
|
||||
qboolean ai_checkattack(edict_t *self);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*
|
||||
* Called once each frame to set level.sight_client
|
||||
* to the player to be checked for in findtarget.
|
||||
|
@ -73,9 +75,8 @@ AI_SetSightClient(void)
|
|||
|
||||
ent = &g_edicts[check];
|
||||
|
||||
if (ent->inuse &&
|
||||
(ent->health > 0) &&
|
||||
!(ent->flags & FL_NOTARGET))
|
||||
if (ent->inuse && (ent->health > 0) &&
|
||||
!(ent->flags & (FL_NOTARGET | FL_DISGUISED)))
|
||||
{
|
||||
level.sight_client = ent;
|
||||
return; /* got one */
|
||||
|
@ -118,6 +119,7 @@ void
|
|||
ai_stand(edict_t *self, float dist)
|
||||
{
|
||||
vec3_t v;
|
||||
qboolean retval;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
|
@ -144,8 +146,30 @@ ai_stand(edict_t *self, float dist)
|
|||
self->monsterinfo.run(self);
|
||||
}
|
||||
|
||||
M_ChangeYaw(self);
|
||||
ai_checkattack(self);
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
|
||||
/* find out if we're going to be shooting */
|
||||
retval = ai_checkattack(self);
|
||||
|
||||
/* record sightings of player */
|
||||
if ((self->enemy) && (self->enemy->inuse) &&
|
||||
(visible(self, self->enemy)))
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.blind_fire_target);
|
||||
self->monsterinfo.trail_time = level.time;
|
||||
self->monsterinfo.blind_fire_delay = 0;
|
||||
}
|
||||
/* check retval to make sure we're not blindfiring */
|
||||
else if (!retval)
|
||||
{
|
||||
FindTarget(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -200,7 +224,8 @@ ai_walk(edict_t *self, float dist)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((self->monsterinfo.search) && (level.time > self->monsterinfo.idle_time))
|
||||
if ((self->monsterinfo.search) &&
|
||||
(level.time > self->monsterinfo.idle_time))
|
||||
{
|
||||
if (self->monsterinfo.idle_time)
|
||||
{
|
||||
|
@ -223,23 +248,69 @@ void
|
|||
ai_charge(edict_t *self, float dist)
|
||||
{
|
||||
vec3_t v;
|
||||
float ofs;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(self->enemy)
|
||||
if (!self->enemy || !self->enemy->inuse)
|
||||
{
|
||||
VectorSubtract(self->enemy->s.origin, self->s.origin, v);
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible(self, self->enemy))
|
||||
{
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.blind_fire_target);
|
||||
}
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
VectorSubtract(self->enemy->s.origin, self->s.origin, v);
|
||||
self->ideal_yaw = vectoyaw(v);
|
||||
}
|
||||
|
||||
self->ideal_yaw = vectoyaw(v);
|
||||
M_ChangeYaw(self);
|
||||
|
||||
if (dist)
|
||||
{
|
||||
M_walkmove(self, self->s.angles[YAW], dist);
|
||||
if (self->monsterinfo.aiflags & AI_CHARGING)
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
return;
|
||||
}
|
||||
|
||||
/* circle strafe support */
|
||||
if (self->monsterinfo.attack_state == AS_SLIDING)
|
||||
{
|
||||
/* if we're fighting a tesla, NEVER circle strafe */
|
||||
if ((self->enemy) && (self->enemy->classname) &&
|
||||
(!strcmp(self->enemy->classname, "tesla")))
|
||||
{
|
||||
ofs = 0;
|
||||
}
|
||||
else if (self->monsterinfo.lefty)
|
||||
{
|
||||
ofs = 90;
|
||||
}
|
||||
else
|
||||
{
|
||||
ofs = -90;
|
||||
}
|
||||
|
||||
if (M_walkmove(self, self->ideal_yaw + ofs, dist))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
|
||||
M_walkmove(self, self->ideal_yaw - ofs, dist);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_walkmove(self, self->s.angles[YAW], dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +338,10 @@ ai_turn(edict_t *self, float dist)
|
|||
return;
|
||||
}
|
||||
|
||||
M_ChangeYaw(self);
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================ */
|
||||
|
@ -360,7 +434,7 @@ visible(edict_t *self, edict_t *other)
|
|||
spot2[2] += other->viewheight;
|
||||
trace = gi.trace(spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
|
||||
|
||||
if (trace.fraction == 1.0)
|
||||
if ((trace.fraction == 1.0) || (trace.ent == other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -417,6 +491,7 @@ HuntTarget(edict_t *self)
|
|||
self->monsterinfo.stand(self);
|
||||
}
|
||||
else
|
||||
if (self->monsterinfo.run)
|
||||
{
|
||||
self->monsterinfo.run(self);
|
||||
}
|
||||
|
@ -446,6 +521,11 @@ FoundTarget(edict_t *self)
|
|||
/* let other monsters see this monster for a while */
|
||||
if (self->enemy->client)
|
||||
{
|
||||
if (self->enemy->flags & FL_DISGUISED)
|
||||
{
|
||||
self->enemy->flags &= ~FL_DISGUISED;
|
||||
}
|
||||
|
||||
level.sight_entity = self;
|
||||
level.sight_entity_framenum = level.framenum;
|
||||
level.sight_entity->light_level = 128;
|
||||
|
@ -455,6 +535,8 @@ FoundTarget(edict_t *self)
|
|||
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
|
||||
self->monsterinfo.trail_time = level.time;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.blind_fire_target);
|
||||
self->monsterinfo.blind_fire_delay = 0;
|
||||
|
||||
if (!self->combattarget)
|
||||
{
|
||||
|
@ -544,6 +626,10 @@ FindTarget(edict_t *self)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (level.disguise_violation_framenum > level.framenum)
|
||||
{
|
||||
client = level.disguise_violator;
|
||||
}
|
||||
else if (level.sound_entity_framenum >= (level.framenum - 1))
|
||||
{
|
||||
client = level.sound_entity;
|
||||
|
@ -573,6 +659,11 @@ FindTarget(edict_t *self)
|
|||
return true;
|
||||
}
|
||||
|
||||
if ((self->monsterinfo.aiflags & AI_HINT_PATH) && (coop) && (coop->value))
|
||||
{
|
||||
heardit = false;
|
||||
}
|
||||
|
||||
if (client->client)
|
||||
{
|
||||
if (client->flags & FL_NOTARGET)
|
||||
|
@ -594,7 +685,7 @@ FindTarget(edict_t *self)
|
|||
}
|
||||
else if (heardit)
|
||||
{
|
||||
if (client->owner->flags & FL_NOTARGET)
|
||||
if ((client->owner) && (client->owner->flags & FL_NOTARGET))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -694,15 +785,28 @@ FindTarget(edict_t *self)
|
|||
}
|
||||
|
||||
self->ideal_yaw = vectoyaw(temp);
|
||||
M_ChangeYaw(self);
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
|
||||
/* hunt the sound for a bit; hopefully find the real player */
|
||||
self->monsterinfo.aiflags |= AI_SOUND_TARGET;
|
||||
self->enemy = client;
|
||||
}
|
||||
|
||||
/* got one */
|
||||
FoundTarget(self);
|
||||
/* if we got an enemy, we need to bail out of
|
||||
hint paths, so take over here */
|
||||
if (self->monsterinfo.aiflags & AI_HINT_PATH)
|
||||
{
|
||||
/* this calls foundtarget for us */
|
||||
hintpath_stop(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
FoundTarget(self);
|
||||
}
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) &&
|
||||
(self->monsterinfo.sight))
|
||||
|
@ -764,7 +868,52 @@ M_CheckAttack(edict_t *self)
|
|||
/* do we have a clear shot? */
|
||||
if (tr.ent != self->enemy)
|
||||
{
|
||||
return false;
|
||||
/* we want them to go ahead and shoot at info_notnulls if they can. */
|
||||
if ((self->enemy->solid != SOLID_NOT) || (tr.fraction < 1.0))
|
||||
{
|
||||
/* if we can't see our target, and we're not
|
||||
blocked by a monster, go into blind fire
|
||||
if available */
|
||||
if ((!(tr.ent->svflags & SVF_MONSTER)) &&
|
||||
(!visible(self, self->enemy)))
|
||||
{
|
||||
if ((self->monsterinfo.blindfire) &&
|
||||
(self->monsterinfo.blind_fire_delay <= 20.0))
|
||||
{
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (level.time <
|
||||
(self->monsterinfo.trail_time +
|
||||
self->monsterinfo.blind_fire_delay))
|
||||
{
|
||||
/* wait for our time */
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* make sure we're not going to shoot a monster */
|
||||
tr = gi.trace(spot1, NULL, NULL,
|
||||
self->monsterinfo.blind_fire_target,
|
||||
self, CONTENTS_MONSTER);
|
||||
|
||||
if (tr.allsolid || tr.startsolid ||
|
||||
((tr.fraction < 1.0) &&
|
||||
(tr.ent != self->enemy)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self->monsterinfo.attack_state = AS_BLIND;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,6 +923,8 @@ M_CheckAttack(edict_t *self)
|
|||
/* don't always melee in easy mode */
|
||||
if ((skill->value == SKILL_EASY) && (randk() & 3))
|
||||
{
|
||||
/* fix for melee only monsters & strafing */
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -792,6 +943,8 @@ M_CheckAttack(edict_t *self)
|
|||
/* missile attack */
|
||||
if (!self->monsterinfo.attack)
|
||||
{
|
||||
/* fix for melee only monsters & strafing */
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -831,16 +984,51 @@ M_CheckAttack(edict_t *self)
|
|||
chance *= 2;
|
||||
}
|
||||
|
||||
if (random() < chance)
|
||||
/* go ahead and shoot every time if it's a info_notnull */
|
||||
if ((random() < chance) || (self->enemy->solid == SOLID_NOT))
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
self->monsterinfo.attack_finished = level.time + 2 * random();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* daedalus should strafe more.. this can be done
|
||||
here or in a customized check_attack code for
|
||||
the hover. */
|
||||
if (self->flags & FL_FLY)
|
||||
{
|
||||
if (random() < 0.3)
|
||||
/* originally, just 0.3 */
|
||||
float strafe_chance;
|
||||
|
||||
if (!(strcmp(self->classname, "monster_daedalus")))
|
||||
{
|
||||
strafe_chance = 0.8;
|
||||
}
|
||||
else
|
||||
{
|
||||
strafe_chance = 0.6;
|
||||
}
|
||||
|
||||
/* if enemy is tesla, never strafe */
|
||||
if ((self->enemy->classname) &&
|
||||
(!strcmp(self->enemy->classname, "tesla")))
|
||||
{
|
||||
strafe_chance = 0;
|
||||
}
|
||||
|
||||
if (random() < strafe_chance)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* do we want the monsters strafing? */
|
||||
if (random() < 0.4)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
}
|
||||
|
@ -866,7 +1054,11 @@ ai_run_melee(edict_t *self)
|
|||
}
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
M_ChangeYaw(self);
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
|
||||
if (FacingIdeal(self))
|
||||
{
|
||||
|
@ -891,25 +1083,35 @@ ai_run_missile(edict_t *self)
|
|||
}
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
M_ChangeYaw(self);
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
|
||||
if (FacingIdeal(self))
|
||||
{
|
||||
if (self->monsterinfo.attack) {
|
||||
if (self->monsterinfo.attack)
|
||||
{
|
||||
self->monsterinfo.attack(self);
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
|
||||
if ((self->monsterinfo.attack_state == AS_MISSILE) ||
|
||||
(self->monsterinfo.attack_state == AS_BLIND)) {
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Strafe sideways, but stay at
|
||||
* approximately the same range
|
||||
* aproximately the same range
|
||||
*/
|
||||
void
|
||||
ai_run_slide(edict_t *self, float distance)
|
||||
{
|
||||
float ofs;
|
||||
float angle;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
|
@ -917,15 +1119,26 @@ ai_run_slide(edict_t *self, float distance)
|
|||
}
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
M_ChangeYaw(self);
|
||||
angle = 90;
|
||||
|
||||
if (self->monsterinfo.lefty)
|
||||
{
|
||||
ofs = 90;
|
||||
ofs = angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
ofs = -90;
|
||||
ofs = -angle;
|
||||
}
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
|
||||
/* clamp maximum sideways move for non flyers to make them look less jerky */
|
||||
if (!(self->flags & FL_FLY))
|
||||
{
|
||||
distance = min(distance, 8.0);
|
||||
}
|
||||
|
||||
if (M_walkmove(self, self->ideal_yaw + ofs, distance))
|
||||
|
@ -933,8 +1146,29 @@ ai_run_slide(edict_t *self, float distance)
|
|||
return;
|
||||
}
|
||||
|
||||
/* if we're dodging, give up on it and go straight */
|
||||
if (self->monsterinfo.aiflags & AI_DODGING)
|
||||
{
|
||||
monster_done_dodge(self);
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
|
||||
M_walkmove(self, self->ideal_yaw - ofs, distance);
|
||||
|
||||
if (M_walkmove(self, self->ideal_yaw - ofs, distance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we're dodging, give up on it and go straight */
|
||||
if (self->monsterinfo.aiflags & AI_DODGING)
|
||||
{
|
||||
monster_done_dodge(self);
|
||||
}
|
||||
|
||||
/* the move failed, so signal the caller (ai_run) to try going straight */
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -974,6 +1208,7 @@ qboolean
|
|||
ai_checkattack(edict_t *self)
|
||||
{
|
||||
vec3_t temp;
|
||||
qboolean retval;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
|
@ -1037,6 +1272,14 @@ ai_checkattack(edict_t *self)
|
|||
self->oldenemy = NULL;
|
||||
HuntTarget(self);
|
||||
}
|
||||
else if (self->monsterinfo.last_player_enemy &&
|
||||
(self->monsterinfo.last_player_enemy->health > 0))
|
||||
{
|
||||
self->enemy = self->monsterinfo.last_player_enemy;
|
||||
self->oldenemy = NULL;
|
||||
self->monsterinfo.last_player_enemy = NULL;
|
||||
HuntTarget(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->movetarget)
|
||||
|
@ -1068,6 +1311,10 @@ ai_checkattack(edict_t *self)
|
|||
{
|
||||
self->monsterinfo.search_time = level.time + 5;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
|
||||
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
|
||||
self->monsterinfo.trail_time = level.time;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.blind_fire_target);
|
||||
self->monsterinfo.blind_fire_delay = 0;
|
||||
}
|
||||
|
||||
/* look for other coop players here */
|
||||
|
@ -1087,26 +1334,38 @@ ai_checkattack(edict_t *self)
|
|||
enemy_yaw = vectoyaw(temp);
|
||||
}
|
||||
|
||||
if (self->monsterinfo.attack_state == AS_MISSILE)
|
||||
retval = self->monsterinfo.checkattack(self);
|
||||
|
||||
if (retval)
|
||||
{
|
||||
ai_run_missile(self);
|
||||
return true;
|
||||
if (self->monsterinfo.attack_state == AS_MISSILE)
|
||||
{
|
||||
ai_run_missile(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->monsterinfo.attack_state == AS_MELEE)
|
||||
{
|
||||
ai_run_melee(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* added so monsters can shoot blind */
|
||||
if (self->monsterinfo.attack_state == AS_BLIND)
|
||||
{
|
||||
ai_run_missile(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if enemy is not currently visible,
|
||||
we will never attack */
|
||||
if (!enemy_vis)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->monsterinfo.attack_state == AS_MELEE)
|
||||
{
|
||||
ai_run_melee(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if enemy is not currently visible,
|
||||
we will never attack */
|
||||
if (!enemy_vis)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return self->monsterinfo.checkattack(self);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1126,6 +1385,10 @@ ai_run(edict_t *self, float dist)
|
|||
vec3_t v_forward, v_right;
|
||||
float left, center, right;
|
||||
vec3_t left_target, right_target;
|
||||
qboolean retval;
|
||||
qboolean alreadyMoved = false;
|
||||
qboolean gotcha = false;
|
||||
edict_t *realEnemy;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
|
@ -1139,6 +1402,79 @@ ai_run(edict_t *self, float dist)
|
|||
return;
|
||||
}
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_DUCKED)
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_DUCKED;
|
||||
}
|
||||
|
||||
if (self->maxs[2] != self->monsterinfo.base_height)
|
||||
{
|
||||
monster_duck_up(self);
|
||||
}
|
||||
|
||||
/* if we're currently looking for a hint path */
|
||||
if (self->monsterinfo.aiflags & AI_HINT_PATH)
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
|
||||
if (!self->inuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* first off, make sure we're looking for
|
||||
the player, not a noise he made */
|
||||
if (self->enemy)
|
||||
{
|
||||
if (self->enemy->inuse)
|
||||
{
|
||||
if (strcmp(self->enemy->classname, "player_noise") != 0)
|
||||
{
|
||||
realEnemy = self->enemy;
|
||||
}
|
||||
else if (self->enemy->owner)
|
||||
{
|
||||
realEnemy = self->enemy->owner;
|
||||
}
|
||||
else /* uh oh, can't figure out enemy, bail */
|
||||
{
|
||||
self->enemy = NULL;
|
||||
hintpath_stop(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->enemy = NULL;
|
||||
hintpath_stop(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hintpath_stop(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible(self, realEnemy))
|
||||
{
|
||||
gotcha = true;
|
||||
}
|
||||
else if (coop->value)
|
||||
{
|
||||
FindTarget(self);
|
||||
}
|
||||
|
||||
/* if we see the player, stop following hintpaths. */
|
||||
if (gotcha)
|
||||
{
|
||||
/* disconnect from hintpaths and start looking normally for players. */
|
||||
hintpath_stop(self);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
|
||||
{
|
||||
/* Special case: Some projectiles like grenades or rockets are
|
||||
|
@ -1151,16 +1487,23 @@ ai_run(edict_t *self, float dist)
|
|||
if (self->enemy)
|
||||
{
|
||||
VectorSubtract(self->s.origin, self->enemy->s.origin, v);
|
||||
}
|
||||
|
||||
if (VectorLength(v) < 64)
|
||||
{
|
||||
self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
|
||||
self->monsterinfo.stand(self);
|
||||
return;
|
||||
}
|
||||
if ((!self->enemy) || (VectorLength(v) < 64))
|
||||
{
|
||||
self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
|
||||
self->monsterinfo.stand(self);
|
||||
return;
|
||||
}
|
||||
|
||||
M_MoveToGoal(self, dist);
|
||||
/* prevent double moves for sound_targets */
|
||||
alreadyMoved = true;
|
||||
|
||||
if (!self->inuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FindTarget(self))
|
||||
{
|
||||
|
@ -1168,30 +1511,117 @@ ai_run(edict_t *self, float dist)
|
|||
}
|
||||
}
|
||||
|
||||
if (ai_checkattack(self))
|
||||
retval = ai_checkattack(self);
|
||||
|
||||
/* don't strafe if we can't see our enemy */
|
||||
if ((!enemy_vis) && (self->monsterinfo.attack_state == AS_SLIDING))
|
||||
{
|
||||
return;
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
|
||||
/* unless we're dodging (dodging out of view looks smart) */
|
||||
if (self->monsterinfo.aiflags & AI_DODGING)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
}
|
||||
|
||||
if (self->monsterinfo.attack_state == AS_SLIDING)
|
||||
{
|
||||
ai_run_slide(self, dist);
|
||||
/* protect against double moves */
|
||||
if (!alreadyMoved)
|
||||
{
|
||||
ai_run_slide(self, dist);
|
||||
}
|
||||
|
||||
/* we're using attack_state as the return value out of
|
||||
ai_run_slide to indicate whether or not the move
|
||||
succeeded. If the move succeeded, and we're still
|
||||
sliding, we're done in here (since we've had our
|
||||
chance to shoot in ai_checkattack, and have moved).
|
||||
if the move failed, our state is as_straight, and
|
||||
it will be taken care of below */
|
||||
if ((!retval) && (self->monsterinfo.attack_state == AS_SLIDING))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (self->monsterinfo.aiflags & AI_CHARGING)
|
||||
{
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
|
||||
if (!(self->monsterinfo.aiflags & AI_MANUAL_STEERING))
|
||||
{
|
||||
M_ChangeYaw(self);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
{
|
||||
if ((dist != 0) && (!alreadyMoved) &&
|
||||
(self->monsterinfo.attack_state == AS_STRAIGHT) &&
|
||||
(!(self->monsterinfo.aiflags & AI_STAND_GROUND)))
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
}
|
||||
|
||||
if ((self->enemy) && (self->enemy->inuse) && (enemy_vis))
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
|
||||
self->monsterinfo.trail_time = level.time;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.blind_fire_target);
|
||||
self->monsterinfo.blind_fire_delay = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (enemy_vis)
|
||||
if ((self->enemy) && (self->enemy->inuse) && (enemy_vis))
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
/* check for alreadyMoved */
|
||||
if (!alreadyMoved)
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
}
|
||||
|
||||
if (!self->inuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
|
||||
self->monsterinfo.trail_time = level.time;
|
||||
VectorCopy(self->enemy->s.origin, self->monsterinfo.blind_fire_target);
|
||||
self->monsterinfo.blind_fire_delay = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((self->monsterinfo.trail_time + 5) <= level.time)
|
||||
{
|
||||
/* and we haven't checked for valid hint paths in the last 10 seconds */
|
||||
if ((self->monsterinfo.last_hint_time + 10) <= level.time)
|
||||
{
|
||||
/* check for hint_paths. */
|
||||
self->monsterinfo.last_hint_time = level.time;
|
||||
|
||||
if (monsterlost_checkhint(self))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((self->monsterinfo.search_time) &&
|
||||
(level.time > (self->monsterinfo.search_time + 20)))
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
/* double move protection */
|
||||
if (!alreadyMoved)
|
||||
{
|
||||
M_MoveToGoal(self, dist);
|
||||
}
|
||||
|
||||
self->monsterinfo.search_time = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -1330,6 +1760,11 @@ ai_run(edict_t *self, float dist)
|
|||
|
||||
M_MoveToGoal(self, dist);
|
||||
|
||||
if (!self->inuse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
G_FreeEdict(tempgoal);
|
||||
|
||||
self->goalentity = save;
|
||||
|
|
|
@ -60,7 +60,6 @@ UpdateChaseCam(edict_t *ent)
|
|||
targ = ent->client->chase_target;
|
||||
|
||||
VectorCopy(targ->s.origin, ownerv);
|
||||
|
||||
ownerv[2] += targ->viewheight;
|
||||
|
||||
VectorCopy(targ->client->v_angle, angles);
|
||||
|
|
|
@ -147,11 +147,72 @@ Killed(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
return;
|
||||
}
|
||||
|
||||
targ->enemy = attacker;
|
||||
/* 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. */
|
||||
if (targ->monsterinfo.aiflags & AI_DUCKED)
|
||||
{
|
||||
targ->monsterinfo.aiflags &= ~AI_DUCKED;
|
||||
}
|
||||
|
||||
if (targ->monsterinfo.aiflags & AI_MEDIC)
|
||||
{
|
||||
if (targ->enemy)
|
||||
{
|
||||
cleanupHealTarget(targ->enemy);
|
||||
}
|
||||
|
||||
/* clean up self */
|
||||
targ->monsterinfo.aiflags &= ~AI_MEDIC;
|
||||
targ->enemy = attacker;
|
||||
}
|
||||
else
|
||||
{
|
||||
targ->enemy = attacker;
|
||||
}
|
||||
|
||||
if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
|
||||
{
|
||||
if (!(targ->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
/* free up slot for spawned monster if it's spawned */
|
||||
if (targ->monsterinfo.aiflags & AI_SPAWNED_CARRIER)
|
||||
{
|
||||
if (targ->monsterinfo.commander &&
|
||||
targ->monsterinfo.commander->inuse &&
|
||||
!strcmp(targ->monsterinfo.commander->classname, "monster_carrier"))
|
||||
{
|
||||
targ->monsterinfo.commander->monsterinfo.monster_slots++;
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->monsterinfo.aiflags & AI_SPAWNED_MEDIC_C)
|
||||
{
|
||||
if (targ->monsterinfo.commander)
|
||||
{
|
||||
if (targ->monsterinfo.commander->inuse &&
|
||||
!strcmp(targ->monsterinfo.commander->classname, "monster_medic_commander"))
|
||||
{
|
||||
targ->monsterinfo.commander->monsterinfo.monster_slots++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->monsterinfo.aiflags & AI_SPAWNED_WIDOW)
|
||||
{
|
||||
/* need to check this because we can
|
||||
have variable numbers of coop players */
|
||||
if (targ->monsterinfo.commander &&
|
||||
targ->monsterinfo.commander->inuse &&
|
||||
!strncmp(targ->monsterinfo.commander->classname, "monster_widow", 13))
|
||||
{
|
||||
if (targ->monsterinfo.commander->monsterinfo.monster_used > 0)
|
||||
{
|
||||
targ->monsterinfo.commander->monsterinfo.monster_used--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!(targ->monsterinfo.aiflags & AI_GOOD_GUY)) &&
|
||||
(!(targ->monsterinfo.aiflags & AI_DO_NOT_COUNT)))
|
||||
{
|
||||
level.killed_monsters++;
|
||||
|
||||
|
@ -243,7 +304,7 @@ CheckPowerArmor(edict_t *ent, vec3_t point, vec3_t normal,
|
|||
|
||||
client = ent->client;
|
||||
|
||||
if (dflags & DAMAGE_NO_ARMOR)
|
||||
if (dflags & (DAMAGE_NO_ARMOR | DAMAGE_NO_POWER_ARMOR))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -307,7 +368,15 @@ CheckPowerArmor(edict_t *ent, vec3_t point, vec3_t normal,
|
|||
damage = (2 * damage) / 3;
|
||||
}
|
||||
|
||||
save = power * damagePerCell;
|
||||
/* etf rifle */
|
||||
if (dflags & DAMAGE_NO_REG_ARMOR)
|
||||
{
|
||||
save = (power * damagePerCell) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
save = power * damagePerCell;
|
||||
}
|
||||
|
||||
if (!save)
|
||||
{
|
||||
|
@ -322,7 +391,14 @@ CheckPowerArmor(edict_t *ent, vec3_t point, vec3_t normal,
|
|||
SpawnDamage(pa_te_type, point, normal);
|
||||
ent->powerarmor_time = level.time + 0.2;
|
||||
|
||||
power_used = save / damagePerCell;
|
||||
if (dflags & DAMAGE_NO_REG_ARMOR)
|
||||
{
|
||||
power_used = (save / damagePerCell) * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
power_used = save / damagePerCell;
|
||||
}
|
||||
|
||||
if (client)
|
||||
{
|
||||
|
@ -362,7 +438,7 @@ CheckArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (dflags & DAMAGE_NO_ARMOR)
|
||||
if (dflags & (DAMAGE_NO_ARMOR | DAMAGE_NO_REG_ARMOR))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -402,9 +478,11 @@ CheckArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage,
|
|||
}
|
||||
|
||||
void
|
||||
M_ReactToDamage(edict_t *targ, edict_t *attacker)
|
||||
M_ReactToDamage(edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
||||
{
|
||||
if (!targ || !attacker)
|
||||
qboolean new_tesla;
|
||||
|
||||
if (!targ || !attacker || !inflictor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -419,13 +497,30 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
|
|||
return;
|
||||
}
|
||||
|
||||
/* logic for tesla - if you are hit by a tesla,
|
||||
and can't see who you should be mad at (attacker)
|
||||
attack the tesla also, target the tesla if it's
|
||||
a "new" tesla */
|
||||
if (!strcmp(inflictor->classname, "tesla"))
|
||||
{
|
||||
new_tesla = MarkTeslaArea(targ, inflictor);
|
||||
|
||||
if (new_tesla || !targ->enemy)
|
||||
{
|
||||
TargetTesla(targ, inflictor);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((attacker == targ) || (attacker == targ->enemy))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we are a good guy monster and our attacker is a player
|
||||
or another good guy, do not get mad at them */
|
||||
/* if we are a good guy monster and
|
||||
our attacker is a player or another
|
||||
good guy, do not get mad at them */
|
||||
if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
|
||||
{
|
||||
if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
|
||||
|
@ -434,15 +529,55 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
|
|||
}
|
||||
}
|
||||
|
||||
/* if we're currently mad at something
|
||||
a target_anger made us mad at, ignore
|
||||
damage */
|
||||
if (targ->enemy && targ->monsterinfo.aiflags & AI_TARGET_ANGER)
|
||||
{
|
||||
float percentHealth;
|
||||
|
||||
/* make sure whatever we were pissed at is still around. */
|
||||
if (targ->enemy->inuse)
|
||||
{
|
||||
percentHealth = (float)(targ->health) / (float)(targ->max_health);
|
||||
|
||||
if (percentHealth > 0.33)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove the target anger flag */
|
||||
targ->monsterinfo.aiflags &= ~AI_TARGET_ANGER;
|
||||
}
|
||||
|
||||
/* if we're healing someone, do like above and try to stay with them */
|
||||
if ((targ->enemy) && (targ->monsterinfo.aiflags & AI_MEDIC))
|
||||
{
|
||||
float percentHealth;
|
||||
|
||||
percentHealth = (float)(targ->health) / (float)(targ->max_health);
|
||||
|
||||
/* ignore it some of the time */
|
||||
if (targ->enemy->inuse && (percentHealth > 0.25))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove the medic flag */
|
||||
targ->monsterinfo.aiflags &= ~AI_MEDIC;
|
||||
cleanupHealTarget(targ->enemy);
|
||||
}
|
||||
|
||||
/* if attacker is a client, get mad at
|
||||
them because he's good and we're not */
|
||||
if (attacker->client)
|
||||
{
|
||||
targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
|
||||
|
||||
/* this can only happen in coop (both new and old
|
||||
enemies are clients) only switch if can't see
|
||||
the current enemy */
|
||||
/* this can only happen in coop (both new and
|
||||
old enemies are clients) only switch if can't
|
||||
see the current enemy */
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
{
|
||||
if (visible(targ, targ->enemy))
|
||||
|
@ -473,7 +608,9 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
|
|||
(strcmp(attacker->classname, "monster_tank") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_supertank") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_makron") != 0) &&
|
||||
(strcmp(attacker->classname, "monster_jorg") != 0))
|
||||
(strcmp(attacker->classname, "monster_jorg") != 0) &&
|
||||
!(attacker->monsterinfo.aiflags & AI_IGNORE_SHOTS) &&
|
||||
!(targ->monsterinfo.aiflags & AI_IGNORE_SHOTS))
|
||||
{
|
||||
if (targ->enemy && targ->enemy->client)
|
||||
{
|
||||
|
@ -520,6 +657,12 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
|
|||
}
|
||||
}
|
||||
|
||||
qboolean
|
||||
CheckTeamDamage(edict_t *targ, edict_t *attacker)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_knockback(edict_t *targ, vec3_t dir, float knockback, float scale)
|
||||
{
|
||||
|
@ -539,9 +682,9 @@ apply_knockback(edict_t *targ, vec3_t dir, float knockback, float scale)
|
|||
}
|
||||
|
||||
void
|
||||
T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
||||
vec3_t dir, vec3_t point, vec3_t normal, int damage,
|
||||
int knockback, int dflags, int mod)
|
||||
T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir,
|
||||
vec3_t point, vec3_t normal, int damage, int knockback, int dflags,
|
||||
int mod)
|
||||
{
|
||||
gclient_t *client;
|
||||
int take;
|
||||
|
@ -549,6 +692,7 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
int asave;
|
||||
int psave;
|
||||
int te_sparks;
|
||||
int sphere_notified;
|
||||
|
||||
if (!targ || !inflictor || !attacker)
|
||||
{
|
||||
|
@ -560,16 +704,20 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
return;
|
||||
}
|
||||
|
||||
/* friendly fire avoidance if enabled you
|
||||
can't hurt teammates (but you can hurt
|
||||
yourself) knockback still occurs */
|
||||
sphere_notified = false;
|
||||
|
||||
/* friendly fire avoidance. If enabled you can't
|
||||
hurt teammates (but you can hurt yourself)
|
||||
knockback still occurs */
|
||||
if ((targ != attacker) && ((deathmatch->value &&
|
||||
((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) ||
|
||||
coop->value))
|
||||
{
|
||||
if (OnSameTeam(targ, attacker))
|
||||
{
|
||||
if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
|
||||
/* nukes kill everyone */
|
||||
if (((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE) &&
|
||||
(mod != MOD_NUKE))
|
||||
{
|
||||
damage = 0;
|
||||
}
|
||||
|
@ -582,6 +730,25 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
|
||||
meansOfDeath = mod;
|
||||
|
||||
/* allow the deathmatch game to change values */
|
||||
if (deathmatch->value && gamerules && gamerules->value)
|
||||
{
|
||||
if (DMGame.ChangeDamage)
|
||||
{
|
||||
damage = DMGame.ChangeDamage(targ, attacker, damage, mod);
|
||||
}
|
||||
|
||||
if (DMGame.ChangeKnockback)
|
||||
{
|
||||
knockback = DMGame.ChangeKnockback(targ, attacker, knockback, mod);
|
||||
}
|
||||
|
||||
if (!damage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* easy mode takes half damage */
|
||||
if ((skill->value == SKILL_EASY) && (deathmatch->value == 0) && targ->client)
|
||||
{
|
||||
|
@ -595,6 +762,18 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
|
||||
client = targ->client;
|
||||
|
||||
/* defender sphere takes half damage */
|
||||
if ((client) && (client->owned_sphere) &&
|
||||
(client->owned_sphere->spawnflags == 1))
|
||||
{
|
||||
damage *= 0.5;
|
||||
|
||||
if (!damage)
|
||||
{
|
||||
damage = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dflags & DAMAGE_BULLET)
|
||||
{
|
||||
te_sparks = TE_BULLET_SPARKS;
|
||||
|
@ -639,7 +818,8 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
}
|
||||
|
||||
/* check for invincibility */
|
||||
if ((client && (client->invincible_framenum > level.framenum)) &&
|
||||
if ((client &&
|
||||
(client->invincible_framenum > level.framenum)) &&
|
||||
!(dflags & DAMAGE_NO_PROTECTION) && (mod != MOD_TRAP))
|
||||
{
|
||||
if (targ->pain_debounce_time < level.time)
|
||||
|
@ -653,6 +833,22 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
save = damage;
|
||||
}
|
||||
|
||||
/* check for monster invincibility */
|
||||
if (((targ->svflags & SVF_MONSTER) &&
|
||||
(targ->monsterinfo.invincible_framenum > level.framenum)) &&
|
||||
!(dflags & DAMAGE_NO_PROTECTION))
|
||||
{
|
||||
if (targ->pain_debounce_time < level.time)
|
||||
{
|
||||
gi.sound(targ, CHAN_ITEM, gi.soundindex(
|
||||
"items/protect4.wav"), 1, ATTN_NORM, 0);
|
||||
targ->pain_debounce_time = level.time + 2;
|
||||
}
|
||||
|
||||
take = 0;
|
||||
save = damage;
|
||||
}
|
||||
|
||||
psave = CheckPowerArmor(targ, point, normal, take, dflags);
|
||||
take -= psave;
|
||||
|
||||
|
@ -662,15 +858,35 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
/* treat cheat/powerup savings the same as armor */
|
||||
asave += save;
|
||||
|
||||
/* this option will do damage both to the armor
|
||||
and person. originally for DPU rounds */
|
||||
if (dflags & DAMAGE_DESTROY_ARMOR)
|
||||
{
|
||||
if (!(targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) &&
|
||||
!(client && (client->invincible_framenum > level.framenum)))
|
||||
{
|
||||
take = damage;
|
||||
}
|
||||
}
|
||||
|
||||
/* do the damage */
|
||||
if (take)
|
||||
{
|
||||
if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
/* need more blood for chainfist. */
|
||||
if (targ->flags & FL_MECHANICAL)
|
||||
{
|
||||
SpawnDamage(TE_ELECTRIC_SPARKS, point, normal);
|
||||
}
|
||||
else if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
{
|
||||
if (strcmp(targ->classname, "monster_gekk") == 0)
|
||||
{
|
||||
SpawnDamage(TE_GREENBLOOD, point, normal);
|
||||
}
|
||||
else if (mod == MOD_CHAINFIST)
|
||||
{
|
||||
SpawnDamage(TE_MOREBLOOD, point, normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpawnDamage(TE_BLOOD, point, normal);
|
||||
|
@ -683,6 +899,17 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
|
||||
targ->health = targ->health - take;
|
||||
|
||||
/* spheres need to know who to shoot at */
|
||||
if (client && client->owned_sphere)
|
||||
{
|
||||
sphere_notified = true;
|
||||
|
||||
if (client->owned_sphere->pain)
|
||||
{
|
||||
client->owned_sphere->pain(client->owned_sphere, attacker, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->health <= 0)
|
||||
{
|
||||
if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
|
@ -695,11 +922,24 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
|
|||
}
|
||||
}
|
||||
|
||||
/* spheres need to know who to shoot at */
|
||||
if (!sphere_notified)
|
||||
{
|
||||
if (client && client->owned_sphere)
|
||||
{
|
||||
if (client->owned_sphere->pain)
|
||||
{
|
||||
client->owned_sphere->pain(client->owned_sphere, attacker, 0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targ->svflags & SVF_MONSTER)
|
||||
{
|
||||
M_ReactToDamage(targ, attacker);
|
||||
M_ReactToDamage(targ, attacker, inflictor);
|
||||
|
||||
if (!(targ->monsterinfo.aiflags & (AI_DUCKED|AI_IGNORE_PAIN)) && (take))
|
||||
if (!(targ->monsterinfo.aiflags & (AI_DUCKED | AI_IGNORE_PAIN)) && (take))
|
||||
{
|
||||
targ->pain(targ, attacker, knockback, take);
|
||||
|
||||
|
|
|
@ -1792,7 +1792,7 @@ Drop_Item(edict_t *ent, gitem_t *item)
|
|||
dropped->item = item;
|
||||
dropped->spawnflags = DROPPED_ITEM;
|
||||
dropped->s.effects = item->world_model_flags;
|
||||
dropped->s.renderfx = RF_GLOW;
|
||||
dropped->s.renderfx = RF_GLOW | RF_IR_VISIBLE;
|
||||
|
||||
if (frandk() > 0.5)
|
||||
{
|
||||
|
@ -1803,8 +1803,8 @@ Drop_Item(edict_t *ent, gitem_t *item)
|
|||
dropped->s.angles[1] -= frandk()*45;
|
||||
}
|
||||
|
||||
VectorSet (dropped->mins, -16, -16, -16);
|
||||
VectorSet (dropped->maxs, 16, 16, 16);
|
||||
VectorSet(dropped->mins, -15, -15, -15);
|
||||
VectorSet(dropped->maxs, 15, 15, 15);
|
||||
gi.setmodel(dropped, dropped->item->world_model);
|
||||
dropped->solid = SOLID_TRIGGER;
|
||||
dropped->movetype = MOVETYPE_TOSS;
|
||||
|
@ -2116,9 +2116,17 @@ SpawnItem(edict_t *ent, gitem_t *item)
|
|||
return;
|
||||
}
|
||||
|
||||
PrecacheItem(item);
|
||||
if (!g_disruptor->value)
|
||||
{
|
||||
if ((!strcmp(ent->classname, "ammo_disruptor")) ||
|
||||
(!strcmp(ent->classname, "weapon_disintegrator")))
|
||||
{
|
||||
G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->spawnflags)
|
||||
if (ent->spawnflags > 1)
|
||||
{
|
||||
if (strcmp(ent->classname, "key_power_cube") != 0)
|
||||
{
|
||||
|
@ -2212,6 +2220,25 @@ SpawnItem(edict_t *ent, gitem_t *item)
|
|||
}
|
||||
}
|
||||
|
||||
/* DM only items */
|
||||
if (!deathmatch->value)
|
||||
{
|
||||
if ((item->pickup == Pickup_Doppleganger) ||
|
||||
(item->pickup == Pickup_Nuke))
|
||||
{
|
||||
G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((item->use == Use_Vengeance) || (item->use == Use_Hunter))
|
||||
{
|
||||
G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PrecacheItem(item);
|
||||
|
||||
if (coop->value && !(ent->spawnflags & ITEM_NO_TOUCH) && (strcmp(ent->classname, "key_power_cube") == 0))
|
||||
{
|
||||
ent->spawnflags |= (1 << (8 + level.power_cubes));
|
||||
|
@ -2274,7 +2301,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_armor_combat",
|
||||
|
@ -2298,7 +2325,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_armor_jacket",
|
||||
|
@ -2322,7 +2349,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_armor_shard",
|
||||
|
@ -2346,7 +2373,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_power_screen",
|
||||
|
@ -2370,7 +2397,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_power_shield",
|
||||
|
@ -2419,7 +2446,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_shotgun",
|
||||
|
@ -2443,7 +2470,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_supershotgun",
|
||||
|
@ -2467,7 +2494,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_machinegun",
|
||||
|
@ -2492,7 +2519,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_chaingun",
|
||||
|
@ -2517,7 +2544,31 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_etf_rifle (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_etf_rifle",
|
||||
Pickup_Weapon,
|
||||
Use_Weapon,
|
||||
Drop_Weapon,
|
||||
Weapon_ETF_Rifle,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_etf_rifle/tris.md2", EF_ROTATE,
|
||||
"models/weapons/v_etf_rifle/tris.md2",
|
||||
"w_etf_rifle",
|
||||
"ETF Rifle",
|
||||
0,
|
||||
1,
|
||||
"Flechettes",
|
||||
IT_WEAPON,
|
||||
WEAP_ETFRIFLE,
|
||||
NULL,
|
||||
0,
|
||||
"weapons/nail1.wav models/proj/flechette/tris.md2",
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_grenades",
|
||||
|
@ -2567,7 +2618,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_grenadelauncher",
|
||||
|
@ -2592,7 +2643,31 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_proxlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_proxlauncher",
|
||||
Pickup_Weapon,
|
||||
Use_Weapon,
|
||||
Drop_Weapon,
|
||||
Weapon_ProxLauncher,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_plaunch/tris.md2", EF_ROTATE,
|
||||
"models/weapons/v_plaunch/tris.md2",
|
||||
"w_proxlaunch",
|
||||
"Prox Launcher",
|
||||
0,
|
||||
1,
|
||||
"Prox",
|
||||
IT_WEAPON,
|
||||
WEAP_PROXLAUNCH,
|
||||
NULL,
|
||||
AMMO_PROX,
|
||||
"weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav weapons/proxwarn.wav weapons/proxopen.wav",
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_rocketlauncher",
|
||||
|
@ -2617,7 +2692,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_hyperblaster",
|
||||
|
@ -2641,6 +2716,30 @@ static const gitem_t gameitemlist[] = {
|
|||
"weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_plasmabeam (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_plasmabeam",
|
||||
Pickup_Weapon,
|
||||
Use_Weapon,
|
||||
Drop_Weapon,
|
||||
Weapon_Heatbeam,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_beamer/tris.md2", EF_ROTATE,
|
||||
"models/weapons/v_beamer/tris.md2",
|
||||
"w_heatbeam",
|
||||
"Plasma Beam",
|
||||
0,
|
||||
2,
|
||||
"Cells",
|
||||
IT_WEAPON,
|
||||
WEAP_PLASMA,
|
||||
NULL,
|
||||
0,
|
||||
"models/weapons/v_beamer2/tris.md2 weapons/bfg__l1a.wav",
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_boomer (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
|
@ -2666,7 +2765,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_railgun",
|
||||
|
@ -2715,7 +2814,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_bfg",
|
||||
|
@ -2740,7 +2839,55 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED weapon_chainfist (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_chainfist",
|
||||
Pickup_Weapon,
|
||||
Use_Weapon,
|
||||
Drop_Weapon,
|
||||
Weapon_ChainFist,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_chainf/tris.md2", EF_ROTATE,
|
||||
"models/weapons/v_chainf/tris.md2",
|
||||
"w_chainfist",
|
||||
"Chainfist",
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
IT_WEAPON | IT_MELEE,
|
||||
WEAP_CHAINFIST,
|
||||
NULL,
|
||||
1,
|
||||
"weapons/sawidle.wav weapons/sawhit.wav",
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED weapon_disintegrator (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"weapon_disintegrator",
|
||||
Pickup_Weapon,
|
||||
Use_Weapon,
|
||||
Drop_Weapon,
|
||||
Weapon_Disintegrator,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_dist/tris.md2", EF_ROTATE,
|
||||
"models/weapons/v_dist/tris.md2",
|
||||
"w_disintegrator",
|
||||
"Disruptor",
|
||||
0,
|
||||
1,
|
||||
"Rounds",
|
||||
IT_WEAPON,
|
||||
WEAP_DISRUPTOR,
|
||||
NULL,
|
||||
1,
|
||||
"models/items/spawngro/tris.md2 models/proj/disintegrator/tris.md2 weapons/disrupt.wav weapons/disint2.wav weapons/disrupthit.wav",
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_shells",
|
||||
|
@ -2764,7 +2911,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_bullets",
|
||||
|
@ -2788,7 +2935,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_cells",
|
||||
|
@ -2812,7 +2959,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_rockets",
|
||||
|
@ -2836,7 +2983,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_slugs",
|
||||
|
@ -2859,6 +3006,124 @@ static const gitem_t gameitemlist[] = {
|
|||
""
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_flechettes (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_flechettes",
|
||||
Pickup_Ammo,
|
||||
NULL,
|
||||
Drop_Ammo,
|
||||
NULL,
|
||||
"misc/am_pkup.wav",
|
||||
"models/ammo/am_flechette/tris.md2", 0,
|
||||
NULL,
|
||||
"a_flechettes",
|
||||
"Flechettes",
|
||||
3,
|
||||
50,
|
||||
NULL,
|
||||
IT_AMMO,
|
||||
0,
|
||||
NULL,
|
||||
AMMO_FLECHETTES
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_prox (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_prox",
|
||||
Pickup_Ammo,
|
||||
NULL,
|
||||
Drop_Ammo,
|
||||
NULL,
|
||||
"misc/am_pkup.wav",
|
||||
"models/ammo/am_prox/tris.md2", 0,
|
||||
NULL,
|
||||
"a_prox",
|
||||
"Prox",
|
||||
3,
|
||||
5,
|
||||
NULL,
|
||||
IT_AMMO,
|
||||
0,
|
||||
NULL,
|
||||
AMMO_PROX,
|
||||
"models/weapons/g_prox/tris.md2 weapons/proxwarn.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_tesla (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_tesla",
|
||||
Pickup_Ammo,
|
||||
Use_Weapon,
|
||||
Drop_Ammo,
|
||||
Weapon_Tesla,
|
||||
"misc/am_pkup.wav",
|
||||
"models/ammo/am_tesl/tris.md2", 0,
|
||||
"models/weapons/v_tesla/tris.md2",
|
||||
"a_tesla",
|
||||
"Tesla",
|
||||
3,
|
||||
5,
|
||||
"Tesla",
|
||||
IT_AMMO | IT_WEAPON,
|
||||
0,
|
||||
NULL,
|
||||
AMMO_TESLA,
|
||||
"models/weapons/v_tesla2/tris.md2 weapons/teslaopen.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav models/weapons/g_tesla/tris.md2"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_nuke (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_nuke",
|
||||
Pickup_Nuke,
|
||||
Use_Nuke,
|
||||
Drop_Ammo,
|
||||
NULL,
|
||||
"misc/am_pkup.wav",
|
||||
"models/weapons/g_nuke/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_nuke",
|
||||
"A-M Bomb",
|
||||
3,
|
||||
300,
|
||||
"A-M Bomb",
|
||||
IT_POWERUP,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"weapons/nukewarn2.wav world/rumble.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_disruptor (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"ammo_disruptor",
|
||||
Pickup_Ammo,
|
||||
NULL,
|
||||
Drop_Ammo,
|
||||
NULL,
|
||||
"misc/am_pkup.wav",
|
||||
"models/ammo/am_disr/tris.md2", 0,
|
||||
NULL,
|
||||
"a_disruptor",
|
||||
"Rounds",
|
||||
3,
|
||||
15,
|
||||
NULL,
|
||||
IT_AMMO,
|
||||
0,
|
||||
NULL,
|
||||
AMMO_DISRUPTOR
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED ammo_magslug (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
|
@ -2884,7 +3149,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_quad",
|
||||
|
@ -2933,7 +3198,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_invulnerability",
|
||||
|
@ -2957,7 +3222,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_silencer",
|
||||
|
@ -2981,7 +3246,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_breather",
|
||||
|
@ -3005,7 +3270,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_enviro",
|
||||
|
@ -3029,7 +3294,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* Special item that gives +2 to maximum health
|
||||
*/
|
||||
{
|
||||
|
@ -3054,7 +3319,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* gives +1 to maximum health
|
||||
*/
|
||||
{
|
||||
|
@ -3079,7 +3344,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_bandolier",
|
||||
|
@ -3103,7 +3368,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_pack",
|
||||
|
@ -3127,7 +3392,197 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED item_ir_goggles (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_ir_goggles",
|
||||
Pickup_Powerup,
|
||||
Use_IR,
|
||||
Drop_General,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/goggles/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_ir",
|
||||
"IR Goggles",
|
||||
2,
|
||||
60,
|
||||
NULL,
|
||||
IT_POWERUP | IT_INSTANT_USE,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"misc/ir_start.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_double (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_double",
|
||||
Pickup_Powerup,
|
||||
Use_Double,
|
||||
Drop_General,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/ddamage/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_double",
|
||||
"Double Damage",
|
||||
2,
|
||||
60,
|
||||
NULL,
|
||||
IT_POWERUP | IT_INSTANT_USE,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"misc/ddamage1.wav misc/ddamage2.wav misc/ddamage3.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_compass (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_compass",
|
||||
Pickup_Powerup,
|
||||
Use_Compass,
|
||||
NULL,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/objects/fire/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_compass",
|
||||
"compass",
|
||||
2,
|
||||
60,
|
||||
NULL,
|
||||
IT_POWERUP,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_sphere_vengeance (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_sphere_vengeance",
|
||||
Pickup_Sphere,
|
||||
Use_Vengeance,
|
||||
NULL,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/vengnce/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_vengeance",
|
||||
"vengeance sphere",
|
||||
2,
|
||||
60,
|
||||
NULL,
|
||||
IT_POWERUP | IT_INSTANT_USE,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"spheres/v_idle.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_sphere_hunter (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_sphere_hunter",
|
||||
Pickup_Sphere,
|
||||
Use_Hunter,
|
||||
NULL,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/hunter/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_hunter",
|
||||
"hunter sphere",
|
||||
2,
|
||||
120,
|
||||
NULL,
|
||||
IT_POWERUP | IT_INSTANT_USE,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"spheres/h_idle.wav spheres/h_active.wav spheres/h_lurk.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_sphere_defender (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_sphere_defender",
|
||||
Pickup_Sphere,
|
||||
Use_Defender,
|
||||
NULL,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/defender/tris.md2", EF_ROTATE,
|
||||
NULL,
|
||||
"p_defender",
|
||||
"defender sphere",
|
||||
2,
|
||||
60,
|
||||
NULL,
|
||||
IT_POWERUP | IT_INSTANT_USE,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"models/proj/laser2/tris.md2 models/items/shell/tris.md2 spheres/d_idle.wav"
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED item_doppleganger (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"item_doppleganger",
|
||||
Pickup_Doppleganger,
|
||||
Use_Doppleganger,
|
||||
Drop_General,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/dopple/tris.md2",
|
||||
EF_ROTATE,
|
||||
NULL,
|
||||
"p_doppleganger",
|
||||
"Doppleganger",
|
||||
0,
|
||||
90,
|
||||
NULL,
|
||||
IT_POWERUP,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
"models/objects/dopplebase/tris.md2 models/items/spawngro2/tris.md2 models/items/hunter/tris.md2 models/items/vengnce/tris.md2",
|
||||
},
|
||||
|
||||
{
|
||||
NULL,
|
||||
Tag_PickupToken,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/items/tagtoken/tris.md2",
|
||||
EF_ROTATE | EF_TAGTRAIL,
|
||||
NULL,
|
||||
"i_tagtoken",
|
||||
"Tag Token",
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
IT_POWERUP | IT_NOT_GIVEABLE,
|
||||
0,
|
||||
NULL,
|
||||
1,
|
||||
NULL,
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* key for computer centers
|
||||
*/
|
||||
{
|
||||
|
@ -3177,7 +3632,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* key for the entrance of jail3
|
||||
*/
|
||||
{
|
||||
|
@ -3202,7 +3657,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* key for the city computer
|
||||
*/
|
||||
{
|
||||
|
@ -3227,7 +3682,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* security pass for the security level
|
||||
*/
|
||||
{
|
||||
|
@ -3252,7 +3707,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* normal door key - blue
|
||||
*/
|
||||
{
|
||||
|
@ -3277,7 +3732,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* normal door key - red
|
||||
*/
|
||||
{
|
||||
|
@ -3301,7 +3756,6 @@ static const gitem_t gameitemlist[] = {
|
|||
""
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* QUAKED key_green_key (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* normal door key - blue
|
||||
|
@ -3328,7 +3782,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* tank commander's head
|
||||
*/
|
||||
{
|
||||
|
@ -3353,7 +3807,7 @@ static const gitem_t gameitemlist[] = {
|
|||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
* tank commander's head
|
||||
*/
|
||||
{
|
||||
|
@ -3377,6 +3831,56 @@ static const gitem_t gameitemlist[] = {
|
|||
""
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_nuke_container (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"key_nuke_container",
|
||||
Pickup_Key,
|
||||
NULL,
|
||||
Drop_General,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/weapons/g_nuke/tris.md2",
|
||||
EF_ROTATE,
|
||||
NULL,
|
||||
"i_contain",
|
||||
"Antimatter Pod",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
IT_STAY_COOP | IT_KEY,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
|
||||
/*
|
||||
* QUAKED key_nuke (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
|
||||
*/
|
||||
{
|
||||
"key_nuke",
|
||||
Pickup_Key,
|
||||
NULL,
|
||||
Drop_General,
|
||||
NULL,
|
||||
"items/pkup.wav",
|
||||
"models/weapons/g_nuke/tris.md2",
|
||||
EF_ROTATE,
|
||||
NULL,
|
||||
"i_nuke",
|
||||
"Antimatter Bomb",
|
||||
2,
|
||||
0,
|
||||
NULL,
|
||||
IT_STAY_COOP | IT_KEY,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
|
||||
{
|
||||
NULL,
|
||||
Pickup_Health,
|
||||
|
|
|
@ -89,6 +89,15 @@ P_DamageModifier(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
if (ent->client->quadfire_framenum > level.framenum)
|
||||
{
|
||||
if ((deathmatch->value) || (damage_multiplier == 1))
|
||||
{
|
||||
damage_multiplier *= 2;
|
||||
is_quadfire = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return damage_multiplier;
|
||||
}
|
||||
|
||||
|
@ -520,6 +529,11 @@ ChangeWeapon(edict_t *ent)
|
|||
void
|
||||
NoAmmoWeaponChange(edict_t *ent)
|
||||
{
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))] &&
|
||||
ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))])
|
||||
{
|
||||
|
@ -527,6 +541,20 @@ NoAmmoWeaponChange(edict_t *ent)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] >= 2) &&
|
||||
ent->client->pers.inventory[ITEM_INDEX(FindItem("Plasma Beam"))])
|
||||
{
|
||||
ent->client->newweapon = FindItem("Plasma Beam");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("flechettes"))] &&
|
||||
ent->client->pers.inventory[ITEM_INDEX(FindItem("etf rifle"))])
|
||||
{
|
||||
ent->client->newweapon = FindItem("etf rifle");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] > 1 &&
|
||||
ent->client->pers.inventory[ITEM_INDEX(FindItem("ionripper"))])
|
||||
{
|
||||
|
@ -593,8 +621,7 @@ Think_Weapon(edict_t *ent)
|
|||
/* call active weapon think routine */
|
||||
if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
|
||||
{
|
||||
is_quad = (ent->client->quad_framenum > level.framenum);
|
||||
is_quadfire = (ent->client->quadfire_framenum > level.framenum);
|
||||
P_DamageModifier(ent);
|
||||
|
||||
if (ent->client->silencer_shots)
|
||||
{
|
||||
|
@ -942,6 +969,11 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
|||
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);
|
||||
}
|
||||
|
||||
fire(ent);
|
||||
break;
|
||||
|
@ -960,15 +992,19 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* GRENADE */
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* GRENADE
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
weapon_grenade_fire(edict_t *ent, qboolean held)
|
||||
{
|
||||
vec3_t offset;
|
||||
vec3_t forward, right;
|
||||
vec3_t forward, right, up;
|
||||
vec3_t start;
|
||||
int damage = 125;
|
||||
float timer;
|
||||
|
@ -984,20 +1020,53 @@ weapon_grenade_fire(edict_t *ent, qboolean held)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
damage *= damage_multiplier;
|
||||
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"items/damage3.wav"), 1, ATTN_NORM, 0);
|
||||
if (damage_multiplier >= 4)
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"items/damage3.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
else if (damage_multiplier == 2)
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex(
|
||||
"misc/ddamage3.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
}
|
||||
|
||||
VectorSet(offset, 8, 8, ent->viewheight - 8);
|
||||
AngleVectors(ent->client->v_angle, forward, right, NULL);
|
||||
P_ProjectSource(ent, offset, forward, right, start);
|
||||
AngleVectors(ent->client->v_angle, forward, right, up);
|
||||
|
||||
if (ent->client->pers.weapon->tag == AMMO_TESLA)
|
||||
{
|
||||
VectorSet(offset, 0, -4, ent->viewheight - 22);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet(offset, 2, 6, ent->viewheight - 14);
|
||||
}
|
||||
|
||||
P_ProjectSource2(ent, ent->s.origin, offset,
|
||||
forward, right, up, start);
|
||||
|
||||
timer = ent->client->grenade_time - level.time;
|
||||
speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) *
|
||||
((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
|
||||
fire_grenade2(ent, start, forward, damage, speed, timer, radius, held);
|
||||
|
||||
if (speed > GRENADE_MAXSPEED)
|
||||
{
|
||||
speed = GRENADE_MAXSPEED;
|
||||
}
|
||||
|
||||
switch (ent->client->pers.weapon->tag)
|
||||
{
|
||||
case AMMO_GRENADES:
|
||||
fire_grenade2(ent, start, forward, damage, speed,
|
||||
timer, radius, held);
|
||||
break;
|
||||
default:
|
||||
fire_tesla(ent, start, forward, damage_multiplier, speed);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!((int)dmflags->value & DF_INFINITE_AMMO))
|
||||
{
|
||||
|
@ -1031,9 +1100,13 @@ weapon_grenade_fire(edict_t *ent, qboolean held)
|
|||
}
|
||||
|
||||
void
|
||||
Weapon_Grenade(edict_t *ent)
|
||||
Throw_Generic(edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
|
||||
int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames, int EXPLODE,
|
||||
void (*fire)(edict_t *ent, qboolean held))
|
||||
{
|
||||
if (!ent)
|
||||
int n;
|
||||
|
||||
if (!ent || !pause_frames || !fire)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1047,7 +1120,7 @@ Weapon_Grenade(edict_t *ent)
|
|||
if (ent->client->weaponstate == WEAPON_ACTIVATING)
|
||||
{
|
||||
ent->client->weaponstate = WEAPON_READY;
|
||||
ent->client->ps.gunframe = 16;
|
||||
ent->client->ps.gunframe = FRAME_IDLE_FIRST;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1079,48 +1152,59 @@ Weapon_Grenade(edict_t *ent)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((ent->client->ps.gunframe == 29) ||
|
||||
(ent->client->ps.gunframe == 34) ||
|
||||
(ent->client->ps.gunframe == 39) ||
|
||||
(ent->client->ps.gunframe == 48))
|
||||
if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
|
||||
{
|
||||
if (randk() & 15)
|
||||
ent->client->ps.gunframe = FRAME_IDLE_FIRST;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pause_frames)
|
||||
{
|
||||
for (n = 0; pause_frames[n]; n++)
|
||||
{
|
||||
return;
|
||||
if (ent->client->ps.gunframe == pause_frames[n])
|
||||
{
|
||||
if (randk() & 15)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (++ent->client->ps.gunframe > 48)
|
||||
{
|
||||
ent->client->ps.gunframe = 16;
|
||||
}
|
||||
|
||||
ent->client->ps.gunframe++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->client->weaponstate == WEAPON_FIRING)
|
||||
{
|
||||
if (ent->client->ps.gunframe == 5)
|
||||
if (ent->client->ps.gunframe == FRAME_THROW_SOUND)
|
||||
{
|
||||
gi.sound(ent, CHAN_WEAPON, gi.soundindex(
|
||||
"weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
if (ent->client->ps.gunframe == 11)
|
||||
if (ent->client->ps.gunframe == FRAME_THROW_HOLD)
|
||||
{
|
||||
if (!ent->client->grenade_time)
|
||||
{
|
||||
ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
|
||||
ent->client->weapon_sound = gi.soundindex(
|
||||
"weapons/hgrenc1b.wav");
|
||||
|
||||
switch (ent->client->pers.weapon->tag)
|
||||
{
|
||||
case AMMO_GRENADES:
|
||||
ent->client->weapon_sound = gi.soundindex(
|
||||
"weapons/hgrenc1b.wav");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* they waited too long, detonate it in their hand */
|
||||
if (!ent->client->grenade_blew_up &&
|
||||
if (EXPLODE && !ent->client->grenade_blew_up &&
|
||||
(level.time >= ent->client->grenade_time))
|
||||
{
|
||||
ent->client->weapon_sound = 0;
|
||||
weapon_grenade_fire(ent, true);
|
||||
fire(ent, true);
|
||||
ent->client->grenade_blew_up = true;
|
||||
}
|
||||
|
||||
|
@ -1133,7 +1217,7 @@ Weapon_Grenade(edict_t *ent)
|
|||
{
|
||||
if (level.time >= ent->client->grenade_time)
|
||||
{
|
||||
ent->client->ps.gunframe = 15;
|
||||
ent->client->ps.gunframe = FRAME_FIRE_LAST;
|
||||
ent->client->grenade_blew_up = false;
|
||||
}
|
||||
else
|
||||
|
@ -1143,13 +1227,13 @@ Weapon_Grenade(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
if (ent->client->ps.gunframe == 12)
|
||||
if (ent->client->ps.gunframe == FRAME_THROW_FIRE)
|
||||
{
|
||||
ent->client->weapon_sound = 0;
|
||||
weapon_grenade_fire(ent, false);
|
||||
fire(ent, true);
|
||||
}
|
||||
|
||||
if ((ent->client->ps.gunframe == 15) &&
|
||||
if ((ent->client->ps.gunframe == FRAME_FIRE_LAST) &&
|
||||
(level.time < ent->client->grenade_time))
|
||||
{
|
||||
return;
|
||||
|
@ -1157,7 +1241,7 @@ Weapon_Grenade(edict_t *ent)
|
|||
|
||||
ent->client->ps.gunframe++;
|
||||
|
||||
if (ent->client->ps.gunframe == 16)
|
||||
if (ent->client->ps.gunframe == FRAME_IDLE_FIRST)
|
||||
{
|
||||
ent->client->grenade_time = 0;
|
||||
ent->client->weaponstate = WEAPON_READY;
|
||||
|
@ -1165,9 +1249,49 @@ Weapon_Grenade(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
void
|
||||
Weapon_Grenade(edict_t *ent)
|
||||
{
|
||||
static int pause_frames[] = {29, 34, 39, 48, 0};
|
||||
|
||||
/* GRENADE LAUNCHER */
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Throw_Generic(ent, 15, 48, 5, 11, 12, pause_frames,
|
||||
GRENADE_TIMER, weapon_grenade_fire);
|
||||
}
|
||||
|
||||
void
|
||||
Weapon_Tesla(edict_t *ent)
|
||||
{
|
||||
static int pause_frames[] = {21, 0};
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ent->client->ps.gunframe > 1) && (ent->client->ps.gunframe < 9))
|
||||
{
|
||||
ent->client->ps.gunindex = gi.modelindex("models/weapons/v_tesla2/tris.md2");
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->client->ps.gunindex = gi.modelindex("models/weapons/v_tesla/tris.md2");
|
||||
}
|
||||
|
||||
Throw_Generic(ent, 8, 32, 99, 1, 2, pause_frames, 0, weapon_grenade_fire);
|
||||
}
|
||||
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* GRENADE LAUNCHER
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
weapon_grenadelauncher_fire(edict_t *ent)
|
||||
|
@ -1175,7 +1299,7 @@ weapon_grenadelauncher_fire(edict_t *ent)
|
|||
vec3_t offset;
|
||||
vec3_t forward, right;
|
||||
vec3_t start;
|
||||
int damage = 120;
|
||||
int damage;
|
||||
float radius;
|
||||
|
||||
if (!ent)
|
||||
|
@ -1183,11 +1307,21 @@ weapon_grenadelauncher_fire(edict_t *ent)
|
|||
return;
|
||||
}
|
||||
|
||||
switch (ent->client->pers.weapon->tag)
|
||||
{
|
||||
case AMMO_PROX:
|
||||
damage = 90;
|
||||
break;
|
||||
default:
|
||||
damage = 120;
|
||||
break;
|
||||
}
|
||||
|
||||
radius = damage + 40;
|
||||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
damage *= damage_multiplier;
|
||||
}
|
||||
|
||||
VectorSet(offset, 8, 8, ent->viewheight - 8);
|
||||
|
@ -1197,7 +1331,15 @@ weapon_grenadelauncher_fire(edict_t *ent)
|
|||
VectorScale(forward, -2, ent->client->kick_origin);
|
||||
ent->client->kick_angles[0] = -1;
|
||||
|
||||
fire_grenade(ent, start, forward, damage, 600, 2.5, radius);
|
||||
switch (ent->client->pers.weapon->tag)
|
||||
{
|
||||
case AMMO_PROX:
|
||||
fire_prox(ent, start, forward, damage_multiplier, 600);
|
||||
break;
|
||||
default:
|
||||
fire_grenade(ent, start, forward, damage, 600, 2.5, radius);
|
||||
break;
|
||||
}
|
||||
|
||||
gi.WriteByte(svc_muzzleflash);
|
||||
gi.WriteShort(ent - g_edicts);
|
||||
|
@ -1220,6 +1362,11 @@ Weapon_GrenadeLauncher(edict_t *ent)
|
|||
static int pause_frames[] = {34, 51, 59, 0};
|
||||
static int fire_frames[] = {6, 0};
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Weapon_Generic(ent, 5, 16, 59, 64, pause_frames,
|
||||
fire_frames, weapon_grenadelauncher_fire);
|
||||
|
||||
|
@ -1230,9 +1377,28 @@ Weapon_GrenadeLauncher(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
void
|
||||
Weapon_ProxLauncher(edict_t *ent)
|
||||
{
|
||||
static int pause_frames[] = {34, 51, 59, 0};
|
||||
static int fire_frames[] = {6, 0};
|
||||
|
||||
/* ROCKET */
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Weapon_Generic(ent, 5, 16, 59, 64, pause_frames,
|
||||
fire_frames, weapon_grenadelauncher_fire);
|
||||
}
|
||||
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* ROCKET
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
Weapon_RocketLauncher_Fire(edict_t *ent)
|
||||
|
@ -1254,8 +1420,8 @@ Weapon_RocketLauncher_Fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
radius_damage *= 4;
|
||||
damage *= damage_multiplier;
|
||||
radius_damage *= damage_multiplier;
|
||||
}
|
||||
|
||||
AngleVectors(ent->client->v_angle, forward, right, NULL);
|
||||
|
@ -1289,7 +1455,7 @@ Weapon_RocketLauncher(edict_t *ent)
|
|||
static int pause_frames[] = {25, 33, 42, 50, 0};
|
||||
static int fire_frames[] = {5, 0};
|
||||
|
||||
if (!ent)
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1304,9 +1470,13 @@ Weapon_RocketLauncher(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* BLASTER / HYPERBLASTER */
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* BLASTER / HYPERBLASTER
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
Blaster_Fire(edict_t *ent, vec3_t g_offset, int damage,
|
||||
|
@ -1323,7 +1493,7 @@ Blaster_Fire(edict_t *ent, vec3_t g_offset, int damage,
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
damage *= damage_multiplier;
|
||||
}
|
||||
|
||||
AngleVectors(ent->client->v_angle, forward, right, NULL);
|
||||
|
@ -1515,9 +1685,13 @@ Weapon_HyperBlaster(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* MACHINEGUN / CHAINGUN */
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* MACHINEGUN / CHAINGUN
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
Machinegun_Fire(edict_t *ent)
|
||||
|
@ -1568,8 +1742,8 @@ Machinegun_Fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
kick *= 4;
|
||||
damage *= damage_multiplier;
|
||||
kick *= damage_multiplier;
|
||||
}
|
||||
|
||||
for (i = 1; i < 3; i++)
|
||||
|
@ -1761,8 +1935,8 @@ Chaingun_Fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
kick *= 4;
|
||||
damage *= damage_multiplier;
|
||||
kick *= damage_multiplier;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
|
@ -1820,9 +1994,13 @@ Weapon_Chaingun(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* SHOTGUN / SUPERSHOTGUN */
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* SHOTGUN / SUPERSHOTGUN
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
weapon_shotgun_fire(edict_t *ent)
|
||||
|
@ -1854,8 +2032,8 @@ weapon_shotgun_fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
kick *= 4;
|
||||
damage *= damage_multiplier;
|
||||
kick *= damage_multiplier;
|
||||
}
|
||||
|
||||
if (deathmatch->value)
|
||||
|
@ -1932,8 +2110,8 @@ weapon_supershotgun_fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
kick *= 4;
|
||||
damage *= damage_multiplier;
|
||||
kick *= damage_multiplier;
|
||||
}
|
||||
|
||||
v[PITCH] = ent->client->v_angle[PITCH];
|
||||
|
@ -2010,7 +2188,13 @@ Weapon_SuperShotgun(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* RAILGUN */
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* RAILGUN
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
weapon_railgun_fire(edict_t *ent)
|
||||
|
@ -2040,8 +2224,8 @@ weapon_railgun_fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
kick *= 4;
|
||||
damage *= damage_multiplier;
|
||||
kick *= damage_multiplier;
|
||||
}
|
||||
|
||||
AngleVectors(ent->client->v_angle, forward, right, NULL);
|
||||
|
@ -2089,9 +2273,13 @@ Weapon_Railgun(edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* BFG10K */
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* BFG10K
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
weapon_bfg_fire(edict_t *ent)
|
||||
|
@ -2139,7 +2327,7 @@ weapon_bfg_fire(edict_t *ent)
|
|||
|
||||
if (is_quad)
|
||||
{
|
||||
damage *= 4;
|
||||
damage *= damage_multiplier;
|
||||
}
|
||||
|
||||
AngleVectors(ent->client->v_angle, forward, right, NULL);
|
||||
|
|
|
@ -1209,7 +1209,7 @@ extern void Move_Final ( edict_t * ent ) ;
|
|||
extern void Move_Done ( edict_t * ent ) ;
|
||||
extern void T_RadiusDamage ( edict_t * inflictor , edict_t * attacker , float damage , edict_t * ignore , float radius , int mod ) ;
|
||||
extern void T_Damage ( edict_t * targ , edict_t * inflictor , edict_t * attacker , vec3_t dir , vec3_t point , vec3_t normal , int damage , int knockback , int dflags , int mod ) ;
|
||||
extern void M_ReactToDamage ( edict_t * targ , edict_t * attacker ) ;
|
||||
extern void M_ReactToDamage ( edict_t * targ , edict_t * attacker, edict_t *inflictor ) ;
|
||||
extern int CheckArmor ( edict_t * ent , vec3_t point , vec3_t normal , int damage , int te_sparks , int dflags ) ;
|
||||
extern int CheckPowerArmor ( edict_t * ent , vec3_t point , vec3_t normal , int damage , int dflags ) ;
|
||||
extern void SpawnDamage ( int type , vec3_t origin , vec3_t normal ) ;
|
||||
|
|
1751
src/rogue/g_ai.c
1751
src/rogue/g_ai.c
File diff suppressed because it is too large
Load diff
|
@ -1,249 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) ZeniMax Media Inc.
|
||||
* Licensed under the GNU General Public License 2.0.
|
||||
*/
|
||||
|
||||
/*
|
||||
* =======================================================================
|
||||
*
|
||||
* Chase cam. Only used in multiplayer mode.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* is our chase target gone? */
|
||||
if (!ent->client->chase_target->inuse ||
|
||||
ent->client->chase_target->client->resp.spectator)
|
||||
{
|
||||
edict_t *old = ent->client->chase_target;
|
||||
ChaseNext(ent);
|
||||
|
||||
if (ent->client->chase_target == old)
|
||||
{
|
||||
ent->client->chase_target = NULL;
|
||||
ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
|
||||
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;
|
||||
}
|
||||
|
||||
if (targ->deadflag)
|
||||
{
|
||||
ent->client->ps.pmove.pm_type = PM_DEAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
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]);
|
||||
}
|
||||
|
||||
if (targ->deadflag)
|
||||
{
|
||||
ent->client->ps.viewangles[ROLL] = 40;
|
||||
ent->client->ps.viewangles[PITCH] = -15;
|
||||
ent->client->ps.viewangles[YAW] = targ->client->killer_yaw;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
ChaseNext(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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->client->resp.spectator)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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->client->resp.spectator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void
|
||||
GetChaseTarget(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *other;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 1; i <= maxclients->value; i++)
|
||||
{
|
||||
other = g_edicts + i;
|
||||
|
||||
if (other->inuse && !other->client->resp.spectator)
|
||||
{
|
||||
ent->client->chase_target = other;
|
||||
ent->client->update_chase = true;
|
||||
UpdateChaseCam(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gi.centerprintf(ent, "No other players to chase.");
|
||||
}
|
1177
src/rogue/g_combat.c
1177
src/rogue/g_combat.c
File diff suppressed because it is too large
Load diff
4249
src/rogue/g_func.c
4249
src/rogue/g_func.c
File diff suppressed because it is too large
Load diff
3845
src/rogue/g_items.c
3845
src/rogue/g_items.c
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1459,7 +1459,7 @@ extern void ChasePrev ( edict_t * ent ) ;
|
|||
extern void ChaseNext ( edict_t * ent ) ;
|
||||
extern void UpdateChaseCam ( edict_t * ent ) ;
|
||||
extern void ai_run ( edict_t * self , float dist ) ;
|
||||
extern qboolean ai_checkattack ( edict_t * self , float dist ) ;
|
||||
extern qboolean ai_checkattack ( edict_t * self ) ;
|
||||
extern void ai_run_slide ( edict_t * self , float distance ) ;
|
||||
extern void ai_run_missile ( edict_t * self ) ;
|
||||
extern void ai_run_melee ( edict_t * self ) ;
|
||||
|
|
Loading…
Reference in a new issue