📄 g_combat.pas
字号:
//100%
{----------------------------------------------------------------------------}
{ }
{ File(s): g_combat.c }
{ Content: }
{ }
{ Initial conversion by : ??? }
{ Initial conversion on : ??? }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ 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. }
{ }
{----------------------------------------------------------------------------}
{ Updated on : 2003-Sept-18 }
{ Updated by : Scott Price (scott.price@totalise.co.uk) }
{ Updated on : 2002-Sept-25 }
{ Updated by : FAB (Fabrizio Rossini) }
{ }
{----------------------------------------------------------------------------}
{ Notes: }
{ - Review this code and assure we have not missed some Assignments in IF }
{ statements, and accidentally interpretted them as Comparasons }
{----------------------------------------------------------------------------}
unit g_combat;
interface
uses
q_shared,
q_shared_add,
g_local,
g_local_add;
function CanDamage(targ, inflictor: edict_p): qboolean;
procedure Killed(targ, inflictor, attacker: edict_p; damage: Integer; const point: vec3_t);
procedure SpawnDamage(dmgtype: Integer; const origin, normal: vec3_t; damage: Integer);
procedure M_ReactToDamage(targ, attacker: edict_p);
function CheckTeamDamage(targ, attacker: edict_p): qboolean;
procedure T_Damage(targ, inflictor, attacker: edict_p; var dir, point, normal: vec3_t; damage, knockback, dflags, mofd: Integer);
procedure T_RadiusDamage(inflictor, attacker: edict_p; damage: Single; ignore: edict_p; radius: Single; mofd: Integer);
implementation
uses
GameUnit,
g_main,
cpas,
g_monster,
g_items,
g_ai,
g_cmds,
g_utils; // added by FAB
(* ============
CanDamage
Returns true if the inflictor can directly damage the target. Used for
explosions and melee attacks.
============ *)
function CanDamage(targ, inflictor: edict_p): 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: edict_p; damage: Integer; const 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 <> 0) AND (attacker^.client <> nil) 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; const 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: edict_p; const point, normal: vec3_t; damage, dflags: Integer): Integer;
var
client: gclient_p;
save, power_armor_type, index, damagePerCell, pa_te_type, power, power_used: Integer;
vec, forward_: vec3_t;
dot: Single;
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
// only works if damage point is in front
AngleVectors(ent^.s.angles, @forward_, Nil, Nil);
VectorSubtract(point, ent^.s.origin, vec);
VectorNormalize(vec);
dot := DotProduct(vec, forward_);
if (dot <= 0.3) then
begin
Result := 0;
Exit;
end;
damagePerCell := 1;
pa_te_type := Ord(TE_SCREEN_SPARKS); // Check this typecast ...by FAB
damage := damage div 3;
end
else
begin
damagePerCell := 2;
pa_te_type := Ord(TE_SHIELD_SPARKS); // Check this typecast ...by FAB
damage := (2 * damage) div 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;
power_used := save mod 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: edict_p; const point, normal: vec3_t; damage, te_sparks, dflags: Integer): Integer;
var
client: gclient_p;
save, index: Integer;
armor: gitem_p;
begin
if (damage = 0) then
begin
Result := 0;
Exit;
end;
client := ent^.client;
if (client = Nil) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -