⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 g_ai.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ File(s): g_ai.c                                                            }
{ Content:                                                                   }
{                                                                            }
{ Initial conversion by : Scott Price                                        }
{ Initial conversion on : 09-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.                       }
{                                                                            }
{ NOTE!! This is same file than in CTF folder with same name                 }
{----------------------------------------------------------------------------}
unit g_ai;

interface

uses
  g_local;

function FindTarget(self: Pedict_t): qboolean;
//extern cvar_t	*maxclients;

function ai_checkattack(self: Pedict_t; dist: Single): qboolean;


var
  enemy_vis: qboolean;
  enemy_infront: qboolean;
  enemy_range: Integer;
  enemy_yaw: Single;



implementation

uses
  m_move;


(* =================
AI_SetSightClient

Called once each frame to set level.sight_client to the
player to be checked for in findtarget.

If all clients sare either dead or in notarget, sight_client
will be null.

In coop games, sight_client will cycle between the clients.
================= *)
procedure AI_SetSightClient;
var
  ent: Pedict_t;
  start, check: Integer;
begin
  if (level.sight_client = nil) then
     start := 1
  else
     start := (Cardinal(level.sight_client) - Cardinal(g_edicts)) div sizeof(edict_t);

  check := start;
  while (True) do begin
     Inc(check);

     if (check > game.maxclients) then
        check := 1;

     ent := @g_edicts[check];
     { TODO:  Translate the Following Line: }
     // ORIGINAL:  if (ent->inuse && ent->health > 0 && !(ent->flags & FL_NOTARGET) )
     if (ent^.inuse AND (ent^.health > 0) AND ((ent^.flags AND FL_NOTARGET) = 0)) then begin
        level.sight_client := ent;
        Exit;  // got one
     end;

     if (check = start) then begin
        level.sight_client := nil;
        Exit;  // nobody to see
     end;
  end;
end;

(* =============
ai_move

Move the specified distance at current facing.
This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward
============== *)
procedure ai_move(self: Pedict_t; dist: Single);
begin
  M_walkmove(self, self^.s.angles[YAW], dist);
end;

(* =============
ai_stand

Used for standing around and looking for players
Distance is for slight position adjustments needed by the animations
============== *)
procedure ai_stand(self: Pedict_t; dist: Single);
var
  v: vec3_t;
begin
  if (dist <> 0) then
     M_walkmove(self, self^.s.angles[YAW], dist);

  if ((self^.monsterinfo.aiflags AND AI_STAND_GROUND) <> 0) then begin
     if (self^.enemy <> 0) then begin
        VectorSubtract(self^.enemy^.s.origin, self^.s.origin, v);
        self^.ideal_yaw := vectoyaw(v);
        { TODO:  Translate the Line Below: }
        // ORIGINAL:  if (self->s.angles[YAW] <> self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND) then
        if ((self^.s.angles[YAW] <> self^.ideal_yaw) AND ((self^.monsterinfo.aiflags AND AI_TEMP_STAND_GROUND) <> 0)) then
        begin
           { TODO:  Translate the Line Below: }
           // ORIGINAL:  self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
           self^.monsterinfo.aiflags := self^.monsterinfo.aiflags AND (NOT (AI_STAND_GROUND OR AI_TEMP_STAND_GROUND));
           self^.monsterinfo.run(self);
        end;

        M_ChangeYaw(self);
        ai_checkattack(self, 0);
     end else
         FindTarget(self);

     Exit;
  end;

  if (FindTarget(self)) then
     Exit;

  if (level.time > self->monsterinfo.pausetime) then begin
     self^.monsterinfo.walk(self);
     Exit;
  end;

  { TODO:  Translate the Line Below: }
  // ORIGINAL:  if (!(self->spawnflags & 1) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time))
  if (((self^.spawnflags AND 1) = 0) AND (self^.monsterinfo.idle) AND (level.time > self^.monsterinfo.idle_time)) then
  begin
     { TODO:  Translate the Line Below: }
     if (self^.monsterinfo.idle_time) then begin
        self^.monsterinfo.idle(self);
        self^.monsterinfo.idle_time := level.time + 15 + random() * 15;
     end else begin
         self^.monsterinfo.idle_time := level.time + random() * 15;
     end;
  end;
end;

(* =============
ai_walk

The monster is walking it's beat
============= *)
procedure ai_walk(self: Pedict_t, dist: Single);
begin
  M_MoveToGoal(self, dist);

  // check for noticing a player
  if FindTarget(self) then
     Exit;

  { TODO:  Translate the Line Below: }
  // ORIGINAL:  if ((self->monsterinfo.search) && (level.time > self->monsterinfo.idle_time)) then begin
  if ((self^.monsterinfo.search) AND (level.time > self^.monsterinfo.idle_time)) then begin
     { TODO:  Translate the Line Below: }
     if (self^.monsterinfo.idle_time) begin
        self^.monsterinfo.search(self);
        self^.monsterinfo.idle_time := level.time + 15 + random() * 15;
     end else begin
         self^.monsterinfo.idle_time := level.time + random() * 15;
     end;
  end;
end;

(* =============
ai_charge

Turns towards target and advances
Use this call with a distnace of 0 to replace ai_face
============== *)
procedure ai_charge(self: Pedict_t; dist: Single);
var
  v: vec3_t;
begin
  VectorSubtract(self^.enemy^.s.origin, self^.s.origin, v);
  self^.ideal_yaw := vectoyaw(v);
  M_ChangeYaw(self);

  if (dist <> 0) then
     M_walkmove(self, self^.s.angles[YAW], dist);
end;

(* =============
ai_turn

don't move, but turn towards ideal_yaw
Distance is for slight position adjustments needed by the animations
============= *)
procedure ai_turn(self: Pedict_t; dist: Single);
begin
  if (dist <> 0) then
     M_walkmove(self, self^s.angles[YAW], dist);

  if FindTarget(self) then
     Exit;

  M_ChangeYaw(self);
end;

(*
.enemy
Will be world if not currently angry at anyone.

.movetarget
The next path spot to walk toward.  If .enemy, ignore .movetarget.
When an enemy is killed, the monster will try to return to it's path.

.hunt_time
Set to time + something when the player is in sight, but movement straight for
him is blocked.  This causes the monster to use wall following code for
movement direction instead of sighting on the player.

.ideal_yaw
A yaw angle of the intended direction, which will be turned towards at up
to 45 deg / state.  If the enemy is in view and hunt_time is not active,
this will be the exact line towards the enemy.

.pausetime
A monster will leave it's stand state and head towards it's .movetarget when
time > .pausetime.

walkmove(angle, speed) primitive is all or nothing  *)

(*
=============
range

returns the range catagorization of an entity reletive to self
0	melee range, will become hostile even if back is turned
1	visibility and infront, or visibility and show hostile
2	infront and show hostile
3	only triggered by damage
=============
*)
function range(self: Pedict_t; other: Pedict_t): Integer;
//function range(self, other: Pedict_t): Integer;
var
  v: vec3_t;
  len: Single;
begin
  VectorSubtract(self^.s.origin, other^.s.origin, v);
  len := VectorLength(v);

  if (len < MELEE_DISTANCE) then begin
     Result := RANGE_MELEE;
     Exit;
  end;

  if (len < 500) then begin
     Result := RANGE_NEAR;
     Exit;
  end;

  if (len < 1000) then begin
     Result := RANGE_MID;
     Exit;
  end;

  Result := RANGE_FAR;
end;

(* =============
visible

returns 1 if the entity is visible to self, even if not infront ()
============= *)
function visible(self: Pedict_t; other: Pedict_t): qboolean;
//function visible(self, other: Pedict_t): qboolean;
var
  spot1: vec3_t;
  spot2: vec3_t;
  trace: trace_t;
begin
  VectorCopy(self^.s.origin, spot1);
  //spot1[2] += self->viewheight;  <-- TODO:  Check this Translation
  spot1[2] := (spot1[2] + self^.viewheight);

  VectorCopy(other^.s.origin, spot2);
  //spot2[2] += other->viewheight;  <-- TODO:  Check this Translation
  spot2[2] := (spot2[2] + other^.viewheight);
  trace := gi.trace(spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);

  if (trace.fraction = 1.0) then begin
     Result := True;
     Exit;
  end;

  Result := False;
end;

(* =============
infront

returns 1 if the entity is in front (in sight) of self
============= *)
function infront(self: Pedict_t; other: Pedict_t): qboolean;
//function infront(self, other: Pedict_t): qboolean;
var
  vec: vec3_t;
  dot: Single;
  forward_: vec3_t;
begin
  AngleVectors(self^.s.angles, forward_, NULL, NULL);
  VectorSubtract(other^.s.origin, self^.s.origin, vec);
  VectorNormalize(vec);
  dot := DotProduct(vec, forward_);

  if (dot > 0.3) then begin
     Result := True;
     Exit;
  end;

  Result := False;
end;


//============================================================================

procedure HuntTarget(self: Pedict_t);
var
  vec: vec3_t;
begin
  self^.goalentity := self^.enemy;
  if ((self^.monsterinfo.aiflags AND AI_STAND_GROUND) <> 0) then
     self^.monsterinfo.stand(self);
  else
     self^.monsterinfo.run(self);

  VectorSubtract(self^.enemy^.s.origin, self^.s.origin, vec);
  self^.ideal_yaw := vectoyaw(vec);
  { wait a while before first attack }
  if ((self^.monsterinfo.aiflags AND AI_STAND_GROUND) = 0) then
     AttackFinished(self, 1);
end;

procedure FoundTarget(self: Pedict_t);
begin
  { let other monsters see this monster for a while }
  if (self^.enemy^.client) then begin
     level.sight_entity := self;
     level.sight_entity_framenum := level.framenum;
     level.sight_entity^.light_level := 128;
  end;

  { wake up other monsters }
  self^.show_hostile := level.time + 1;

  VectorCopy(self^.enemy^.s.origin, self^.monsterinfo.last_sighting);
  self^.monsterinfo.trail_time := level.time;

  if (NOT self^.combattarget) then begin
     HuntTarget(self);
     Exit;
  end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -