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

📄 g_func.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 4 页
字号:
(*
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.

*)
{******************************************************
   Name: g_func.pas
   Translator: you_known
   Description: a part of Quake 2 - Visual C to Delphi
                Conversion
   Date: 2002-02-03 16:43
   E-mail: you_known@163.com
******************************************************}

unit g_func;

interface

uses
  q_shared,
  GameUnit,
  g_local,
  g_combat,
  game_add,
  g_local_add,
  SysUtils;


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

  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: edict_p); cdecl;

procedure plat_go_down (ent:edict_p); cdecl;

procedure door_go_down (self:edict_p); cdecl;

procedure train_next (self:edict_p); cdecl;

procedure train_use (self:edict_p; other:edict_p; activator:edict_p); cdecl;
procedure func_train_find (self:edict_p); cdecl;


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

procedure SP_func_plat (ent:edict_p); cdecl;
procedure SP_func_button (ent:edict_p); cdecl;
procedure SP_func_door_rotating (ent:edict_p); cdecl;
procedure SP_func_rotating (ent:edict_p); cdecl;
procedure SP_func_door (ent:edict_p); cdecl;
procedure SP_func_water (self:edict_p); cdecl;
procedure SP_func_train (self:edict_p); cdecl;
procedure SP_func_timer (self:edict_p); cdecl;
procedure SP_func_conveyor (self:edict_p); cdecl;
procedure SP_func_door_secret (ent:edict_p); cdecl;
procedure SP_func_killbox (ent:edict_p); cdecl;
procedure SP_trigger_elevator (self:edict_p); cdecl;

implementation

uses
  g_misc,
  g_utils,
  g_save,
  g_main,
  q_shared_add;

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

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

procedure Move_Final (ent:edict_p); cdecl;
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:edict_p); cdecl;
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 := ent^.moveinfo.remaining_distance - frames * ent^.moveinfo.speed * FRAMETIME;
	ent^.nextthink := level.time + (frames * FRAMETIME);
	ent^.think := Move_Final;
end;



procedure Move_Calc (ent: edict_p; const dest: vec3_t; Func : Proc_edit_s);
var
  tempEdict : edict_p;
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) and (ent^.moveinfo.speed = ent^.moveinfo.decel) then
	begin
    if (ent^.flags and FL_TEAMSLAVE) <> 0 then
      tempEdict := ent^.teammaster
    else
      tempEdict := ent;
		if (level.current_entity  = tempEdict) 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:edict_p); cdecl;
begin
	VectorClear (ent^.avelocity);
	ent^.moveinfo.endfunc (ent);
end;

procedure AngleMove_Final (ent:edict_p); cdecl;
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) <> 0) 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:edict_p); cdecl;
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:edict_p; func : Proc_edit_s);
var
  tempEdict : edict_p;
begin
	VectorClear (ent^.avelocity);
	ent^.moveinfo.endfunc := func;
  if (ent^.flags and FL_TEAMSLAVE) <> 0 then
    tempEdict := ent^.teammaster
  else
    tempEdict := ent;
	if (level.current_entity = tempEdict) 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
==============
*)
function AccelerationDistance(target, rate : double):double;
begin
  Result := (target * ((target / rate) + 1) / 2);
end;

procedure plat_CalcAcceleratedMove(moveinfo:moveinfo_p);
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:moveinfo_p);
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 <> 0) 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:edict_p);
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(@ent^.moveinfo);

	plat_Accelerate (@ent^.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:edict_p); cdecl;
begin
	if ((ent^.flags and FL_TEAMSLAVE) = 0) then
	begin
		if (ent^.moveinfo.sound_end <> 0) 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:edict_p); cdecl;
begin
	if ((ent^.flags and FL_TEAMSLAVE) = 0) then
	begin;
		if (ent^.moveinfo.sound_end <> 0) 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:edict_p);
begin
	if ((ent^.flags and FL_TEAMSLAVE) = 0) then
	begin
		if (ent^.moveinfo.sound_start <> 0) 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:edict_p);
begin
	if ((ent^.flags and FL_TEAMSLAVE) = 0) then
	begin
		if (ent^.moveinfo.sound_start <> 0) 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:edict_p; other:edict_p); cdecl;
begin
	if ((other^.svflags and SVF_MONSTER = 0) and (other^.client = nil)) 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 assigned(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:edict_p; other:edict_p;activator:edict_p); cdecl;
begin
	if assigned(ent^.think) then
		exit;		// already down
	plat_go_down (ent);
end;


procedure Touch_Plat_Center (ent:edict_p; other:edict_p; plane:cplane_p; surf:csurface_p); cdecl;
begin
	if (other^.client = nil) 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:edict_p);
var
	trigger:edict_p;
	tmin, tmax:vec3_t;
begin
//
// middle trigger
//	
	trigger := G_Spawn();
	trigger^.touch := Touch_Plat_Center;

⌨️ 快捷键说明

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