📄 g_combat.pas
字号:
unit g_combat;
(*
Copyright (C) 1997-2001 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
// g_combat.c
// TODO: #include "g_local.h"
{ NOTES (For Scott):
==================
- Review this code and assure we have not missed some Assignments in IF
statements, and accidentally interpretted them as Comparasons }
interface
function CanDamage(targ, inflictor: Pedict_t): qboolean;
procedure Killed(targ, inflictor, attacker: Pedict_t; damage: Integer; point: vec3_t);
procedure SpawnDamage(dmgtype: Integer; origin, normal: vec3_t; damage: Integer);
procedure M_ReactToDamage(targ, attacker: Pedict_t);
function CheckTeamDamage(targ, attacker: Pedict_t): qboolean;
procedure T_Damage(targ, inflictor, attacker: Pedict_t; dir, point, normal: vec3_t; damage, knockback, dflags, mofd: Integer);
procedure T_RadiusDamage(inflictor, attacker: Pedict_t; damage: float; ignore: Pedict_t; radius: float; mofd: Integer);
implementation
(* ============
CanDamage
Returns true if the inflictor can directly damage the target. Used for
explosions and melee attacks.
============ *)
function CanDamage(targ, inflictor: Pedict_t): qboolean;
var
dest: vec3_t;
trace: trace_t;
begin
{ Following line originally commented out }
// bmodels need special checking because their origin is 0,0,0
if (targ^.movetype = MOVETYPE_PUSH) then
begin
VectorAdd(targ^.absmin, targ^.absmax, dest);
VectorScale(dest, 0.5, dest);
trace := gi.trace(inflictor^.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if (trace.fraction = 1.0) then
begin
Result := True;
Exit;
end;
if (trace.ent = targ) then
begin
Result := True;
Exit;
end;
Result := False;
Exit;
end;
trace := gi.trace (inflictor^.s.origin, vec3_origin, vec3_origin, targ^.s.origin, inflictor, MASK_SOLID);
if (trace.fraction = 1.0) then
begin
Result := True;
Exit;
end;
VectorCopy(targ^.s.origin, dest);
dest[0] := dest[0] + 15.0;
dest[1] := dest[1] + 15.0;
trace := gi.trace(inflictor^.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if (trace.fraction = 1.0) then
begin
Result := True;
Exit;
end;
VectorCopy(targ^.s.origin, dest);
dest[0] := dest[0] + 15.0;
dest[1] := dest[1] - 15.0;
trace := gi.trace(inflictor^.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if (trace.fraction = 1.0) then
begin
Result := True;
Exit;
end;
VectorCopy(targ^.s.origin, dest);
dest[0] := dest[0] - 15.0;
dest[1] := dest[1] + 15.0;
trace := gi.trace(inflictor^.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if (trace.fraction = 1.0) then
begin
Result := True;
Exit;
end;
VectorCopy(targ^.s.origin, dest);
dest[0] := dest[0] - 15.0;
dest[1] := dest[1] - 15.0;
trace := gi.trace(inflictor^.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if (trace.fraction = 1.0) then
begin
Result := True;
Exit;
end;
Result := False;
end;
(* ============
Killed
============ *)
procedure Killed(targ, inflictor, attacker: Pedict_t; damage: Integer; point: vec3_t);
begin
if (targ^.health < -999) then
targ^.health := -999;
targ^.enemy := attacker;
if (((targ^.svflags AND SVF_MONSTER) <> 0) AND (targ^.deadflag <> DEAD_DEAD)) then
begin
{ Following line originally commented out }
// targ->svflags |= SVF_DEADMONSTER; // now treat as a different content type
if ((targ^.monsterinfo.aiflags AND AI_GOOD_GUY) = 0) then
begin
Inc(level.killed_monsters);
if (coop^.value AND attacker^.client) then
Inc(attacker^.client^.resp.score);
// medics won't heal monsters that they kill themselves
if (strcmp(attacker^.classname, 'monster_medic') = 0) then
targ^.owner := attacker;
end;
end;
if ((targ^.movetype = MOVETYPE_PUSH) OR (targ^.movetype = MOVETYPE_STOP) OR (targ^.movetype = MOVETYPE_NONE)) then
begin // doors, triggers, etc
targ^.die(targ, inflictor, attacker, damage, point);
Exit;
end;
if (((targ^.svflags AND SVF_MONSTER) <> 0) AND (targ^.deadflag <> DEAD_DEAD)) then
begin
targ^.touch := Nil;
monster_death_use(targ);
end;
targ^.die(targ, inflictor, attacker, damage, point);
end;
(* ================
SpawnDamage
================ *)
procedure SpawnDamage(dmgtype: Integer; origin, normal: vec3_t; damage: Integer);
begin
if (damage > 255) then
damage := 255;
gi.WriteByte(svc_temp_entity);
gi.WriteByte(dmgtype);
{ Following line originally commented out }
// gi.WriteByte (damage);
gi.WritePosition(origin);
gi.WriteDir(normal);
gi.multicast(origin, MULTICAST_PVS);
end;
{ This Routine is only visible in-side this unit }
(* ============
T_Damage
targ entity that is being damaged
inflictor entity that is causing the damage
attacker entity that caused the inflictor to damage targ
example: targ=monster, inflictor=rocket, attacker=player
dir direction of the attack
point point at which the damage is being inflicted
normal normal vector from that point
damage amount of damage being inflicted
knockback force to be applied against targ as a result of the damage
dflags these flags are used to control how T_Damage works
DAMAGE_RADIUS damage was indirect (from a nearby explosion)
DAMAGE_NO_ARMOR armor does not protect from this damage
DAMAGE_ENERGY damage is from an energy based weapon
DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
DAMAGE_BULLET damage is from a bullet (used for ricochets)
DAMAGE_NO_PROTECTION kills godmode, armor, everything
============ *)
function CheckPowerArmor(ent: Pedict_t; point, normal: vec3_t; damage, dflags: Integer): Integer;
var
client: Pgclient_t;
save, power_armor_type, index, damagePerCell, pa_te_type, power, power_used: Integer;
vec, forwards: vec3_t;
dot: float;
begin
if (damage = 0) then
begin
Result := 0;
Exit;
end;
client := ent^.client;
if (dflags AND DAMAGE_NO_ARMOR) <> 0 then
begin
Result := 0;
Exit;
end;
if (client <> Nil) then
begin
power_armor_type := PowerArmorType(ent);
if (power_armor_type <> POWER_ARMOR_NONE) then
begin
index := ITEM_INDEX(FindItem('Cells'));
power := client^.pers.inventory[index];
end
end
else if (ent^.svflags AND SVF_MONSTER) <> 0 then
begin
power_armor_type := ent^.monsterinfo.power_armor_type;
power := ent^.monsterinfo.power_armor_power;
end
else
begin
Result := 0;
Exit;
end;
if (power_armor_type = POWER_ARMOR_NONE) then
begin
Result := 0;
Exit;
end;
if (power = 0) then
begin
Result := 0;
Exit;
end;
if (power_armor_type = POWER_ARMOR_SCREEN) then
begin
{ The variable 'forward' has been renamed to 'forwards' }
// only works if damage point is in front
AngleVectors(ent^.s.angles, forwards, Nil, Nil);
VectorSubtract(point, ent^.s.origin, vec);
VectorNormalize(vec);
dot := DotProduct(vec, forwards);
if (dot <= 0.3) then
begin
Result := 0;
Exit;
end;
damagePerCell := 1;
pa_te_type := TE_SCREEN_SPARKS;
{ TODO: The following commented line is a Delphi Safe alternative }
//damage := damage div 3;
damage := damage / 3;
end
else
begin
damagePerCell := 2;
pa_te_type := TE_SHIELD_SPARKS;
{ TODO: The following commented line is a Delphi Safe alternative }
//damage := (2 * damage) div 3;
damage := (2 * damage) / 3;
end;
save := power * damagePerCell;
if (save = 0) then
begin
Result := 0;
Exit;
end;
if (save > damage) then
save := damage;
SpawnDamage(pa_te_type, point, normal, save);
ent^.powerarmor_time := level.time + 0.2;
power_used := save / damagePerCell;
if (client <> Nil) then
client^.pers.inventory[index] := client^.pers.inventory[index] - power_used;
else
ent^.monsterinfo.power_armor_power := ent^.monsterinfo.power_armor_power - power_used;
Result := save;
end;
{ This Routine is only visible in-side this unit }
function CheckArmor(ent: Pedict_t; point, normal: vec3_t; damage, te_sparks, dflags: Integer): Integer;
var
client: Pgclient_t;
save, index: Integer;
armor: Pgitem_t;
begin
if (damage = 0) then
begin
Result := 0;
Exit;
end;
client := ent^.client;
if (client = Nil) then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -