📄 g_weapon.pas
字号:
{----------------------------------------------------------------------------}
{ }
{ File(s): g_weapon.c }
{ }
{ Initial conversion by : YgriK (Igor Karpov) - glYgriK@hotbox.ru }
{ Initial conversion on : 24-Jan-2002 }
{ }
{ 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 : 20 Sept 2002 }
{ Updated by : Fabrizio Rossini (FAB) }
{ Completed translation }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ }
{ }
{----------------------------------------------------------------------------}
{ * TODO: }
{ 1) Do more tests and check for error }
{ }
{----------------------------------------------------------------------------}
unit g_weapon;
interface
//...
uses
q_shared,
g_local,
g_local_add;
procedure fire_grenade (self : edict_p; const start, aimdir : vec3_t; damage, speed : integer; timer, damage_radius : Single);
procedure fire_grenade2 (self : edict_p; const start, aimdir : vec3_t; damage, speed : integer; timer, damage_radius : Single; held : qboolean);
procedure fire_rocket (self : edict_p; const start, dir : vec3_t; damage, speed : integer; damage_radius : Single; radius_damage: Integer);
procedure fire_blaster (self : edict_p; var start, dir : vec3_t; damage, speed, effect : integer; hyper : qboolean);
procedure fire_bullet (self : edict_p; var start, aimdir : vec3_t; damage, kick, hspread, vspread, mod_ : integer);
procedure fire_shotgun (self : edict_p; var start, aimdir : vec3_t; damage, kick, hspread, vspread, count, mod_ : integer);
procedure fire_rail (self : edict_p; var start, aimdir : vec3_t; damage, kick : integer);
procedure fire_bfg (self : edict_p; const start, dir : vec3_t; damage, speed : integer; damage_radius : Single);
function fire_hit (self : edict_p; var aim : vec3_t; damage, kick : integer) : qboolean;
implementation
uses
g_main,
GameUnit,
g_ai,
g_combat,
g_utils,
p_weapon,
g_misc,
q_shared_add,
game_add,
CPas;
{*
=================
check_dodge
This is a support routine used when a client is firing
a non-instant attack weapon. It checks to see if a
monster's dodge function should be called.
=================
*}
procedure check_dodge (self : edict_p; const start, dir : vec3_t; speed : integer);
var
end_,
v : vec3_t;
tr : trace_t;
eta : Single;
begin
// easy mode only ducks one quarter the time
if (skill^.value = 0) then
if (_random() > 0.25) then
Exit;
VectorMA (start, 8192, dir, end_);
tr := gi.trace(@start, Nil, Nil, @end_, self, MASK_SHOT);
if ( (tr.ent <> Nil) AND ((edict_p(tr.ent)^.svflags AND SVF_MONSTER) <> 0) AND
(edict_p(tr.ent)^.health > 0) AND (@edict_p(tr.ent)^.monsterinfo.dodge <> Nil) AND (not infront(tr.ent, self)) ) then
begin
VectorSubtract (tr.endpos, start, v);
eta := (VectorLength(v) - edict_p(tr.ent)^.maxs[0]) / speed;
edict_p(tr.ent)^.monsterinfo.dodge (tr.ent, self, eta);
end;
end;
{*
=================
fire_hit
Used for all impact (hit/punch/slash) attacks
=================
*}
//function fire_hit (edict_t *self, vec3_t aim, int damage, int kick) : qboolean;
function fire_hit (self : edict_p; var aim : vec3_t; damage, kick : integer) : qboolean;
var
tr : trace_t;
forward_,
right, up,
v,
point,
dir : vec3_t;
range : Single;
begin
//see if enemy is in range
VectorSubtract (self.enemy^.s.origin, self.s.origin, dir);
range := VectorLength(dir);
if (range > aim[0]) then
begin
Result := false;
Exit;
end;
if (aim[1] > self.mins[0]) AND (aim[1] < self.maxs[0])
then begin
// the hit is straight on so back the range up to the edge of their bbox
range := range - self.enemy^.maxs[0];
end
else begin
// this is a side hit so adjust the "right" value out to the edge of their bbox
if (aim[1] < 0) then
aim[1] := self.enemy^.mins[0]
else
aim[1] := self.enemy^.maxs[0];
end;
VectorMA (self.s.origin, range, dir, point);
tr := gi.trace (@self.s.origin, Nil, Nil, @point, self, MASK_SHOT);
if (tr.fraction < 1) then
begin
if (edict_p(tr.ent)^.takedamage = DAMAGE_NO ) then
begin
Result := false;
Exit;
end;
// if it will hit any client/monster then hit the one we wanted to hit
if ( ((edict_p(tr.ent)^.svflags AND SVF_MONSTER) <> 0) OR (edict_p(tr.ent)^.client <> Nil) ) then
tr.ent := self.enemy;
end;
AngleVectors(self.s.angles, @forward_, @right, @up);
VectorMA (self.s.origin, range, forward_, point);
VectorMA (point, aim[1], right, point);
VectorMA (point, aim[2], up, point);
VectorSubtract (point, self.enemy^.s.origin, dir);
// do the damage
T_Damage (tr.ent, @self, @self, dir, point, vec3_origin, damage, kick div 2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
{ if (!(tr.ent.svflags & SVF_MONSTER) and (!tr.ent.client)) then }
if ( ((edict_p(tr.ent).svflags AND SVF_MONSTER) = 0) AND (edict_p(tr.ent).client = nil) ) then
begin
Result := false;
Exit;
end;
// do our special form of knockback here
VectorMA (self.enemy^.absmin, 0.5, self.enemy^.size, v);
VectorSubtract (v, point, v);
VectorNormalize (v);
VectorMA (self.enemy^.velocity, kick, v, self.enemy^.velocity);
if (self.enemy^.velocity[2] > 0) then
self.enemy^.groundentity := Nil;
Result := true;
end;
{*
=================
fire_lead
This is an internal support routine used for bullet/pellet based weapons.
=================
*}
procedure fire_lead (self : edict_p; var start, aimdir : vec3_t; damage, kick, te_impact, hspread, vspread, mod_ : integer);
var
tr : trace_t;
dir,
forward_,
right, up,
end_,
water_start,
pos : vec3_t;
r, u : Single;
water : qboolean;
color,
content_mask : integer;
begin
{ qboolean water = false;
int content_mask = MASK_SHOT | MASK_WATER;}
water := false;
content_mask := MASK_SHOT OR MASK_WATER;
tr := gi.trace (@self.s.origin, Nil, Nil, @start, self, MASK_SHOT);
if ((tr.fraction < 1.0) = False) then
begin
vectoangles (aimdir, dir);
AngleVectors (dir, @forward_, @right, @up);
r := crandom()*hspread;
u := crandom()*vspread;
VectorMA (start, 8192, forward_, end_);
VectorMA (end_, r, right, end_);
VectorMA (end_, u, up, end_);
{ if (gi.pointcontents (start) & MASK_WATER) then }
if (gi.pointcontents (start) AND MASK_WATER) <> 0 then
begin
water := true;
VectorCopy (start, water_start);
content_mask := content_mask AND (NOT MASK_WATER);
end;
tr := gi.trace (@start, Nil, Nil, @end_, self, content_mask);
// see if we hit water
if (tr.contents AND MASK_WATER) <> 0 then
begin
water := true;
VectorCopy (tr.endpos, water_start);
if (VectorCompare (start, tr.endpos) = 0) then
begin
if (tr.contents AND CONTENTS_WATER) <> 0 then
begin
if (strcmp(tr.surface^.name, '*brwater') = 0) then
color := SPLASH_BROWN_WATER
else
color := SPLASH_BLUE_WATER;
end
else if (tr.contents AND CONTENTS_SLIME) <> 0 then
color := SPLASH_SLIME
else if (tr.contents AND CONTENTS_LAVA) <> 0 then
color := SPLASH_LAVA
else
color := SPLASH_UNKNOWN;
if (color <> SPLASH_UNKNOWN) then
begin
gi.WriteByte (svc_temp_entity);
gi.WriteByte (integer(TE_SPLASH));
gi.WriteByte (8);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.WriteByte (color);
gi.multicast (@tr.endpos, MULTICAST_PVS);
end;
// change bullet's course when it enters water
VectorSubtract (end_, start, dir);
vectoangles (dir, dir);
AngleVectors (dir, @forward_, @right, @up);
r := crandom()*hspread*2;
u := crandom()*vspread*2;
VectorMA (water_start, 8192, forward_, end_);
VectorMA (end_, r, right, end_);
VectorMA (end_, u, up, end_);
end;
// re-trace ignoring water this time
tr := gi.trace(@water_start, Nil, Nil, @end_, self, MASK_SHOT);
end;
end;
// send gun puff / flash
if NOT ( (tr.surface <> Nil) AND ((tr.surface^.flags AND SURF_SKY) <> 0) ) then
begin
if (tr.fraction < 1.0) then
if (edict_p(tr.ent)^.takedamage <> DAMAGE_NO) then
T_Damage(tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod_)
else
if (strncmp (tr.surface^.name, 'sky', 3) <> 0) then
begin
gi.WriteByte (svc_temp_entity);
gi.WriteByte (te_impact);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.multicast (@tr.endpos, MULTICAST_PVS);
if (self^.client <> nil) then
PlayerNoise (self, tr.endpos, PNOISE_IMPACT);
end;
end;
// if went through water, determine where the end and make a bubble trail
if (water) then
begin
VectorSubtract (tr.endpos, water_start, dir);
VectorNormalize (dir);
VectorMA (tr.endpos, -2, dir, pos);
if ((gi.pointcontents (pos) AND MASK_WATER) <> 0) then
VectorCopy(pos, tr.endpos)
else
tr := gi.trace(@pos, Nil, Nil, @water_start, tr.ent, MASK_WATER);
VectorAdd (water_start, tr.endpos, pos);
VectorScale (pos, 0.5, pos);
gi.WriteByte (svc_temp_entity);
gi.WriteByte (integer(TE_BUBBLETRAIL));
gi.WritePosition (water_start);
gi.WritePosition (tr.endpos);
gi.multicast (@pos, MULTICAST_PVS);
end;
end;
{*
=================
fire_bullet
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -