📄 g_combat.pas
字号:
begin
Result := 0;
Exit;
end;
if (dflags AND DAMAGE_NO_ARMOR) <> 0 then
begin
Result := 0;
Exit;
end;
index := ArmorIndex(ent);
if (index = 0) then
begin
Result := 0;
Exit;
end;
armor := GetItemByIndex(index);
if (dflags AND DAMAGE_ENERGY) <> 0 then
save := ceil((Pgitem_armor_t(armor)^.info)^.energy_protection * damage);
else
save := ceil((Pgitem_armor_t(armor)^.info)^.normal_protection * damage);
if (save >= client^.pers.inventory[index]) then
save := client^.pers.inventory[index];
if (save = 0) then
begin
Result := 0;
Exit;
end;
client^.pers.inventory[index] := client^.pers.inventory[index] - save;
SpawnDamage(te_sparks, point, normal, save);
Result := save;
end;
procedure M_ReactToDamage(targ, attacker: Pedict_t);
end;
if (attacker^.client = Nil) AND ((attacker^.svflags AND SVF_MONSTER) = 0) then
Exit;
if (attacker = targ) OR (attacker = targ^.enemy) then
Exit;
// 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 AND AI_GOOD_GUY) <> 0 then
begin
if (attacker^.client <> Nil) OR ((attacker^.monsterinfo.aiflags AND AI_GOOD_GUY) <> 0) then
Exit;
end;
// we now know that we are not both good guys
// if attacker is a client, get mad at them because he's good and we're not
if (attacker^.client <> Nil) then
begin
targ^.monsterinfo.aiflags := targ^.monsterinfo.aiflags AND (NOT 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
if (targ^.enemy <> Nil) AND (targ^.enemy^.client <> Nil) then
begin
if (visible(targ, targ^.enemy)) then
begin
targ^.oldenemy := attacker;
Exit;
end;
targ^.oldenemy := targ^.enemy;
end;
targ^.enemy := attacker;
if ((targ^.monsterinfo.aiflags AND AI_DUCKED) = 0) then
FoundTarget(targ);
Exit;
end;
// it's the same base (walk/swim/fly) type and a different classname and it's not a tank
// (they spray too much), get mad at them
if (((targ^.flags AND (FL_FLY OR FL_SWIM)) = (attacker^.flags AND (FL_FLY OR FL_SWIM))) AND
(strcmp(targ^.classname, attacker^.classname) <> 0) AND
(strcmp(attacker^.classname, 'monster_tank') <> 0) AND
(strcmp(attacker^.classname, 'monster_supertank') <> 0) AND
(strcmp(attacker^.classname, 'monster_makron') <> 0) AND
(strcmp(attacker^.classname, 'monster_jorg') <> 0) ) then
begin
if (targ^.enemy <> Nil) AND (targ^.enemy^.client <> Nil) then
targ^.oldenemy := targ^.enemy;
targ^.enemy := attacker;
if ((targ^.monsterinfo.aiflags AND AI_DUCKED) = 0)
FoundTarget(targ);
end;
// if they *meant* to shoot us, then shoot back
else if (attacker^.enemy = targ) then
begin
if (targ^.enemy <> Nil) AND (targ^.enemy^.client <> Nil) then
targ^.oldenemy := targ^.enemy;
targ^.enemy := attacker;
if ((targ^.monsterinfo.aiflags AND AI_DUCKED) = 0) then
FoundTarget(targ);
end
// otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
else if (attacker^.enemy <> Nil) AND (attacker^.enemy <> targ) then
begin
if (targ^.enemy <> Nil) AND (targ^.enemy^.client <> Nil) then
targ^.oldenemy := targ^.enemy;
targ^.enemy := attacker^.enemy;
if ((targ^.monsterinfo.aiflags AND AI_DUCKED) = 0) then
FoundTarget(targ);
end;
end;
function CheckTeamDamage(targ, attacker: Pedict_t): qboolean;
begin
//FIXME make the next line real and uncomment this block
// if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
Result := False;
end;
procedure T_Damage(targ, inflictor, attacker: Pedict_t; dir, point, normal: vec3_t; damage, knockback, dflags, mofd: Integer);
var
client: Pgclient_t;
take, save, asave, psave, te_sparks: Integer;
kvel: vec3_t;
mass: float;
begin
if (targ^.takedamage = 0) then
Exit;
// friendly fire avoidance
// if enabled you can't hurt teammates (but you can hurt yourself)
// knockback still occurs
if ((targ <> attacker) AND ((deathmatch^.value AND (Integer(dmflags^.value) AND (DF_MODELTEAMS OR DF_SKINTEAMS))) OR coop^.value)) then
begin
if (OnSameTeam(targ, attacker)) then
begin
if (Integer(dmflags^.value) AND DF_NO_FRIENDLY_FIRE) then
damage := 0;
else
mofd := mofd OR MOD_FRIENDLY_FIRE;
end;
end;
meansOfDeath := mofd;
// easy mode takes half damage
if (skill^.value = 0) AND (deathmatch^.value = 0) AND (targ^.client <> Nil) then
begin
damage := damage * 0.5;
if (damage = 0) then
damage := 1;
end;
client := targ^.client;
if (dflags AND DAMAGE_BULLET) <> 0 then
te_sparks := TE_BULLET_SPARKS;
else
te_sparks := TE_SPARKS;
VectorNormalize(dir);
// bonus damage for suprising a monster
if ((dflags AND DAMAGE_RADIUS) = 0) AND ((targ^.svflags AND SVF_MONSTER) <> 0) AND (attacker^.client <> Nil) AND (targ^.enemy = Nil) AND (targ^.health > 0) then
damage := damage * 2;
if (targ^.flags AND FL_NO_KNOCKBACK) <> 0 then
knockback := 0;
// figure momentum add
if ((dflags AND DAMAGE_NO_KNOCKBACK) = 0) then
begin
if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
begin
if (targ^.mass < 50) then
mass := 50;
else
mass := targ^.mass;
if (targ^.client <> Nil) AND (attacker = targ) then
VectorScale(dir, 1600.0 * float(knockback) / mass, kvel); // the rocket jump hack...
else
VectorScale(dir, 500.0 * float(knockback) / mass, kvel);
VectorAdd(targ^.velocity, kvel, targ^.velocity);
end;
end;
take := damage;
save := 0;
// check for godmode
if ((targ^.flags AND FL_GODMODE) <> 0) AND ((dflags AND DAMAGE_NO_PROTECTION) = 0) then
begin
take := 0;
save := damage;
SpawnDamage(te_sparks, point, normal, save);
end;
// check for invincibility
if (client <> Nil) AND (client^.invincible_framenum > level.framenum) AND ((dflags AND DAMAGE_NO_PROTECTION) = 0)
begin
if (targ^.pain_debounce_time < level.time) then
begin
gi.sound(targ, CHAN_ITEM, gi.soundindex('items/protect4.wav'), 1, ATTN_NORM, 0);
targ^.pain_debounce_time := level.time + 2;
end;
take := 0;
save := damage;
end;
psave := CheckPowerArmor(targ, point, normal, take, dflags);
take := take - psave;
asave = CheckArmor(targ, point, normal, take, te_sparks, dflags);
take := take - asave;
//treat cheat/powerup savings the same as armor
asave := asave + save;
// team damage avoidance
if ((dflags AND DAMAGE_NO_PROTECTION) = 0) AND CheckTeamDamage(targ, attacker) then
Exit;
// do the damage
if (take <> 0) then
begin
if ((targ^.svflags AND SVF_MONSTER) <> 0) OR (client <> Nil) then
SpawnDamage(TE_BLOOD, point, normal, take)
else
SpawnDamage(te_sparks, point, normal, take);
targ^.health := targ^.health - take;
if (targ^.health <= 0) then
begin
if ((targ^.svflags AND SVF_MONSTER) <> 0) OR (client <> Nil) then
targ^.flags := targ^.flags OR FL_NO_KNOCKBACK;
Killed(targ, inflictor, attacker, take, point);
Exit;
end;
end;
if (targ^.svflags AND SVF_MONSTER) <> 0 then
begin
M_ReactToDamage(targ, attacker);
if ((targ^.monsterinfo.aiflags AND AI_DUCKED) = 0) AND (take <> Nil) then
begin
targ^.pain(targ, attacker, knockback, take);
// nightmare mode monsters don't go into pain frames often
if (skill^.value = 3) then
targ^.pain_debounce_time := level.time + 5;
end;
end
else if (client <> Nil) then
begin
if ((targ^.flags AND FL_GODMODE) = 0) AND (take <> Nil) then
targ^.pain(targ, attacker, knockback, take);
end
else if (take <> Nil) then
begin
if (targ^.pain <> Nil) then
targ^.pain(targ, attacker, knockback, take);
end
// add to the damage inflicted on a player this frame
// the total will be turned into screen blends and view angle kicks
// at the end of the frame
if (client <> Nil) then
begin
client^.damage_parmor := client^.damage_parmor + psave;
client^.damage_armor := client^.damage_armor + asave;
client^.damage_blood := client^.damage_blood + take;
client^.damage_knockback := client^.damage_knockback + knockback;
VectorCopy(point, client^.damage_from);
end;
end;
(* ============
T_RadiusDamage
============ *)
procedure T_RadiusDamage(inflictor, attacker: Pedict_t; damage: float; ignore: Pedict_t; radius: float; mofd: Integer);
var
points: float;
ent: Pedict_t;
v, dir: vec3_t;
begin
ent := Nil;
{ NOTE: Original Code here used a WHILE loop to perform this operation, but
made an assignment in the Logical Test, so I have altered to be a
initally called, and then a TRY..FINALLY block to perform the
operation again prior to the end of the Loop and ReTest - Scott Price }
ent := findradius(ent, inflictor^.s.origin, radius);
while (ent <> Nil) do
begin
{ NOTE: ADDED THE TRY FINALLY BLOCK TO COMPENSATE }
TRY
if (ent = ignore) then
Continue;
if (ent^.takedamage = 0) then
Continue;
VectorAdd(ent^.mins, ent^.maxs, v);
VectorMA(ent^.s.origin, 0.5, v, v);
VectorSubtract(inflictor^.s.origin, v, v);
points := damage - 0.5 * VectorLength(v);
if (ent = attacker) then
points := points * 0.5;
if (points > 0) then
begin
if CanDamage(ent, inflictor) then
begin
VectorSubtract(ent^.s.origin, inflictor^.s.origin, dir);
T_Damage(ent, inflictor, attacker, dir, inflictor^.s.origin, vec3_origin, Integer(points), Integer(points), DAMAGE_RADIUS, mofd);
end;
end;
FINALLY
{ NOTE: ADDED THIS LINE TO COMPENSATE }
ent := findradius(ent, inflictor^.s.origin, radius);
END;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -