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

📄 g_func.pas

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