📄 g_func.pas
字号:
door_use (self^.owner, other, other);
end;
procedure Think_CalcMoveSpeed (self:edict_p); cdecl;
var
ent:edict_p;
min:single;
time:single;
newspeed:single;
ratio:single;
dist:single;
begin
if (self^.flags and FL_TEAMSLAVE<>0) then
exit; // only the team master does this
// find the smallest distance any member of the team will be moving
min := fabs(self^.moveinfo.distance);
ent := self^.teamchain;
while Assigned(ent) do
begin
dist := fabs(ent^.moveinfo.distance);
if (dist < min) then
min := dist;
ent := ent^.teamchain;
end;
time := min / self^.moveinfo.speed;
// adjust speeds so they will all complete at the same time
ent := Self;
while Assigned(ent) do
begin
newspeed := fabs(ent^.moveinfo.distance) / time;
ratio := newspeed / ent^.moveinfo.speed;
if (ent^.moveinfo.accel = ent^.moveinfo.speed) then
ent^.moveinfo.accel := newspeed
else
ent^.moveinfo.accel := ent^.moveinfo.accel * ratio;
if (ent^.moveinfo.decel = ent^.moveinfo.speed) then
ent^.moveinfo.decel := newspeed
else
ent^.moveinfo.decel := ent^.moveinfo.decel * ratio;
ent^.moveinfo.speed := newspeed;
ent := ent^.teamchain;
end;
end;
procedure Think_SpawnDoorTrigger (ent:edict_p); cdecl;
var
other:edict_p;
mins,maxs:vec3_t;
begin
if (ent^.flags and FL_TEAMSLAVE<>0) then
exit; // only the team leader spawns a trigger
VectorCopy (ent^.absmin, mins);
VectorCopy (ent^.absmax, maxs);
other := ent^.teamchain;
while Assigned(other) do
begin
AddPointToBounds (other^.absmin, mins, maxs);
AddPointToBounds (other^.absmax, mins, maxs);
other:=other^.teamchain;
end;
// expand
mins[0] := mins[0] - 60;
mins[1] := mins[1] - 60;
maxs[0] := maxs[0] + 60;
maxs[1] := maxs[1] + 60;
other := G_Spawn;
VectorCopy (mins, other^.mins);
VectorCopy (maxs, other^.maxs);
other^.owner := ent;
other^.solid := SOLID_TRIGGER;
other^.movetype := MOVETYPE_NONE;
other^.touch := Touch_DoorTrigger;
gi.linkentity (other);
if (ent^.spawnflags and DOOR_START_OPEN) <> 0 then
door_use_areaportals (ent, true);
Think_CalcMoveSpeed (ent);
end;
procedure door_blocked (self:edict_p; other:edict_p); cdecl;
var
ent:edict_p;
begin
if ((other^.svflags and SVF_MONSTER=0) and (not Assigned(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 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^.spawnflags and DOOR_CRUSHER<>0) then
exit;
// if a door has a negative wait, it would never come back if blocked,
// so let it just squash the object to death real fast
if (self^.moveinfo.wait >= 0) then
begin
if (self^.moveinfo.state = STATE_DOWN) then
begin
ent := self^.teammaster;
while Assigned(ent) do
begin
door_go_up (ent, ent^.activator);
ent := ent^.teamchain;
end;
end
else
begin
ent := self^.teammaster;
while Assigned(ent) do
begin
door_go_down (ent);
ent := ent^.teamchain;
end;
end;
end;
end;
procedure door_killed (self:edict_p; inflictor:edict_p ; attacker:edict_p ; damage:Integer; const point:vec3_t ); cdecl;
var
ent:edict_p;
begin
ent := self^.teammaster;
while Assigned(ent) do
begin
ent^.health := ent^.max_health;
ent^.takedamage := DAMAGE_NO;
ent:=ent^.teamchain;
end;
door_use (self^.teammaster, attacker, attacker);
end;
procedure door_touch (self:edict_p; other:edict_p; plane:cplane_p; surf:csurface_p); cdecl;
begin
if not Assigned(other^.client) then
exit;
if (level.time < self^.touch_debounce_time) then
exit;
self^.touch_debounce_time := level.time + 5.0;
gi.centerprintf (other, '%s', self^._message);
gi.sound (other, CHAN_AUTO, gi.soundindex ('misc/talk1.wav'), 1, ATTN_NORM, 0);
end;
procedure SP_func_door (ent:edict_p);
var
abs_movedir:vec3_t;
begin
if (ent^.sounds <> 1) then
begin
ent^.moveinfo.sound_start := gi.soundindex ('doors/dr1_strt.wav');
ent^.moveinfo.sound_middle := gi.soundindex ('doors/dr1_mid.wav');
ent^.moveinfo.sound_end := gi.soundindex ('doors/dr1_end.wav');
end;
G_SetMovedir (ent^.s.angles, ent^.movedir);
ent^.movetype := MOVETYPE_PUSH;
ent^.solid := SOLID_BSP;
gi.setmodel (ent, ent^.model);
ent^.blocked := door_blocked;
ent^.use := door_use;
if (ent^.speed = 0) then
ent^.speed := 100;
if (deathmatch^.Value <> 0) then
ent^.speed := ent^.speed * 2;
if (ent^.accel = 0) then
ent^.accel := ent^.speed;
if (ent^.decel = 0) then
ent^.decel := ent^.speed;
if (ent^.wait = 0) then
ent^.wait := 3;
if (st.lip = 0) then
st.lip := 8;
if (ent^.dmg = 0) then
ent^.dmg := 2;
// calculate second position
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]);
ent^.moveinfo.distance := abs_movedir[0] * ent^.size[0] + abs_movedir[1] * ent^.size[1] + abs_movedir[2] * ent^.size[2] - st.lip;
VectorMA (ent^.pos1, ent^.moveinfo.distance, ent^.movedir, ent^.pos2);
// if it starts open, switch the positions
if (ent^.spawnflags and DOOR_START_OPEN) <> 0 then
begin
VectorCopy (ent^.pos2, ent^.s.origin);
VectorCopy (ent^.pos1, ent^.pos2);
VectorCopy (ent^.s.origin, ent^.pos1);
end;
ent^.moveinfo.state := STATE_BOTTOM;
if (ent^.health) <> 0 then
begin
ent^.takedamage := DAMAGE_YES;
ent^.die := door_killed;
ent^.max_health := ent^.health;
end
else if Assigned(ent^.targetname) and Assigned(ent^._message) then
begin
gi.soundindex ('misc/talk.wav');
ent^.touch := door_touch;
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);
if (ent^.spawnflags and 16) <> 0 then
ent^.s.effects := ent^.s.effects or EF_ANIM_ALL;
if (ent^.spawnflags and 64) <> 0 then
ent^.s.effects := ent^.s.effects or EF_ANIM_ALLFAST;
// to simplify logic elsewhere, make non-teamed doors into a team of one
if not assigned(ent^.team) then
ent^.teammaster := ent;
gi.linkentity (ent);
ent^.nextthink := level.time + FRAMETIME;
if (ent^.health <> 0) or assigned(ent^.targetname) then
ent^.think := Think_CalcMoveSpeed
else
ent^.think := Think_SpawnDoorTrigger;
end;
(*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE CRUSHER NOMONSTER ANIMATED TOGGLE X_AXIS Y_AXIS
TOGGLE causes the door to 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
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.
"distance" is how many degrees the door will be rotated.
"speed" determines how fast the door moves; default value is 100.
REVERSE will cause the door to rotate in the opposite direction.
"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)
"dmg" damage to inflict when blocked (2 default)
"sounds"
1) silent
2) light
3) medium
4) heavy
*)
procedure SP_func_door_rotating (ent:edict_p);
begin
VectorClear (ent^.s.angles);
// set the axis of rotation
VectorClear(ent^.movedir);
if (ent^.spawnflags and DOOR_X_AXIS) <> 0 then
ent^.movedir[2] := 1.0
else if (ent^.spawnflags and DOOR_Y_AXIS) <> 0 then
ent^.movedir[0] := 1.0
else // Z_AXIS
ent^.movedir[1] := 1.0;
// check for reverse rotation
if (ent^.spawnflags and DOOR_REVERSE) <> 0 then
VectorNegate (ent^.movedir, ent^.movedir);
if st.distance = 0 then
begin
gi.dprintf('%s at %s with no distance set'#10, ent^.classname, vtos(ent^.s.origin));
st.distance := 90;
end;
VectorCopy (ent^.s.angles, ent^.pos1);
VectorMA (ent^.s.angles, st.distance, ent^.movedir, ent^.pos2);
ent^.moveinfo.distance := st.distance;
ent^.movetype := MOVETYPE_PUSH;
ent^.solid := SOLID_BSP;
gi.setmodel (ent, ent^.model);
ent^.blocked := door_blocked;
ent^.use := door_use;
if (ent^.speed = 0) then
ent^.speed := 100;
if (ent^.accel = 0) then
ent^.accel := ent^.speed;
if (ent^.decel = 0) then
ent^.decel := ent^.speed;
if (ent^.wait = 0) then
ent^.wait := 3;
if (ent^.dmg = 0) then
ent^.dmg := 2;
if (ent^.sounds <> 1) then
begin
ent^.moveinfo.sound_start := gi.soundindex ('doors/dr1_strt.wav');
ent^.moveinfo.sound_middle := gi.soundindex ('doors/dr1_mid.wav');
ent^.moveinfo.sound_end := gi.soundindex ('doors/dr1_end.wav');
end;
// if it starts open, switch the positions
if (ent^.spawnflags and DOOR_START_OPEN) <> 0 then
begin
VectorCopy (ent^.pos2, ent^.s.angles);
VectorCopy (ent^.pos1, ent^.pos2);
VectorCopy (ent^.s.angles, ent^.pos1);
VectorNegate (ent^.movedir, ent^.movedir);
end;
if (ent^.health) <> 0 then
begin
ent^.takedamage := DAMAGE_YES;
ent^.die := door_killed;
ent^.max_health := ent^.health;
end;
if assigned(ent^.targetname) and assigned(ent^._message) then
begin
gi.soundindex ('misc/talk.wav');
ent^.touch := door_touch;
end;
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^.s.origin, ent^.moveinfo.start_origin);
VectorCopy (ent^.pos1, ent^.moveinfo.start_angles);
VectorCopy (ent^.s.origin, ent^.moveinfo.end_origin);
VectorCopy (ent^.pos2, ent^.moveinfo.end_angles);
if (ent^.spawnflags and 16) <> 0 then
ent^.s.effects := ent^.s.effects or EF_ANIM_ALL;
// to simplify logic elsewhere, make non-teamed doors into a team of one
if not Assigned(ent^.team) then
ent^.teammaster := ent;
gi.linkentity (ent);
ent^.nextthink := level.time + FRAMETIME;
if (ent^.health <> 0) or Assigned(ent^.targetname) then
ent^.think := Think_CalcMoveSpeed
else
ent^.think := Think_SpawnDoorTrigger;
end;
(*QUAKED func_water (0 .5 .8) ? START_OPEN
func_water is a moveable water brush. It must be targeted to operate. Use a non-water texture at your own risk.
START_OPEN causes the water to move to its destination when spawned and operate in reverse.
"angle" determines the opening direction (up or down only)
"speed" movement speed (25 default)
"wait" wait before exiting (-1 default, -1 := TOGGLE)
"lip" lip remaining at end of move (0 default)
"sounds" (yes, these need to be changed)
0) no sound
1) water
2) lava
*)
procedure SP_func_water (self:edict_p);
var
abs_movedir:vec3_t;
begin
G_SetMovedir (self^.s.angles, self^.movedir);
self^.movetype := MOVETYPE_PUSH;
self^.solid := SOLID_BSP;
gi.setmodel (self, self^.model);
case (self^.sounds) of
1: // water
begin
self^.moveinfo.sound_start := gi.soundindex ('world/mov_watr.wav');
self^.moveinfo.sound_end := gi.soundindex ('world/stp_watr.wav');
// break;
end;
2: // lava
begin
self^.moveinfo.sound_start := gi.soundindex ('world/mov_watr.wav');
self^.moveinfo.sound_end := gi.soundindex ('world/stp_watr.wav');
// break;
end;
// else break;
end;
// calculate second position
VectorCopy (self^.s.origin, self^.pos1);
abs_movedir[0] := abs(self^.movedir[0]);
abs_movedir[1] := abs(self^.movedir[1]);
abs_movedir[2] := abs(self^.movedir[2]);
self^.moveinfo.distance := abs_movedir[0] * self^.size[0] + abs_movedir[1] * self^.size[1] + abs_movedir[2] * self^.size[2] - st.lip;
VectorMA (self^.pos1, self^.moveinfo.distance, self^.movedir, self^.pos2);
// if it starts open, switch the positions
if (self^.spawnflags and DOOR_START_OPEN) <> 0 then
begin
VectorCopy (self^.pos2, self^.s.origin);
VectorCopy (self^.pos1, self^.pos2);
VectorCopy (self^.s.origin, self^.pos1);
end;
VectorCopy (self^.pos1, self^.moveinfo.start_origin);
VectorCopy (self^.s.angles, self^.moveinfo.start_angles);
VectorCopy (self^.pos2, self^.moveinfo.end_origin);
VectorCopy (self^.s.angles, self^.moveinfo.end_angles);
self^.moveinfo.state := STATE_BOTTOM;
if (self^.speed = 0) then
self^.speed := 25;
self^.moveinfo.speed := self^.speed;
self^.moveinfo.decel := self^.moveinfo.speed;
self^.moveinfo.accel := self^.moveinfo.decel;
if (self^.wait = 0) then
self^.wait := -1;
self^.moveinfo.wait := self^.wait;
self^.use := door_use;
if (self^.wait = -1) then
self^.spawnflags := self^.spawnflags or DOOR_TOGGLE;
self^.classname := 'func_door';
gi.linkentity (self);
end;
const
TRAIN_START_ON = 1;
TRAIN_TOGGLE = 2;
TRAIN_BLOCK_STOPS = 4;
(*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
Trains are moving platforms that players can ride.
The targets origin specifies the min point of the train at each corner.
The train spawns at the first target it is pointing at.
If the train is the target of a button or trigger, it will not begin moving until activated.
speed default 100
dmg default 2
noise looping sound to play when the train is in motion
*)
procedure train_blocked (self:edict_p; other:edict_p); cdecl;
begin
if ((other^.svflags and SVF_MONSTER=0) and (not Assigned(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 assigned(other) then
BecomeExplosion1 (other);
exit;
end;
if (level.time < self^.touch_debounce_time) then
exit;
if (self^.dmg=0) then
exit;
self^.touch_debounce_time := level.time + 0.5;
T_Damage (other, self, self, vec3_origin, other^.s.origin, vec3_origin, self^.dmg, 1, 0, MOD_CRUSH);
end;
procedure train_wait (self:edict_p); cdecl;
var
savetarget:pchar;
ent:edict_p;
begin
if assigned(self^.target_ent^.pathtarget) then
begin
ent := self^.target_ent;
savetarget := ent^.target;
ent^.target := ent^.pathtarget;
G_UseTargets (ent, self^.activator);
ent^.target := savetarget;
// make sure we didn't get killed by a killtarget
if (not self^.inuse) then
exit;
end;
if (self^.moveinfo.wait<>0) then
begin
if (self^.moveinfo.wait > 0) then
begin
self^.nextthink := level.time + self^.moveinfo.wait;
self^.think := train_next;
end
else if (self^.spawnflags and TRAIN_TOGGLE) <> 0 then // && wait < 0
begin
train_next (self);
self^.spawnflags := self^.spawnflags and not TRAIN_START_ON;
VectorClear (self^.velocity);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -