📄 g_monster.pas
字号:
ent^.s.origin[2] := ent^.s.origin[2] + 1;
VectorCopy(ent^.s.origin, end_);
end_[2] := end_[2] - 256;
trace := gi.trace(@ent^.s.origin, @ent^.mins, @ent^.maxs, @end_, ent, MASK_MONSTERSOLID);
if (trace.fraction = 1) or (trace.allsolid) then
Exit;
VectorCopy(trace.endpos, ent^.s.origin);
gi.linkentity(ent);
M_CheckGround(ent);
M_CatagorizePosition(ent);
end;
procedure M_SetEffects(ent: edict_p);
begin
ent^.s.effects := ent^.s.effects and (not (EF_COLOR_SHELL or EF_POWERSCREEN));
ent^.s.renderfx := ent^.s.renderfx and (not (RF_SHELL_RED or RF_SHELL_GREEN or RF_SHELL_BLUE));
if (ent^.monsterinfo.aiflags and AI_RESURRECTING) <> 0 then
begin
ent^.s.effects := ent^.s.effects or EF_COLOR_SHELL;
ent^.s.renderfx := ent^.s.renderfx or RF_SHELL_RED;
end;
if (ent^.health <= 0) then
Exit;
if (ent^.powerarmor_time > level.time) then
begin
if (ent^.monsterinfo.power_armor_type = POWER_ARMOR_SCREEN) then
begin
ent^.s.effects := ent^.s.effects or EF_POWERSCREEN;
end
else if (ent^.monsterinfo.power_armor_type = POWER_ARMOR_SHIELD) then
begin
ent^.s.effects := ent^.s.effects or EF_COLOR_SHELL;
ent^.s.renderfx := ent^.s.renderfx or RF_SHELL_GREEN;
end;
end;
end;
procedure M_MoveFrame(self: edict_p);
var
move: mmove_p;
index: integer;
begin
move := self^.monsterinfo.currentmove;
self^.nextthink := level.time + FRAMETIME;
if ((self^.monsterinfo.nextframe <> 0) and (self^.monsterinfo.nextframe >= move^.firstframe)
and (self^.monsterinfo.nextframe <= move^.lastframe)) then
begin
self^.s.frame := self^.monsterinfo.nextframe;
self^.monsterinfo.nextframe := 0;
end
else
begin
if (self^.s.frame = move^.lastframe)then
begin
if Assigned(move^.endfunc) then
begin
move^.endfunc(self);
// regrab move, endfunc is very likely to change it
move := self^.monsterinfo.currentmove;
// check for death
if (self^.svflags and SVF_DEADMONSTER) <> 0 then
Exit;
end;
end;
if (self^.s.frame < move^.firstframe) or (self^.s.frame > move^.lastframe) then
begin
self^.monsterinfo.aiflags := self^.monsterinfo.aiflags and (not AI_HOLD_FRAME);
self^.s.frame := move^.firstframe;
end
else
begin
if (self^.monsterinfo.aiflags AND AI_HOLD_FRAME) = 0 then
begin
Inc(self^.s.frame);
if (self^.s.frame > move^.lastframe) then
self^.s.frame := move^.firstframe;
end;
end;
end;
index := self^.s.frame - move^.firstframe;
if (@mframe_a(move^.frame)[index].aifunc)<> nil then
if (self^.monsterinfo.aiflags and AI_HOLD_FRAME) = 0 then
mframe_a(move^.frame)[index].aifunc (self , mframe_a(move^.frame)[index].dist * self^.monsterinfo.scale)
else
mframe_a(move^.frame)[index].aifunc(self, 0);
if Assigned(mframe_a(move^.frame)[index].thinkfunc) then
mframe_a(move^.frame)[index].thinkfunc(self);
end;
procedure monster_think(self: edict_p);
begin
M_MoveFrame(self);
if (self^.linkcount <> self^.monsterinfo.linkcount) then
begin
self^.monsterinfo.linkcount := self^.linkcount;
M_CheckGround(self);
end;
M_CatagorizePosition(self);
M_WorldEffects(self);
M_SetEffects(self);
end;
{ ================
monster_use
Using a monster makes it angry at the current activator
================ }
procedure monster_use(self, other, activator: edict_p);
begin
if (self^.enemy <> nil)then
Exit;
if (self^.health <= 0)then
Exit;
if (activator^.flags and FL_NOTARGET) <> 0 then
Exit;
if (activator^.client = nil) and ((activator^.monsterinfo.aiflags and AI_GOOD_GUY) = 0) then
Exit;
// delay reaction so if the monster is teleported, its sound is still heard
self^.enemy := activator;
FoundTarget(self);
end;
procedure monster_triggered_spawn(self: edict_p);
begin
self^.s.origin[2] := self^.s.origin[2] + 1;
KillBox(self);
self^.solid := SOLID_BBOX;
self^.movetype := MOVETYPE_STEP;
self^.svflags := self^.svflags and (NOT SVF_NOCLIENT);
self^.air_finished := level.time + 12;
gi.linkentity(self);
monster_start_go(self);
if (self^.enemy <> nil) and ((self^.spawnflags and 1) = 0) and ((self^.enemy^.flags and FL_NOTARGET) = 0) then
begin
FoundTarget(self)
end
else
begin
self^.enemy := Nil;
end;
end;
procedure monster_triggered_spawn_use(self, other, activator: edict_p);
begin
// we have a one frame delay here so we don't telefrag the guy who activated us
self^.think := monster_triggered_spawn;
self^.nextthink := level.time + FRAMETIME;
if Assigned(activator^.client) then
self^.enemy := activator;
self^.use := monster_use;
end;
procedure monster_triggered_start(self: edict_p);
begin
self^.solid := SOLID_NOT;
self^.movetype := MOVETYPE_NONE;
self^.svflags := self^.svflags or SVF_NOCLIENT;
self^.nextthink := 0;
self^.use := monster_triggered_spawn_use;
end;
{ ================
monster_death_use
When a monster dies, it fires all of its targets with the current
enemy as activator.
================ }
procedure monster_death_use(self : edict_p);
begin
self^.flags := self^.flags and (NOT (FL_FLY or FL_SWIM));
self^.monsterinfo.aiflags := self^.monsterinfo.aiflags and AI_GOOD_GUY;
if Assigned(self^.item) then
begin
Drop_Item(self, self^.item);
self^.item := Nil;
end;
if (self^.deathtarget <> nil)then
self^.target := self^.deathtarget;
if (self^.target = Nil) then
Exit;
G_UseTargets(self, self^.enemy);
end;
//============================================================================
function monster_start(self: edict_p): qboolean;
begin
if (deathmatch^.value <> 0) then
begin
G_FreeEdict(self);
Result := false;
Exit;
end;
if ((self^.spawnflags and 4) <> 0) and ((self^.monsterinfo.aiflags and AI_GOOD_GUY) = 0) then
begin
self^.spawnflags := self^.spawnflags and (not 4);
self^.spawnflags := self^.spawnflags or 1;
{ The following line was originally commented out }
// gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
end;
if (self^.monsterinfo.aiflags and AI_GOOD_GUY) = 0 then
Inc(level.total_monsters);
self^.nextthink := level.time + FRAMETIME;
self^.svflags := self^.svflags or SVF_MONSTER;
self^.s.renderfx := self^.s.renderfx or RF_FRAMELERP;
self^.takedamage := DAMAGE_AIM;
self^.air_finished := level.time + 12;
self^.use := monster_use;
self^.max_health := self^.health;
self^.clipmask := MASK_MONSTERSOLID;
self^.s.skinnum := 0;
self^.deadflag := DEAD_NO;
self^.svflags := self^.svflags and (not SVF_DEADMONSTER);
if (@self^.monsterinfo.checkattack = nil) then
self^.monsterinfo.checkattack := M_CheckAttack;
VectorCopy(self^.s.origin, self^.s.old_origin);
if (st.item <> nil) then
begin
self^.item := FindItemByClassname(st.item);
if (self^.item = nil) then
gi.dprintf('%s at %s has bad item: %s'#10, self^.classname, vtos(self^.s.origin), st.item);
end;
// randomize what frame they start on
if (self^.monsterinfo.currentmove <> nil) then
self^.s.frame := self^.monsterinfo.currentmove^.firstframe +
(rand() mod (self^.monsterinfo.currentmove^.lastframe
- self^.monsterinfo.currentmove^.firstframe + 1));
Result := True;
end;
procedure monster_start_go(self: edict_p);
var
v: vec3_t;
notcombat, fixup: qboolean;
target: edict_p;
begin
if (self^.health <= 0) then
Exit;
// check for target to combat_point and change to combattarget
if (self^.target <> nil) then
begin
target := Nil;
notcombat := False;
fixup := False;
{ NOTE(SP): Removed the TRY..FINALLY block that ensured the next call to
G_Find occured, due to possible performance issues with
try blocks. }
target := G_Find(target, FOFS_targetname, self^.target);
while (target <> Nil) do
begin
if (strcmp(target^.classname, 'point_combat') = 0) then
begin
self^.combattarget := self^.target;
fixup := True;
end
else
notcombat := True;
target := G_Find(target, FOFS_targetname, self^.target);
end;
if notcombat AND (self^.combattarget <> nil) then
gi.dprintf('%s at %s has target with mixed types'#10, self^.classname, vtos(self^.s.origin));
if fixup then
self^.target := Nil;
end;
// validate combattarget
if (self^.combattarget <> nil) then
begin
target := Nil;
{ NOTE(SP): Removed the TRY..FINALLY block that ensured the next call to
G_Find occured, due to possible performance issues with
try blocks. }
target := G_Find(target, FOFS_targetname , self^.combattarget);
while (target <> Nil) do
begin
if (strcmp(target^.classname, 'point_combat') <> 0) then
begin
gi.dprintf('%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)'#10,
self^.classname, Trunc(self^.s.origin[0]), Trunc(self^.s.origin[1]), Trunc(self^.s.origin[2]),
self^.combattarget, target^.classname, Trunc(target^.s.origin[0]), Trunc(target^.s.origin[1]),
Trunc(target^.s.origin[2]));
end;
target := G_Find(target, FOFS_targetname , self^.combattarget);
end;
end;
if (self^.target <> nil) then
begin
self^.movetarget := G_PickTarget(self^.target);
self^.goalentity := self^.movetarget;
if (self^.movetarget = nil) then
begin
gi.dprintf ('%s can''t find target %s at %s'#10, self^.classname, self^.target, vtos(self^.s.origin));
self^.target := Nil;
self^.monsterinfo.pausetime := 100000000;
self^.monsterinfo.stand(self);
end
else if (strcmp(self^.movetarget^.classname, 'path_corner') = 0) then
begin
VectorSubtract(self^.goalentity^.s.origin, self^.s.origin, v);
self^.s.angles[YAW] := vectoyaw(v);
self^.ideal_yaw := self^.s.angles[YAW];
self^.monsterinfo.walk(self);
self^.target := Nil;
end
else
begin
self^.movetarget := Nil;
self^.goalentity := self^.movetarget;
self^.monsterinfo.pausetime := 100000000;
self^.monsterinfo.stand(self);
end;
end
else
begin
self^.monsterinfo.pausetime := 100000000;
self^.monsterinfo.stand(self);
end;
self^.think := monster_think;
self^.nextthink := level.time + FRAMETIME;
end;
procedure walkmonster_start_go(self: edict_p);
begin
if ((self^.spawnflags AND 2) = 0) AND (level.time < 1) then
begin
M_droptofloor(self);
if (self^.groundentity <> nil) then
if not (M_walkmove(self, 0, 0)) then
gi.dprintf('%s in solid at %s'#10, self^.classname, vtos(self^.s.origin));
end;
if (self^.yaw_speed = 0) then
self^.yaw_speed := 20;
self^.viewheight := 25;
monster_start_go(self);
if (self^.spawnflags AND 2) <> 0 then
monster_triggered_start(self);
end;
procedure walkmonster_start(self: edict_p);
begin
self^.think := walkmonster_start_go;
monster_start(self);
end;
procedure flymonster_start_go(self: edict_p);
begin
if not(M_walkmove(self, 0, 0)) then
gi.dprintf('%s in solid at %s'#10, self^.classname, vtos(self^.s.origin));
if (self^.yaw_speed = 0) then
self^.yaw_speed := 10;
self^.viewheight := 25;
monster_start_go(self);
if (self^.spawnflags AND 2) <> 0 then
monster_triggered_start(self);
end;
procedure flymonster_start(self: edict_p);
begin
self^.flags := self^.flags OR FL_FLY;
self^.think := flymonster_start_go;
monster_start(self);
end;
procedure swimmonster_start_go(self: edict_p);
begin
if (self^.yaw_speed = 0) then
self^.yaw_speed := 10;
self^.viewheight := 10;
monster_start_go(self);
if (self^.spawnflags AND 2) <> 0 then
monster_triggered_start(self);
end;
procedure swimmonster_start(self: edict_p);
begin
self^.flags := self^.flags OR FL_SWIM;
self^.think := swimmonster_start_go;
monster_start(self);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -