📄 g_func.pas
字号:
begin
tmin[1] := (ent^.mins[1] + ent^.maxs[1]) *0.5;
tmax[1] := tmin[1] + 1;
end;
VectorCopy (tmin, trigger^.mins);
VectorCopy (tmax, trigger^.maxs);
gi.linkentity (trigger);
end;
(*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
speed default 150
Plats are always drawn in the extended position, so they will light correctly.
If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
"speed" overrides default 200.
"accel" overrides default 500
"lip" overrides default 8 pixel lip
If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height.
Set "sounds" to one of the following:
1) base fast
2) chain slow
*)
procedure SP_func_plat (ent:pedict_t);
begin
VectorClear (ent^.s.angles);
ent^.solid := SOLID_BSP;
ent^.movetype := MOVETYPE_PUSH;
gi.setmodel (ent, ent^.model);
ent^.blocked := plat_blocked;
if (not ent^.speed) then
ent^.speed := 20
else
ent^.speed := ent^.speed * 0.1;
if (not ent^.accel) then
ent^.accel := 5
else
ent^.accel := ent^.accel * 0.1;
if (not ent^.decel) then
ent^.decel := 5
else
ent^.decel := ent^.decel * 0.1;
if (not ent^.dmg) then
ent^.dmg := 2;
if (not st.lip) then
st.lip := 8;
// pos1 is the top position, pos2 is the bottom
VectorCopy (ent^.s.origin, ent^.pos1);
VectorCopy (ent^.s.origin, ent^.pos2);
if (st.height) then
ent^.pos2[2] -:= st.height
else
ent^.pos2[2] -:= (ent^.maxs[2] - ent^.mins[2]) - st.lip;
ent^.use := Use_Plat;
plat_spawn_inside_trigger (ent); // the "start moving" trigger
if (ent^.targetname) then
begin
ent^.moveinfo.state := STATE_UP;
end
else
begin
VectorCopy (ent^.pos2, ent^.s.origin);
gi.linkentity (ent);
ent^.moveinfo.state := STATE_BOTTOM;
end'
ent^.moveinfo.speed := ent^.speed;
ent^.moveinfo.accel := ent^.accel;
ent^.moveinfo.decel := ent^.decel;
ent^.moveinfo.wait := ent^.wait;
VectorCopy (ent^.pos1, ent^.moveinfo.start_origin);
VectorCopy (ent^.s.angles, ent^.moveinfo.start_angles);
VectorCopy (ent^.pos2, ent^.moveinfo.end_origin);
VectorCopy (ent^.s.angles, ent^.moveinfo.end_angles);
ent^.moveinfo.sound_start := gi.soundindex ('plats/pt1_strt.wav');
ent^.moveinfo.sound_middle := gi.soundindex ('plats/pt1_mid.wav');
ent^.moveinfo.sound_end := gi.soundindex ('plats/pt1_end.wav');
end;
//====================================================================
(*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS TOUCH_PAIN STOP ANIMATED ANIMATED_FAST
You need to have an origin brush as part of this entity. The center of that brush will be
the point around which it is rotated. It will rotate around the Z axis by default. You can
check either the X_AXIS or Y_AXIS box to change that.
"speed" determines how fast it moves; default value is 100.
"dmg" damage to inflict when blocked (2 default)
REVERSE will cause the it to rotate in the opposite direction.
STOP mean it will stop moving instead of pushing entities
*)
procedure rotating_blocked (self:pedict_t; other:pedict_t);
begin
T_Damage (other, self, self, vec3_origin, other^.s.origin, vec3_origin, self^.dmg, 1, 0, MOD_CRUSH);
end;
procedure rotating_touch (self:pedict_t; other:pedict_t; plane:pcplane_t; surf:pcsurface_t);
begin
if (self^.avelocity[0] or self^.avelocity[1] or self^.avelocity[2]) then
T_Damage (other, self, self, vec3_origin, other^.s.origin, vec3_origin, self^.dmg, 1, 0, MOD_CRUSH);
end;
procedure rotating_use (self:pedict_t; other:pedict_t;activator:pedict_t);
begin
if (not VectorCompare (self^.avelocity, vec3_origin)) then
begin
self^.s.sound := 0;
VectorClear (self^.avelocity);
self^.touch := nil;
end
else
begin
self^.s.sound := self^.moveinfo.sound_middle;
VectorScale (self^.movedir, self^.speed, self^.avelocity);
if (self^.spawnflags and 16) then
self^.touch := rotating_touch;
end;
end;
procedure SP_func_rotating (ent:pedict_t);
begin
ent^.solid := SOLID_BSP;
if (ent^.spawnflags and 32) then
ent^.movetype := MOVETYPE_STOP
else
ent^.movetype := MOVETYPE_PUSH;
// set the axis of rotation
VectorClear(ent^.movedir);
if (ent^.spawnflags and 4) then
ent^.movedir[2] := 1.0
else if (ent^.spawnflags and 8) then
ent^.movedir[0] := 1.0
else // Z_AXIS
ent^.movedir[1] := 1.0;
// check for reverse rotation
if (ent^.spawnflags and 2 ) then
VectorNegate (ent^.movedir, ent^.movedir);
if (not ent^.speed) then
ent^.speed := 100;
if (not ent^.dmg) then
ent^.dmg := 2;
// ent^.moveinfo.sound_middle := "doors/hydro1.wav";
ent^.use := rotating_use;
if (ent^.dmg) then
ent^.blocked := rotating_blocked;
if (ent^.spawnflags and 1) then
ent^.use (ent, nil, nil);
if (ent^.spawnflags and 64) then
ent^.s.effects := ent^.s.effects or EF_ANIM_ALL;
if (ent^.spawnflags and 128) then
ent^.s.effects := ent^.s.effects or EF_ANIM_ALLFAST;
gi.setmodel (ent, ent^.model);
gi.linkentity (ent);
end;
(*
======================================================================
BUTTONS
======================================================================
*)
(*QUAKED func_button (0 .5 .8) ?
When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then exits to it's original position where it can be triggered again.
"angle" determines the opening direction
"target" all entities with a matching targetname will be used
"speed" override the default 40 speed
"wait" override the default 1 second wait (-1 := never exit)
"lip" override the default 4 pixel lip remaining at end of move
"health" if set, the button must be killed instead of touched
"sounds"
1) silent
2) steam metal
3) wooden clunk
4) metallic click
5) in-out
*)
procedure button_done (self:pedict_t);
begin
self^.moveinfo.state := STATE_BOTTOM;
self^.s.effects := self^.s.effects and not EF_ANIM23;
self^.s.effects := self^.s.effects or EF_ANIM01;
end;
procedure button_exit (self:pedict_t);
begin
self^.moveinfo.state := STATE_DOWN;
Move_Calc (self, self^.moveinfo.start_origin, button_done);
self^.s.frame := 0;
if (self^.health)
self^.takedamage := DAMAGE_YES;
end;
procedure button_wait (self:pedict_t);
begin
self^.moveinfo.state := STATE_TOP;
self^.s.effects := self^.s.effects and not EF_ANIM01;
self^.s.effects := self^.s.effects or EF_ANIM23;
G_UseTargets (self, self^.activator);
self^.s.frame := 1;
if (self^.moveinfo.wait >= 0) then
begin
self^.nextthink := level.time + self^.moveinfo.wait;
self^.think := button_exit;
end;
end;
procedure button_fire (self:pedict_t);
begin
if (self^.moveinfo.state = STATE_UP or self^.moveinfo.state = STATE_TOP) then
exit;
self^.moveinfo.state := STATE_UP;
if (self^.moveinfo.sound_start and not (self^.flags and FL_TEAMSLAVE)) then
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self^.moveinfo.sound_start, 1, ATTN_STATIC, 0);
Move_Calc (self, self^.moveinfo.end_origin, button_wait);
end;
procedure button_use (self:pedict_t; other:pedict_t;activator:pedict_t);
begin
self^.activator := activator;
button_fire (self);
end;
procedure button_touch (self:pedict_t; other:pedict_t; plane:pcplane_t; surf:pcsurface_t);
begin
if (not other^.client) then
exit;
if (other^.health <= 0) then
exit;
self^.activator := other;
button_fire (self);
end;
procedure button_killed (self:pedict_t; inflictor :pedict_t; attacker:pedict_t ; damage:smallint;point:vec3_t );
begin
self^.activator := attacker;
self^.health := self^.max_health;
self^.takedamage := DAMAGE_NO;
button_fire (self);
end;
procedure SP_func_button (ent:pedict_t);
var
abs_movedir:vec3_t;
dist:single;
begin
G_SetMovedir (ent^.s.angles, ent^.movedir);
ent^.movetype := MOVETYPE_STOP;
ent^.solid := SOLID_BSP;
gi.setmodel (ent, ent^.model);
if (ent^.sounds <> 1) then
ent^.moveinfo.sound_start := gi.soundindex ('switches/butn2.wav');
if (not ent^.speed) then
ent^.speed := 40;
if (not ent^.accel) then
ent^.accel := ent^.speed;
if (not ent^.decel) then
ent^.decel := ent^.speed;
if (not ent^.wait) then
ent^.wait := 3;
if (not st.lip) then
st.lip := 4;
VectorCopy (ent^.s.origin, ent^.pos1);
abs_movedir[0] := fabs(ent^.movedir[0]);
abs_movedir[1] := fabs(ent^.movedir[1]);
abs_movedir[2] := fabs(ent^.movedir[2]);
dist := abs_movedir[0] * ent^.size[0] + abs_movedir[1] * ent^.size[1] + abs_movedir[2] * ent^.size[2] - st.lip;
VectorMA (ent^.pos1, dist, ent^.movedir, ent^.pos2);
ent^.use := button_use;
ent^.s.effects := ent^.s.effects or EF_ANIM01;
if (ent^.health) then
begin
ent^.max_health := ent^.health;
ent^.die := button_killed;
ent^.takedamage := DAMAGE_YES;
end
else if (not ent^.targetname) then
ent^.touch := button_touch;
ent^.moveinfo.state := STATE_BOTTOM;
ent^.moveinfo.speed := ent^.speed;
ent^.moveinfo.accel := ent^.accel;
ent^.moveinfo.decel := ent^.decel;
ent^.moveinfo.wait := ent^.wait;
VectorCopy (ent^.pos1, ent^.moveinfo.start_origin);
VectorCopy (ent^.s.angles, ent^.moveinfo.start_angles);
VectorCopy (ent^.pos2, ent^.moveinfo.end_origin);
VectorCopy (ent^.s.angles, ent^.moveinfo.end_angles);
gi.linkentity (ent);
end;
(*
======================================================================
DOORS
spawn a trigger surrounding the entire team unless it is
allready targeted by another
======================================================================
*)
(*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER NOMONSTER ANIMATED TOGGLE ANIMATED_FAST
TOGGLE wait in both the start and end states for a trigger event.
START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
NOMONSTER monsters will not trigger this door
"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
"angle" determines the opening direction
"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
"health" if set, door must be shot open
"speed" movement speed (100 default)
"wait" wait before exiting (3 default, -1 := never exit)
"lip" lip remaining at end of move (8 default)
"dmg" damage to inflict when blocked (2 default)
"sounds"
1) silent
2) light
3) medium
4) heavy
*)
procedure door_use_areaportals (self:pedict_t;open:qboolean);
var
t:pedict_t = nil;
begin
if (not self^.target) then
exit;
while ((t := G_Find (t, FOFS(targetname), self^.target))) do
begin
if (Q_stricmp(t^.classname, 'func_areaportal') = 0) then
begin
gi.SetAreaPortalState (t^.style, open);
end;
end;
end;
procedure door_hit_top (self:pedict_t);
begin
if (not (self^.flags and FL_TEAMSLAVE)) then
begin
if (self^.moveinfo.sound_end) then
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self^.moveinfo.sound_end, 1, ATTN_STATIC, 0);
self^.s.sound := 0;
end;
self^.moveinfo.state := STATE_TOP;
if (self^.spawnflags and DOOR_TOGGLE) then
exit;
if (self^.moveinfo.wait >= 0) then
begin
self^.think := door_go_down;
self^.nextthink := level.time + self^.moveinfo.wait;
end;
end;
procedure door_hit_bottom (self:pedict_t);
begin
if (not (self^.flags and FL_TEAMSLAVE)) then
begin
if (self^.moveinfo.sound_end) then
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self^.moveinfo.sound_end, 1, ATTN_STATIC, 0);
self^.s.sound := 0;
end;
self^.moveinfo.state := STATE_BOTTOM;
door_use_areaportals (self, false);
end;
procedure door_go_down (self:pedict_t);
begin
if (not (self^.flags and FL_TEAMSLAVE)) then
begin
if (self^.moveinfo.sound_start) then
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self^.moveinfo.sound_start, 1, ATTN_STATIC, 0);
self^.s.sound := self^.moveinfo.sound_middle;
end;
if (self^.max_health) then
begin
self^.takedamage := DAMAGE_YES;
self^.health := self^.max_health;
end;
self^.moveinfo.state := STATE_DOWN;
if (strcomp(self^.classname, 'func_door') = 0) then
Move_Calc (self, self^.moveinfo.start_origin, door_hit_bottom)
else if (strcomp(self^.classname, 'func_door_rotating') = 0) then
AngleMove_Calc (self, door_hit_bottom);
end;
procedure door_go_up (self:pedict_t; activator:pedict_t);
begin
if (self^.moveinfo.state = STATE_UP) then
exit; // already going up
if (self^.moveinfo.state = STATE_TOP) then
begin // reset top wait time
if (self^.moveinfo.wait >= 0) then
self^.nextthink := level.time + self^.moveinfo.wait;
exit;
end;
if (not (self^.flags and FL_TEAMSLAVE))
begin
if (self^.moveinfo.sound_start) then
gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self^.moveinfo.sound_start, 1, ATTN_STATIC, 0);
self^.s.sound := self^.moveinfo.sound_middle;
end;
self^.moveinfo.state := STATE_UP;
if (strcomp(self^.classname, 'func_door') = 0) then
Move_Calc (self, self^.moveinfo.end_origin, door_hit_top)
else if (strcomp(self^.classname, 'func_door_rotating') = 0) then
AngleMove_Calc (self, door_hit_top);
G_UseTargets (self, activator);
door_use_areaportals (self, true);
end;
procedure door_use (self:pedict_t; other:pedict_t;activator:pedict_t);
var
ent:pedict_t;
begin
if (self^.flags and FL_TEAMSLAVE) then
exit;
if (self^.spawnflags and DOOR_TOGGLE) then
begin
if (self^.moveinfo.state = STATE_UP or self^.moveinfo.state = STATE_TOP) then
begin
// trigger all paired doors
for ent := self to ent do
begin
ent^.message := nil;
ent^.touch := nil;
door_go_down (ent);
ent := ent^.teamchain;
end;
exit;
end;
end;
// trigger all paired doors
for ent := self to ent do
begin
ent^.message := nil;
ent^.touch := nil;
door_go_up (ent, activator);
ent := ent^.teamchain;
end;
end;
procedure Touch_DoorTrigger (self:pedict_t; other:pedict_t; plane:pcplane_t; surf:pcsurface_t);
begin
if (other^.health <= 0) then
exit;
if (not (other^.svflags and SVF_MONSTER) and (not other^.client)) then
exit;
if ((self^.owner^.spawnflags and DOOR_NOMONSTER) and (other^.svflags and SVF_MONSTER)) then
exit;
if (level.time < self^.touch_debounce_time) then
exit;
self^.touch_debounce_time := level.time + 1.0;
door_use (self^.owner, other, other);
end;
procedure Think_CalcMoveSpeed (self:pedict_t);
var
ent:pedict_t;
min:single;
time:single;
newspeed:single;
ratio:single;
dist:single;
begin
if (self^.flags and FL_TEAMSLAVE) then
exit; // only the team master does this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -