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

📄 g_func.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ File(s): g_func.pas                                                        }
{ Content: Quake2\Game-CTF\ Server commands                                  }
{                                                                            }
{ Initial conversion by : you_known - you_known@163.com                      }
{ Initial conversion on : 03-Feb-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:                                                                 }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on:                               }
{                                                                            }
{----------------------------------------------------------------------------}
{ * TODO:                                                                    }
{                                                                            }
{----------------------------------------------------------------------------}

unit g_func;

interface

uses g_local,SysUtils;

type pedict_t  = ^edict_t;
     pcplane_t = ^cplane_t;
     pcsurface_t = ^csurface_t;
     pmoveinfo = ^moveinfo;
     qboolean  = boolean;

(*
=========================================================

  PLATS

  movement options:

  linear
  smooth start, hard stop
  smooth start, smooth stop

  start
  end
  acceleration
  speed
  deceleration
  begin sound
  end sound
  target fired when reaching end
  wait at end

  object characteristics that use move segments
  ---------------------------------------------
  movetype_push, or movetype_stop
  action when touched
  action when blocked
  action when used
  disabled?
  auto trigger spawning


=========================================================
*)

const  PLAT_LOW_TRIGGER = 1;
  
    STATE_TOP    = 0;
    STATE_BOTTOM = 1;
    STATE_UP     = 2;
    STATE_DOWN   = 3;

    DOOR_START_OPEN =  1;
    DOOR_REVERSE    =  2;
    DOOR_CRUSHER    =  4;
    DOOR_NOMONSTER  =  8;
    DOOR_TOGGLE     = 32;
    DOOR_X_AXIS     = 64;
    DOOR_Y_AXIS     =128;

procedure Think_AccelMove (ent:pedict_t);

procedure plat_go_down (ent:pedict_t);

procedure door_go_down (self:pedict_t);

procedure train_next (self:pedict_t);

procedure door_secret_move1 (self:pedict_t);
procedure door_secret_move2 (self:pedict_t);
procedure door_secret_move3 (self:pedict_t);
procedure door_secret_move4 (self:pedict_t);
procedure door_secret_move5 (self:pedict_t);
procedure door_secret_move6 (self:pedict_t);
procedure door_secret_done (self:pedict_t);

implementation
//
// Support routines for movement (changes in origin using velocity)
//

procedure Move_Done (ent:pedict_t);
begin
  VectorClear (ent^.velocity);
  ent^.moveinfo.endfunc (ent);
end;

procedure Move_Final (ent:pedict_t);
begin
  if (ent^.moveinfo.remaining_distance = 0) then
  begin
    Move_Done (ent);
    exit;
  end;

  VectorScale (ent^.moveinfo.dir, ent^.moveinfo.remaining_distance / FRAMETIME, ent^.velocity);

  ent^.think := Move_Done;
  ent^.nextthink := level.time + FRAMETIME;
end;

procedure Move_Begin (ent:pedict_t);
var
  frames:single;
begin
  if ((ent^.moveinfo.speed * FRAMETIME) >= ent^.moveinfo.remaining_distance) then
  begin
    Move_Final (ent);
    exit;
  end;
  VectorScale (ent^.moveinfo.dir, ent^.moveinfo.speed, ent^.velocity);
  frames := floor((ent^.moveinfo.remaining_distance / ent^.moveinfo.speed) / FRAMETIME);
  ent^.moveinfo.remaining_distance -:= frames * ent^.moveinfo.speed * FRAMETIME;
  ent^.nextthink := level.time + (frames * FRAMETIME);
  ent^.think := Move_Final;
end;



procedure Move_Calc (ent:pedict_t, vec3_t dest, procedure(*func)(edict_t**));
begin
  VectorClear (ent^.velocity);
  VectorSubtract (dest, ent^.s.origin, ent^.moveinfo.dir);
  ent^.moveinfo.remaining_distance := VectorNormalize (ent^.moveinfo.dir);
  ent^.moveinfo.endfunc := func;

  if (ent^.moveinfo.speed = ent^.moveinfo.accel andand ent^.moveinfo.speed = ent^.moveinfo.decel) then
  begin
    if (level.current_entity  = (if (ent^.flags and FL_TEAMSLAVE)=1 then ent^.teammaster else ent)) then
    begin
      Move_Begin (ent);
    end
    else
    begin
      ent^.nextthink := level.time + FRAMETIME;
      ent^.think := Move_Begin;
    end;
  end
  else
  begin
    // accelerative
    ent^.moveinfo.current_speed := 0;
    ent^.think := Think_AccelMove;
    ent^.nextthink := level.time + FRAMETIME;
  end;
end;


//
// Support routines for angular movement (changes in angle using avelocity)
//

procedure AngleMove_Done (ent:pedict_t);
begin
  VectorClear (ent^.avelocity);
  ent^.moveinfo.endfunc (ent);
end;

procedure AngleMove_Final (ent:pedict_t);
var
  move:vec3_t;
begin
  if (ent^.moveinfo.state = STATE_UP) then
    VectorSubtract (ent^.moveinfo.end_angles, ent^.s.angles, move)
  else
    VectorSubtract (ent^.moveinfo.start_angles, ent^.s.angles, move);

  if (VectorCompare (move, vec3_origin)) then
  begin
    AngleMove_Done (ent);
    exit;
  end;

  VectorScale (move, 1.0/FRAMETIME, ent^.avelocity);

  ent^.think := AngleMove_Done;
  ent^.nextthink := level.time + FRAMETIME;
end;

procedure AngleMove_Begin (ent:pedict_t);
var
  destdelta:vec3_t;
  len:single;
  traveltime:single;
  frames:single;
begin
  // set destdelta to the vector needed to move
  if (ent^.moveinfo.state = STATE_UP) then
    VectorSubtract (ent^.moveinfo.end_angles, ent^.s.angles, destdelta) 
  else
    VectorSubtract (ent^.moveinfo.start_angles, ent^.s.angles, destdelta);
  
  // calculate length of vector
  len := VectorLength (destdelta);
  
  // divide by speed to get time to reach dest
  traveltime := len / ent^.moveinfo.speed;

  if (traveltime < FRAMETIME) then
  begin
    AngleMove_Final (ent);
    exit;
  end;

  frames := floor(traveltime / FRAMETIME);

  // scale the destdelta vector by the time spent traveling to get velocity
  VectorScale (destdelta, 1.0 / traveltime, ent^.avelocity);

  // set nextthink to trigger a think when dest is reached
  ent^.nextthink := level.time + frames * FRAMETIME;
  ent^.think := AngleMove_Final;
end;

procedure AngleMove_Calc (ent:pedict_t, procedure(*func)(edict_t**));
begin
  VectorClear (ent^.avelocity);
  ent^.moveinfo.endfunc := func;
  if (level.current_entity = (if (ent^.flags and FL_TEAMSLAVE)=1 then ent^.teammaster else ent)) then
  begin
    AngleMove_Begin (ent);
  end
  else
  begin
    ent^.nextthink := level.time + FRAMETIME;
    ent^.think := AngleMove_Begin;
  end;
end;


(*
==============
Think_AccelMove

The team has completed a frame of movement, so
change the speed for the next frame
==============
*)
const AccelerationDistance(target, rate)=(target * ((target / rate) + 1) / 2);

procedure plat_CalcAcceleratedMove(moveinfo:pmoveinfo_t);
var
  accel_dist:single;
  decel_dist:single;
  f:single;
begin
  moveinfo^.move_speed := moveinfo^.speed;

  if (moveinfo^.remaining_distance < moveinfo^.accel) then
  begin
    moveinfo^.current_speed := moveinfo^.remaining_distance;
    exit;
  end;

  accel_dist := AccelerationDistance (moveinfo^.speed, moveinfo^.accel);
  decel_dist := AccelerationDistance (moveinfo^.speed, moveinfo^.decel);

  if ((moveinfo^.remaining_distance - accel_dist - decel_dist) < 0) then
  begin


    f := (moveinfo^.accel + moveinfo^.decel) / (moveinfo^.accel * moveinfo^.decel);
    moveinfo^.move_speed := (-2 + sqrt(4 - 4 * f * (-2 * moveinfo^.remaining_distance))) / (2 * f);
    decel_dist := AccelerationDistance (moveinfo^.move_speed, moveinfo^.decel);
  end;

  moveinfo^.decel_distance := decel_dist;
end;

procedure plat_Accelerate (moveinfo:pmoveinfo_t);
var
    p1_distance:single;
    p2_distance:single;
    distance:single;
    old_speed:single;
    p1_speed:single;
  
begin
  // are we decelerating?
  if (moveinfo^.remaining_distance <= moveinfo^.decel_distance) then
  begin
    if (moveinfo^.remaining_distance < moveinfo^.decel_distance) then
    begin
      if (moveinfo^.next_speed) then
      begin
        moveinfo^.current_speed := moveinfo^.next_speed;
        moveinfo^.next_speed := 0;
        exit;
      end;
      if (moveinfo^.current_speed > moveinfo^.decel) then
        moveinfo^.current_speed := moveinfo^.current_speed - moveinfo^.decel;
    end;
    exit;
  end;

  // are we at full speed and need to start decelerating during this move?
  if (moveinfo^.current_speed = moveinfo^.move_speed) then
    if ((moveinfo^.remaining_distance - moveinfo^.current_speed) < moveinfo^.decel_distance) then
    begin


      p1_distance := moveinfo^.remaining_distance - moveinfo^.decel_distance;
      p2_distance := moveinfo^.move_speed * (1.0 - (p1_distance / moveinfo^.move_speed));
      distance := p1_distance + p2_distance;
      moveinfo^.current_speed := moveinfo^.move_speed;
      moveinfo^.next_speed := moveinfo^.move_speed - moveinfo^.decel * (p2_distance / distance);
      exit;
    end;

  // are we accelerating?
  if (moveinfo^.current_speed < moveinfo^.speed) then
  begin


    old_speed := moveinfo^.current_speed;

    // figure simple acceleration up to move_speed
    moveinfo^.current_speed := moveinfo^.current_speed + moveinfo^.accel;
    if (moveinfo^.current_speed > moveinfo^.speed) then
      moveinfo^.current_speed := moveinfo^.speed;

    // are we accelerating throughout this entire move?
    if ((moveinfo^.remaining_distance - moveinfo^.current_speed) >= moveinfo^.decel_distance) then
      exit;

    // during this move we will accelrate from current_speed to move_speed
    // and cross over the decel_distance; figure the average speed for the
    // entire move
    p1_distance := moveinfo^.remaining_distance - moveinfo^.decel_distance;
    p1_speed := (old_speed + moveinfo^.move_speed) / 2.0;
    p2_distance := moveinfo^.move_speed * (1.0 - (p1_distance / p1_speed));
    distance := p1_distance + p2_distance;
    moveinfo^.current_speed := (p1_speed * (p1_distance / distance)) + (moveinfo^.move_speed * (p2_distance / distance));
    moveinfo^.next_speed := moveinfo^.move_speed - moveinfo^.decel * (p2_distance / distance);
    exit;
  end;

  // we are at constant velocity (move_speed)
  exit;
end;

procedure Think_AccelMove (ent:pedict_t);
begin
  ent^.moveinfo.remaining_distance := ent^.moveinfo.remaining_distance - ent^.moveinfo.current_speed;

  if (ent^.moveinfo.current_speed = 0) then    // starting or blocked
    plat_CalcAcceleratedMove(andent^.moveinfo);

  plat_Accelerate (andent^.moveinfo);

  // will the entire move complete on next frame?
  if (ent^.moveinfo.remaining_distance <:= ent^.moveinfo.current_speed) then
  begin
    Move_Final (ent);
    exit;
  end;

  VectorScale (ent^.moveinfo.dir, ent^.moveinfo.current_speed*10, ent^.velocity);
  ent^.nextthink := level.time + FRAMETIME;
  ent^.think := Think_AccelMove;
end;




procedure plat_hit_top (ent:pedict_t);
begin
  if (not (ent^.flags and FL_TEAMSLAVE)) then
  begin
    if (ent^.moveinfo.sound_end) then
      gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent^.moveinfo.sound_end, 1, ATTN_STATIC, 0);
    ent^.s.sound := 0;
  end;
  ent^.moveinfo.state := STATE_TOP;

  ent^.think := plat_go_down;
  ent^.nextthink := level.time + 3;
end;

procedure plat_hit_bottom (ent:pedict_t);
begin
  if (not (ent^.flags and FL_TEAMSLAVE)) then
  begin;
    if (ent^.moveinfo.sound_end) then
      gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent^.moveinfo.sound_end, 1, ATTN_STATIC, 0);
    ent^.s.sound := 0;
  end;
  ent^.moveinfo.state := STATE_BOTTOM;
end;

procedure plat_go_down (ent:pedict_t);
begin
  if (not (ent^.flags and FL_TEAMSLAVE)) then
  begin
    if (ent^.moveinfo.sound_start) then
      gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent^.moveinfo.sound_start, 1, ATTN_STATIC, 0);
    ent^.s.sound := ent^.moveinfo.sound_middle;
  end;
  ent^.moveinfo.state := STATE_DOWN;
  Move_Calc (ent, ent^.moveinfo.end_origin, plat_hit_bottom);
end;

procedure plat_go_up (ent:pedict_t);
begin
  if (not (ent^.flags and FL_TEAMSLAVE)) then
  begin
    if (ent^.moveinfo.sound_start) then
      gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent^.moveinfo.sound_start, 1, ATTN_STATIC, 0);
    ent^.s.sound := ent^.moveinfo.sound_middle;
  end;
  ent^.moveinfo.state := STATE_UP;
  Move_Calc (ent, ent^.moveinfo.start_origin, plat_hit_top);
end;

procedure plat_blocked (self:pedict_t; other:pedict_t);
begin
  if (not (other^.svflags and SVF_MONSTER) andand (not other^.client) ) then
  begin
    // give it a chance to go away on it's own terms (like gibs)
    T_Damage (other, self, self, vec3_origin, other^.s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
    // if it's still there, nuke it
    if (other) then
      BecomeExplosion1 (other);
    exit;
  end;

  T_Damage (other, self, self, vec3_origin, other^.s.origin, vec3_origin, self^.dmg, 1, 0, MOD_CRUSH);

  if (self^.moveinfo.state = STATE_UP) then
    plat_go_down (self)
  else if (self^.moveinfo.state = STATE_DOWN) then
    plat_go_up (self);
end;


procedure Use_Plat (ent:pedict_t; other:pedict_t;activator:pedict_t);
begin 
  if (ent^.think) then
    exit;    // already down
  plat_go_down (ent);
end;


procedure Touch_Plat_Center (ent:pedict_t; other:pedict_t; plane:pcplane_t; surf:pcsurface_t);
begin
  if (not other^.client) then
    exit;
    
  if (other^.health <= 0) then
    exit;

  ent := ent^.enemy;  // now point at the plat, not the trigger
  if (ent^.moveinfo.state = STATE_BOTTOM) then
    plat_go_up (ent)
  else if (ent^.moveinfo.state :=:= STATE_TOP) then
    ent^.nextthink := level.time + 1;  // the player is still on the plat, so delay going down
end;

procedure plat_spawn_inside_trigger (ent:pedict_t);
var
  trigger:pedict_t;
  tmin, tmax:vec3_t;
begin
//
// middle trigger
//  
  trigger := G_Spawn();
  trigger^.touch := Touch_Plat_Center;
  trigger^.movetype := MOVETYPE_NONE;
  trigger^.solid := SOLID_TRIGGER;
  trigger^.enemy := ent;
  
  tmin[0] := ent^.mins[0] + 25;
  tmin[1] := ent^.mins[1] + 25;
  tmin[2] := ent^.mins[2];

  tmax[0] := ent^.maxs[0] - 25;
  tmax[1] := ent^.maxs[1] - 25;
  tmax[2] := ent^.maxs[2] + 8;

  tmin[2] := tmax[2] - (ent^.pos1[2] - ent^.pos2[2] + st.lip);

  if (ent^.spawnflags and PLAT_LOW_TRIGGER) then
    tmax[2] := tmin[2] + 8;
  
  if (tmax[0] - tmin[0] <= 0) then
  begin
    tmin[0] := (ent^.mins[0] + ent^.maxs[0]) *0.5;
    tmax[0] := tmin[0] + 1;
  end;
  if (tmax[1] - tmin[1] <= 0) then

⌨️ 快捷键说明

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