📄 g_misc.pas
字号:
{$DEFINE CTF}
//100%
{$ALIGN ON}{$MINENUMSIZE 4}
{----------------------------------------------------------------------------}
{ }
{ File(s): game\g_misc.c }
{ ctf\g_misc.c (if you define CTF) }
{ Content: Saving and loading games }
{ }
{ Initial conversion by: Carl A Kenner (carlkenner@hotmail.com) }
{ Initial conversion on: 1-Mar-2002 }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ Copyright (C) 1997-2001 Id Software, Inc. }
{ }
{ This program is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU General Public License }
{ as published by the Free Software Foundation; either version 2 }
{ of the License, or (at your option) any later version. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ See the GNU General Public License for more details. }
{ }
{----------------------------------------------------------------------------}
{ Updated on: 3-Mar-2002 }
{ Updated by: Carl A Kenner }
{ }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ g_utils.G_FreeEdict, g_combat, m_move, g_func, g_ctf }
{----------------------------------------------------------------------------}
{ * TODO: }
{ Remaining functions }
{----------------------------------------------------------------------------}
unit g_misc;
{$DEFINE NODEPEND}
interface
Uses
{$IFNDEF NODEPEND}
{$IFDEF CTF}
g_ctf,
{$ENDIF}
g_combat, m_move, g_func,
{$ENDIF}
q_shared, GameUnit, g_save, g_utils, g_local;
procedure ThrowGib(self: edict_p; gibname: PChar; damage, _type: Integer);
procedure ThrowHead(self: edict_p; gibname: PChar; damage, _type: integer);
procedure ThrowClientHead(self: edict_p; damage: Integer);
procedure ThrowDebris(self: edict_p; modelname: PChar; speed: Single; const origin: vec3_t);
procedure BecomeExplosion1(self: edict_p);
procedure SP_func_areaportal(ent: edict_p); cdecl;
procedure SP_path_corner(self: edict_p); cdecl;
procedure SP_point_combat(self: edict_p); cdecl;
procedure SP_viewthing(ent: edict_p); cdecl;
procedure SP_info_null(self: edict_p); cdecl;
procedure SP_info_notnull(self: edict_p); cdecl;
procedure SP_light(self: edict_p); cdecl;
procedure SP_func_wall(self: edict_p); cdecl;
procedure SP_func_object(self: edict_p); cdecl;
procedure SP_func_explosive(self: edict_p); cdecl;
procedure SP_misc_explobox(self: edict_p); cdecl;
procedure SP_misc_blackhole(ent: edict_p); cdecl;
procedure SP_misc_eastertank(ent: edict_p); cdecl;
procedure SP_misc_easterchick(ent: edict_p); cdecl;
procedure SP_misc_easterchick2(ent: edict_p); cdecl;
procedure SP_monster_commander_body(self: edict_p); cdecl;
procedure SP_misc_banner(ent: edict_p); cdecl;
procedure SP_misc_deadsoldier(ent: edict_p); cdecl;
procedure SP_misc_viper (ent: edict_p); cdecl;
procedure SP_misc_bigviper(ent: edict_p); cdecl;
procedure SP_misc_viper_bomb(self: edict_p); cdecl;
procedure SP_misc_strogg_ship(ent: edict_p); cdecl;
procedure SP_misc_satellite_dish(ent: edict_p); cdecl;
procedure SP_light_mine1(ent: edict_p); cdecl;
procedure SP_light_mine2(ent: edict_p); cdecl;
procedure SP_misc_gib_arm(ent: edict_p); cdecl;
procedure SP_misc_gib_leg(ent: edict_p); cdecl;
procedure SP_misc_gib_head(ent: edict_p); cdecl;
procedure SP_target_character(self: edict_p); cdecl;
procedure SP_target_string(self: edict_p); cdecl;
procedure SP_func_clock(self: edict_p); cdecl;
procedure SP_misc_teleporter(ent: edict_p); cdecl;
procedure SP_misc_teleporter_dest(ent: edict_p); cdecl;
implementation
Uses SysUtils, DateUtils;
{$IFDEF NODEPEND}
//CAK - Change calling convention to cdecl
procedure G_FreeEdict(ed: edict_p); cdecl;
begin
g_utils.G_FreeEdict(ed);
end;
//g_combat
function T_Damage(targ, inflictor, attacker: edict_p; var dir, point, normal: vec3_t; damage, knockback, dflags, _mod: Integer): edict_p;
begin
result:=nil;
end;
procedure T_RadiusDamage(inflictor, attacker: edict_p; damage: Single; ignore: edict_p; radius: Single; _mod: Integer); begin end;
// m_move
function M_walkmove(ent: edict_p; yaw:single; dist:single): qboolean;
begin
Result:=false;
end;
//g_monster
procedure M_droptofloor(ent: edict_p); cdecl; begin end;
//g_func
procedure train_use(self, other, activator: edict_p); cdecl; begin end;
procedure func_train_find(self: edict_p); cdecl; begin end;
{$IFDEF CTF}
//g_ctf
type ctfteam_t = (CTF_NOTEAM, CTF_TEAM1, CTF_TEAM2);
procedure CTFResetFlag(ctf_team: ctfteam_t); begin end;
function CTFTeamName(team: ctfteam_t): PChar;
begin
Result:='';
end;
procedure CTFRespawnTech(ent: edict_p); begin end;
procedure CTFPlayerResetGrapple(ent: edict_p); begin end;
{$ENDIF}
{$ENDIF}
// g_misc.c
(*QUAKED func_group (0 0 0) ?
Used to group brushes together just for editor convenience.
*)
//====================================================:=
procedure Use_Areaportal(ent, other, activator: edict_p); cdecl;
begin
ent.count := ent.count XOR 1; // toggle state
// gi_dprintf('portalstate: %i = %i\n', [ent.style, ent.count]);
gi.SetAreaPortalState(ent.style, ent.count<>0);
end;
(*QUAKED func_areaportal (0 0 0) ?
This is a non-visible object that divides the world into
areas that are seperated when this portal is not activated.
Usually enclosed in the middle of a door.
*)
procedure SP_func_areaportal(ent: edict_p); cdecl;
begin
ent.use := Use_Areaportal;
ent.count := 0; // always start closed;
end;
//====================================================:=
(*
=================
Misc functions
=================
*)
procedure VelocityForDamage(damage: Integer; var v: vec3_t);
begin
v[0] := 100.0 * crandom();
v[1] := 100.0 * crandom();
v[2] := 200.0 + 100.0 * _random();
if damage < 50 then
VectorScale (v, 0.7, v)
else
VectorScale (v, 1.2, v);
end;
procedure ClipGibVelocity(ent: edict_p);
begin
if ent.velocity[0] < -300 then
ent.velocity[0] := -300
else if ent.velocity[0] > 300 then
ent.velocity[0] := 300;
if ent.velocity[1] < -300 then
ent.velocity[1] := -300
else if ent.velocity[1] > 300 then
ent.velocity[1] := 300;
if ent.velocity[2] < 200 then
ent.velocity[2] := 200 // always some upwards
else if ent.velocity[2] > 500 then
ent.velocity[2] := 500;
end;
(*
=================
gibs
=================
*)
procedure gib_think(self: edict_p); cdecl;
begin
Inc(self.s.frame);
self.nextthink := level.time + FRAMETIME;
if self.s.frame = 10 then begin
self.think := G_FreeEdict;
self.nextthink := level.time + 8 + _random()*10;
end;
end;
procedure gib_touch(self, other: edict_p; plane: cplane_p; surf: csurface_p); cdecl;
Var normal_angles, right: vec3_t;
begin
if self.groundentity=Nil then
exit;
self.touch := Nil;
if plane<>Nil then begin
gi.sound (self, CHAN_VOICE, gi.soundindex ('misc/fhit3.wav'), 1, ATTN_NORM, 0);
vectoangles(plane.normal, normal_angles);
AngleVectors(normal_angles, Nil, @right, Nil);
vectoangles (right, self.s.angles);
if self.s.modelindex = sm_meat_index then begin
inc(self.s.frame);
self.think := gib_think;
self.nextthink := level.time + FRAMETIME;
end;
end;
end;
procedure gib_die(self, inflictor, attacker: edict_p; damage: Integer; point: vec3_t); cdecl;
begin
G_FreeEdict(self);
end;
procedure ThrowGib(self: edict_p; gibname: PChar; damage, _type: Integer);
Var gib: edict_p; vd, origin, size: vec3_t; vscale: Single;
begin
gib := G_Spawn();
VectorScale(self.size, 0.5, size);
VectorAdd(self.absmin, size, origin);
gib.s.origin[0] := origin[0] + crandom() * size[0];
gib.s.origin[1] := origin[1] + crandom() * size[1];
gib.s.origin[2] := origin[2] + crandom() * size[2];
gi.setmodel(gib, gibname);
gib.solid := SOLID_NOT;
gib.s.effects := gib.s.effects OR EF_GIB;
gib.flags := gib.flags OR FL_NO_KNOCKBACK;
gib.takedamage := DAMAGE_YES;
gib.die := gib_die;
if _type = GIB_ORGANIC then begin
gib.movetype := MOVETYPE_TOSS;
gib.touch := gib_touch;
vscale := 0.5;
end else begin
gib.movetype := MOVETYPE_BOUNCE;
vscale := 1.0;
end;
VelocityForDamage(damage, vd);
VectorMA(self.velocity, vscale, vd, gib.velocity);
ClipGibVelocity(gib);
gib.avelocity[0] := _random()*600;
gib.avelocity[1] := _random()*600;
gib.avelocity[2] := _random()*600;
gib.think := G_FreeEdict;
gib.nextthink := level.time + 10 + _random()*10;
gi.linkentity(gib);
end;
procedure ThrowHead(self: edict_p; gibname: PChar; damage, _type: integer);
Var vd: vec3_t; vscale: Single;
begin
self.s.skinnum := 0;
self.s.frame := 0;
VectorClear(self.mins);
VectorClear(self.maxs);
self.s.modelindex2 := 0;
gi.setmodel(self, gibname);
self.solid := SOLID_NOT;
self.s.effects := self.s.effects OR EF_GIB;
self.s.effects := self.s.effects AND (NOT EF_FLIES);
self.s.sound := 0;
self.flags := self.flags OR FL_NO_KNOCKBACK;
self.svflags := self.svflags AND (NOT SVF_MONSTER);
self.takedamage := DAMAGE_YES;
self.die := gib_die;
if _type = GIB_ORGANIC then begin
self.movetype := MOVETYPE_TOSS;
self.touch := gib_touch;
vscale := 0.5;
end else begin
self.movetype := MOVETYPE_BOUNCE;
vscale := 1.0;
end;
VelocityForDamage(damage, vd);
VectorMA(self.velocity, vscale, vd, self.velocity);
ClipGibVelocity(self);
self.avelocity[YAW] := crandom()*600;
self.think := G_FreeEdict;
self.nextthink := level.time + 10 + _random()*10;
gi.linkentity (self);
end;
procedure ThrowClientHead(self: edict_p; damage: Integer);
Var vd: vec3_t; gibname: PChar;
begin
if System.Random(2)=1 then begin
gibname := 'models/objects/gibs/head2/tris.md2';
self.s.skinnum := 1; // second skin is player
end else begin
gibname := 'models/objects/gibs/skull/tris.md2';
self.s.skinnum := 0;
end;
self.s.origin[2] := self.s.origin[2] + 32;
self.s.frame := 0;
gi.setmodel(self, gibname);
VectorSet(self.mins, -16, -16, 0);
VectorSet(self.maxs, 16, 16, 16);
self.takedamage := DAMAGE_NO;
self.solid := SOLID_NOT;
self.s.effects := EF_GIB;
self.s.sound := 0;
self.flags := self.flags OR FL_NO_KNOCKBACK;
self.movetype := MOVETYPE_BOUNCE;
VelocityForDamage (damage, vd);
VectorAdd (self.velocity, vd, self.velocity);
if self.client<>Nil then begin // bodies in the queue don't have a client anymore
self.client.anim_priority := ANIM_DEATH;
self.client.anim_end := self.s.frame;
{$IFNDEF CTF}
end else begin
self.think := Nil;
self.nextthink := 0;
{$ENDIF}
end;
gi.linkentity(self);
end;
(*
=================
debris
=================
*)
procedure debris_die(self, inflictor, attacker: edict_p; damage: integer; point: vec3_t); cdecl;
begin
G_FreeEdict(self);
end;
procedure ThrowDebris(self: edict_p; modelname: PChar; speed: Single; const origin: vec3_t);
Var chunk: edict_p; v: vec3_t;
begin
chunk := G_Spawn();
VectorCopy(origin, chunk.s.origin);
gi.setmodel(chunk, modelname);
v[0] := 100 * crandom();
v[1] := 100 * crandom();
v[2] := 100 + 100 * crandom();
VectorMA(self.velocity, speed, v, chunk.velocity);
chunk.movetype := MOVETYPE_BOUNCE;
chunk.solid := SOLID_NOT;
chunk.avelocity[0] := _random()*600;
chunk.avelocity[1] := _random()*600;
chunk.avelocity[2] := _random()*600;
chunk.think := G_FreeEdict;
chunk.nextthink := level.time + 5 + _random()*5;
chunk.s.frame := 0;
chunk.flags := 0;
chunk.classname := 'debris';
chunk.takedamage := DAMAGE_YES;
chunk.die := debris_die;
gi.linkentity(chunk);
end;
procedure BecomeExplosion1(self: edict_p);
begin
{$IFDEF CTF}
//ZOID
//flags are important
if strcomp(self.classname, 'item_flag_team1') = 0 then begin
CTFResetFlag(CTF_TEAM1); // this will free self!
gi_bprintf(PRINT_HIGH, 'The %s flag has returned!'#10,
[CTFTeamName(CTF_TEAM1)]);
exit;
end;
if strcomp(self.classname, 'item_flag_team2') = 0 then begin
CTFResetFlag(CTF_TEAM2); // this will free self!
gi_bprintf(PRINT_HIGH, 'The %s flag has returned!'#10,
[CTFTeamName(CTF_TEAM1)]);
exit;
end;
// techs are important too
if (self.item<>Nil) and ((self.item.flags AND IT_TECH)<>0) then begin
CTFRespawnTech(self); // this frees self!
exit;
end;
//ZOID
{$ENDIF}
gi.WriteByte(svc_temp_entity);
gi.WriteByte(Ord(TE_EXPLOSION1));
gi.WritePosition(self.s.origin);
gi.multicast(self.s.origin, MULTICAST_PVS);
G_FreeEdict(self);
end;
procedure BecomeExplosion2(self: edict_p);
begin
gi.WriteByte (svc_temp_entity);
gi.WriteByte(Ord(TE_EXPLOSION2));
gi.WritePosition (self.s.origin);
gi.multicast (self.s.origin, MULTICAST_PVS);
G_FreeEdict (self);
end;
(*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
Target: next path corner
Pathtarget: gets used when an entity that has
this path_corner targeted touches it
*)
procedure path_corner_touch(self, other: edict_p; plane: cplane_p; surf: csurface_p); cdecl;
Var v: vec3_t; next: edict_p; savetarget: PChar;
begin
if other.movetarget <> self then
exit;
if other.enemy<>Nil then
exit;
if self.pathtarget<>Nil then begin
savetarget := self.target;
self.target := self.pathtarget;
G_UseTargets(self, other);
self.target := savetarget;
end;
if self.target<>Nil then
next := G_PickTarget(self.target)
else
next := Nil;
if (next<>Nil) and ((next.spawnflags AND 1)>0) then
begin
VectorCopy (next.s.origin, v);
v[2] := v[2] + next.mins[2];
v[2] := v[2] - other.mins[2];
VectorCopy(v, other.s.origin);
next := G_PickTarget(next.target);
{$IFNDEF CTF}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -