📄 g_trigger.pas
字号:
(*
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_trigger.pas
Translator: you_known
Description: a part of Quake 2 - Visual C to Delphi
Conversion
Date: 2002-02-03 12:59
E-mail: you_known@163.com
******************************************************}
unit g_trigger;
interface
uses g_local,SysUtils;
type pedict_t = ^edict_t;
pcplane_t = ^cplane_t;
pcsurface_t = ^csurface_t;
implementation
procedure InitTrigger (self:pedict_t);
begin
if (not VectorCompare (self^.s.angles, vec3_origin)) then
G_SetMovedir (self^.s.angles, self^.movedir);
self^.solid := SOLID_TRIGGER;
self^.movetype := MOVETYPE_NONE;
gi.setmodel (self, self^.model);
self^.svflags := SVF_NOCLIENT;
end;
// the wait time has passed, so set back up for another activation
procedure multi_wait (ent:pedict_t);
begin
ent^.nextthink := 0;
end;
// the trigger was just activated
// ent->activator should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
procedure multi_trigger (ent:pedict_t);
begin
if (ent^.nextthink) then
exit; // already been triggered
G_UseTargets (ent, ent^.activator);
if (ent^.wait > 0) then
begin
ent^.think := multi_wait;
ent^.nextthink := level.time + ent^.wait;
end
else
begin // we can't just remove (self) here, because this is a touch function
// called while looping through area links...
ent^.touch := NiL;
ent^.nextthink := level.time + FRAMETIME;
ent^.think := G_FreeEdict;
end;
end;
procedure Use_Multi (ent:pedict_t; other:pedict_t; activator:pedict_t);
begin
ent^.activator := activator;
multi_trigger (ent);
end;
procedure Touch_Multi (self:pedict_t; other:pedict_t; plane:pcplane_t; surf:pcsurface_t);
var forward:vec3_t;
begin
if(other^.client) then
begin
if (self^.spawnflags and 2) then
exit;
end
else if (other^.svflags and SVF_MONSTER) then
begin
if (not (self^.spawnflags and 1)) then
exit;
end
else
exit;
if (not VectorCompare(self^.movedir, vec3_origin)) then
begin
AngleVectors(other^.s.angles, forward, Nil, NiL);
if (_DotProduct(forward, self^.movedir) < 0) then
exit;
end;
self^.activator := other;
multi_trigger (self);
end;
(*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
Variable sized repeatable trigger. Must be targeted at one or more entities.
If 'delay' is set, the trigger waits some time after activating before firing.
'wait' : Seconds between triggerings. (.2 default)
sounds
1) secret
2) beep beep
3) large switch
4)
set 'message' to text string
*)
procedure trigger_enable (self:pedict_t; other:pedict_t; activator:pedict_t);
begin
self^.solid := SOLID_TRIGGER;
self^.use := Use_Multi;
gi.linkentity (self);
end;
procedure SP_trigger_multiple (ent:pedict_t);
begin
if (ent^.sounds = 1) then
ent^.noise_index := gi.soundindex ('misc/secret.wav')
else if (ent^.sounds = 2) then
ent^.noise_index := gi.soundindex ('misc/talk.wav')
else if (ent^.sounds = 3) then
ent^.noise_index := gi.soundindex ('misc/trigger1.wav');
if (not ent^.wait) then
ent^.wait := 0.2;
ent^.touch := Touch_Multi;
ent^.movetype := MOVETYPE_NONE;
ent^.svflags := ent^.svflags or SVF_NOCLIENT;
if (ent^.spawnflags and 4) then
begin
ent^.solid := SOLID_NOT;
ent^.use := trigger_enable;
end
else
begin
ent^.solid := SOLID_TRIGGER;
ent^.use := Use_Multi;
end;
if (not VectorCompare(ent^.s.angles, vec3_origin)) then
G_SetMovedir (ent^.s.angles, ent^.movedir);
gi.setmodel (ent, ent^.model);
gi.linkentity (ent);
end;
(*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
Triggers once, then removes itself.
You must set the key 'target' to the name of another object in the level that has a matching 'targetname'.
If TRIGGERED, this trigger must be triggered before it is live.
sounds
1) secret
2) beep beep
3) large switch
4)
'message' string to be displayed when triggered
*)
procedure SP_trigger_once(ent:pedict_t);
var v:vec3_t;
begin
// make old maps work because I messed up on flag assignments here
// triggered was on bit 1 when it should have been on bit 4
if (ent^.spawnflags and 1) then
begin
VectorMA (ent^.mins, 0.5, ent^.size, v);
ent^.spawnflags := ent^.spawnflags and (not 1);
ent^.spawnflags := ent^.spawnflags or 4;
gi.dprintf('fixed TRIGGERED flag on %s at %s\n', ent^.classname, vtos(v));
end;
ent^.wait := -1;
SP_trigger_multiple (ent);
end;
(*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
This fixed size trigger cannot be touched, it can only be fired by other events.
*)
procedure trigger_relay_use (self:pedict_t; other:pedict_t; activator:pedict_t);
begin
G_UseTargets (self, activator);
end;
procedure SP_trigger_relay ( self:pedict_t);
begin
self^.use := trigger_relay_use;
end;
(*
==============================================================================
trigger_key
==============================================================================
*)
(*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
A relay trigger that only fires it's targets if player has the proper key.
Use 'item' to specify the required key, for example 'key_data_cd'
*)
procedure trigger_key_use (self:pedict_t; other:pedict_t; activator:pedict_t);
var index:smallint;
player:smallint;
ent:pedict_t;
cube:smallint;
begin
if (not self^.item) then
exit;
if (not activator^.client) then
exit;
index := ITEM_INDEX(self^.item);
if (not activator^.client^.pers.inventory[index]) then
begin
if (level.time < self^.touch_debounce_time) then
exit;
self^.touch_debounce_time := level.time + 5.0;
gi.centerprintf (activator, 'You need the %s', self^.item^.pickup_name);
gi.sound (activator, CHAN_AUTO, gi.soundindex ('misc/keytry.wav'), 1, ATTN_NORM, 0);
exit;
end;
gi.sound (activator, CHAN_AUTO, gi.soundindex ('misc/keyuse.wav'), 1, ATTN_NORM, 0);
if (coop^.value) then
begin
if (strcomp(self^.item^.classname, 'key_power_cube') = 0) then
begin
for cube := 0 to 7 do
if (activator^.client^.pers.power_cubes and (1 shl cube)) then
break;
for player := 1 to game.maxclients do
begin
ent := @g_edicts[player];
if (not ent^.inuse) then
continue;
if (not ent^.client) then
continue;
if (ent^.client^.pers.power_cubes and (1 shl cube)) then
begin
ent^.client^.pers.inventory[index] := ent^.client^.pers.inventory[index] - 1;
ent^.client^.pers.power_cubes := ent^.client^.pers.power_cubes and (not(1 shl cube));
end;
end;
end
else
begin
for player := 1 to game.maxclients do
begin
ent := @g_edicts[player];
if (not ent^.inuse) then
continue;
if (not ent^.client) then
continue;
ent^.client^.pers.inventory[index] := 0;
end;
end;
end
else
begin
activator^.client^.pers.inventory[index] := activator^.client^.pers.inventory[index] - 1;
end;
G_UseTargets (self, activator);
self^.use := NiL;
end;
procedure SP_trigger_key (self:pedict_t);
begin
if (not st.item) then
begin
gi.dprintf('no key item for trigger_key at %s\n', vtos(self^.s.origin));
exit;
end;
self^.item := FindItemByClassname (st.item);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -