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

📄 g_func.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:
	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

	// find the smallest distance any member of the team will be moving
	min := abs(self^.moveinfo.distance);

⌨️ 快捷键说明

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