game: sync rogue g_* files

This commit is contained in:
Denis Pauk 2023-10-22 12:19:30 +03:00
parent 17f223eada
commit 5103bd6f72
14 changed files with 1573 additions and 14127 deletions

View file

@ -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
# ----------

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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 ) ;

File diff suppressed because it is too large Load diff

View file

@ -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.");
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 ) ;