📄 g_func.pas
字号:
// find the smallest distance any member of the team will be moving
min := abs(self^.moveinfo.distance);
for ent := self^.teamchain to ent do
begin
dist := abs(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
for ent := self to 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 *:= ratio;
ent^.moveinfo.speed := newspeed;
ent := ent^.teamchain;
end;
end;
procedure Think_SpawnDoorTrigger (ent:pedict_t);
var
other:pedict_t;
mins,maxs:vec3_t;
begin
if (ent^.flags and FL_TEAMSLAVE) then
exit; // only the team leader spawns a trigger
VectorCopy (ent^.absmin, mins);
VectorCopy (ent^.absmax, maxs);
for other := ent^.teamchain to 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) then
door_use_areaportals (ent, true);
Think_CalcMoveSpeed (ent);
end;
procedure door_blocked (self:pedict_t; other:pedict_t);
var
ent:pedict_t;
begin
if (not (other^.svflags and SVF_MONSTER) and (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^.spawnflags and DOOR_CRUSHER) 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
for ent := self^.teammaster to ent do
begin
door_go_up (ent, ent^.activator);
ent := ent^.teamchain;
end;
end
else
begin
for ent := self^.teammaster to ent do
begin
door_go_down (ent);
ent := ent^.teamchain;
end;
end;
end;
end;
procedure door_killed (self:pedict_t; inflictor:pedict_t ; attacker:pedict_t ; damage:smallint; point:vec3_t );
var
ent:pedict_t;
begin
for ent := self^.teammaster to 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:pedict_t; other:pedict_t; plane:pcplane_t; surf:pcsurface_t);
begin
if (not 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:pedict_t);
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 (not ent^.speed) then
ent^.speed := 100;
if (deathmatch^.value) then
ent^.speed *:= 2;
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 := 8;
if (not ent^.dmg) 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) 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) then
begin
ent^.takedamage := DAMAGE_YES;
ent^.die := door_killed;
ent^.max_health := ent^.health;
end
else if (ent^.targetname andand ent^.message)
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) then
ent^.s.effects := ent^.s.effects or EF_ANIM_ALL;
if (ent^.spawnflags and 64) 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 ent^.team) then
ent^.teammaster := ent;
gi.linkentity (ent);
ent^.nextthink := level.time + FRAMETIME;
if (ent^.health or 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:pedict_t);
begin
VectorClear (ent^.s.angles);
// set the axis of rotation
VectorClear(ent^.movedir);
if (ent^.spawnflags and DOOR_X_AXIS) then
ent^.movedir[2] := 1.0
else if (ent^.spawnflags and DOOR_Y_AXIS) then
ent^.movedir[0] := 1.0
else // Z_AXIS
ent^.movedir[1] := 1.0;
// check for reverse rotation
if (ent^.spawnflags and DOOR_REVERSE) then
VectorNegate (ent^.movedir, ent^.movedir);
if (not st.distance) then
begin
gi.dprintf('%s at %s with no distance set\n', 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 (not ent^.speed) then
ent^.speed := 100;
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 ent^.dmg) 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) 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) then
begin
ent^.takedamage := DAMAGE_YES;
ent^.die := door_killed;
ent^.max_health := ent^.health;
end;
if (ent^.targetname and 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) 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 ent^.team) then
ent^.teammaster := ent;
gi.linkentity (ent);
ent^.nextthink := level.time + FRAMETIME;
if (ent^.health or 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:pedict_t);
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) 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 (not self^.speed) then
self^.speed := 25;
self^.moveinfo.speed := self^.speed;
self^.moveinfo.decel := self^.moveinfo.speed;
self^.moveinfo.accel := self^.moveinfo.decel;
if (not self^.wait) 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;
const TRAIN_TOGGLE = 2;
const 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:pedict_t; other:pedict_t);
begin
if (not (other^.svflags and SVF_MONSTER) and (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;
if (level.time < self^.touch_debounce_time) then
exit;
if (not self^.dmg) 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:pedict_t);
var
savetarget:pchar;
ent:pedict_t;
begin
if (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) 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) then // andand wait < 0
begin
train_next (self);
self^.spawnflags and:= ~TRAIN_START_ON;
VectorClear (self^.velocity);
self^.nextthink := 0;
end;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -