📄 g_combat.pas
字号:
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);
{ NOTE: 2003-09-18-Scott Price:
Commented out FAB's conversion, and corrected the original which was
almost correct - I hope :) }
if (dflags AND DAMAGE_ENERGY) <> 0 then
save := ceil(gitem_armor_p(armor^.info)^.energy_protection * damage)
{ save := ceil((gitem_armor_p(armor)^.energy_protection * damage)) //check this by FAB .. }
else
save := ceil(gitem_armor_p(armor^.info)^.normal_protection * damage);
{ save := ceil((gitem_armor_p(armor)^.normal_protection * damage)); //check this by FAB .. }
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: edict_p);
begin
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) then
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: edict_p): qboolean;
begin
// these 2 lines originally commented
//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: edict_p; var dir, point, normal: vec3_t; damage, knockback, dflags, mofd: Integer);
var
client: gclient_p;
take, save, asave, psave, te_sparks_: Integer;
kvel: vec3_t;
mass: Single;
begin
if (targ^.takedamage = DAMAGE_NO) then // check this .. by FAB
Exit;
// 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))
{ NOTE: 2003-09-18: Scott Price
I think the original works something like the following:
(<first expression> AND (<second expression> AND <third expression>) OR <fourth expression>) }
if ((targ <> attacker) and (((deathmatch^.value <> 0) and ((trunc(dmflags^.value) AND (DF_MODELTEAMS OR DF_SKINTEAMS)) <> 0))) or (coop^.value <> 0)) then
begin
if (OnSameTeam(targ, attacker)) then
begin
if (trunc(dmflags^.value) AND DF_NO_FRIENDLY_FIRE) <> 0 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;
damage := damage div 2; // Check this ...by FAB // SP: Should be ok
if (damage = 0) then
damage := 1;
end;
client := targ^.client;
if (dflags AND DAMAGE_BULLET) <> 0 then
te_sparks_ := Ord(TE_BULLET_SPARKS) // Check this typecast ...by FAB
else
te_sparks_ := Ord(TE_SPARKS); // Check this typecast ...by FAB
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))
if (knockback <> 0) AND (targ^.movetype <> MOVETYPE_NONE) AND (targ^.movetype <> MOVETYPE_BOUNCE) AND (targ^.movetype <> MOVETYPE_PUSH) AND (targ^.movetype <> MOVETYPE_STOP) then
begin
if (targ^.mass < 50) then
mass := 50
else
mass := targ^.mass;
if (targ^.client <> Nil) AND (attacker = targ) then
VectorScale(dir, 1600.0 * knockback / mass, kvel) // the rocket jump hack...
else
VectorScale(dir, 500.0 * 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) then
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(Ord(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 <> 0) 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 <> 0) then
targ^.pain(targ, attacker, knockback, take);
end
else if (take <> 0) 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;
{ | | | | }
{ V V ToDo: Scott to continue from Here V V }
(* ============
T_RadiusDamage
============ *)
procedure T_RadiusDamage(inflictor, attacker: edict_p; damage: Single; ignore: edict_p; radius: Single; mofd: Integer);
var
points: Single;
ent: edict_p;
v, dir: vec3_t;
label
__Continue;
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
if (ent = ignore) then
goto __Continue;
if (ent^.takedamage = DAMAGE_NO) then // check this ...by FAB
goto __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, Trunc(points), Trunc(points), DAMAGE_RADIUS, mofd);
end;
end;
__Continue:
{ NOTE: ADDED THIS LINE TO COMPENSATE }
ent := findradius(ent, inflictor^.s.origin, radius);
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -