📄 g_monster.pas
字号:
if ((ent^.watertype and CONTENTS_LAVA) <> 0) then
begin
if (random <= 0.5) then
gi.sound(ent, CHAN_BODY, gi.soundindex('player/lava1.wav'), 1, ATTN_NORM, 0)
else
gi.sound(ent, CHAN_BODY, gi.soundindex('player/lava2.wav'), 1, ATTN_NORM, 0);
end
else if (ent^.watertype and CONTENTS_SLIME) <> 0 then
gi.sound(ent, CHAN_BODY, gi.soundindex('player/watr_in.wav'), 1, ATTN_NORM, 0)
else if (ent^.watertype and CONTENTS_WATER) <> 0 then
gi.sound(ent, CHAN_BODY, gi.soundindex('player/watr_in.wav'), 1, ATTN_NORM, 0);
end;
//CNH ent->flags |= FL_INWATER;
ent^.flags := ent^.flags or FL_INWATER;
ent^.damage_debounce_time := 0;
end;
end;
procedure M_droptofloor(ent: pedict_t);
var
end_: vec3_t;
trace: trace_t;
begin
Inc(ent^.s.origin[2]);
VectorCopy(ent^.s.origin, end_);
dec(end_[2], 256);
trace := gi.trace(ent^.s.origin, ent^.mins, ent^.maxs, end_, ent, MASK_MONSTERSOLID);
//CNH: if (trace.fraction == 1 || trace.allsolid)
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: pedict_t);
begin
ent^.s.effects := ent^.s.effects and (not (EF_COLOR_SHELL or EF_POWERSCREEN));
//CNH ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
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: pedict_t);
{ Added by Scott Price. This needs to be defined/found/included:
type
pmmove_t = ^mmove_t
}
var
move: pmmove_t;
index: integer;
begin
move := self^.monsterinfo.currentmove;
self^.nextthink := level.time + FRAMETIME;
if ((self^.monsterinfo.nextframe) 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
//CNH: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
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 Assigned(move^.frame[index].aifunc) then
//CNH: if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
if (self^.monsterinfo.aiflags and AI_HOLD_FRAME) = 0 then
move^.frame[index].aifunc(self, move^.frame[index].dist * self^.monsterinfo.scale)
else
move^.frame[index].aifunc(self, 0);
if Assigned(move^.frame[index].thinkfunc) then
move^.frame[index].thinkfunc(self);
end;
procedure monster_think(self: pedict_t);
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: pedict_t);
begin
if (self^.enemy)then
Exit;
if (self^.health <= 0)then
Exit;
if (activator^.flags and FL_NOTARGET) <> 0then
Exit;
//CNH: if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
if (activator^.client = 0) 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: pedict_t);
begin
Inc(self^.s.origin[2], 1);
KillBox(self);
self^.solid := SOLID_BBOX;
self^.movetype := MOVETYPE_STEP;
//CNH: self->svflags &= ~SVF_NOCLIENT;
self^.svflags := self^.svflags and (NOT SVF_NOCLIENT);
self^.air_finished := level.time + 12;
gi.linkentity(self);
monster_start_go(self);
//CNH: if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
if (self^.enemy <> Nil) AND ((self^.spawnflags AND 1) = 0) AND ((self^.enemy^.flags AND FL_NOTARGET) = 0) then
if Assigned(self^.enemy) and ((self^.spawnflags and 1) = 0) and ((self^.enemy^.flage and FL_NOTARGET) = 0)) then
begin
FoundTarget(self)
end
else
begin
self^.enemy := Nil;
end;
end;
procedure monster_triggered_spawn_use(self, other, activator: pedict_t);
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: pedict_t);
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 : pedict_t);
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)then
self^.target := self^.deathtarget;
if (self^.target = Nil) then
Exit;
G_UseTargets(self, self^.enemy);
end;
//============================================================================
function monster_start(self: pedict_t): qboolean;
begin
if (deathmatch^.value) then
begin
G_FreeEdict(self);
result := false;
exit;
end;
//CNH: if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
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) = 0then
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 = 0) then
self^.monsterinfo.checkattack := M_CheckAttack;
VectorCopy(self^.s.origin, self^.s.old_origin);
if (st.item) then
begin
self^.item := FindItemByClassname(st.item);
if (self^.item = 0) 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) then
self^.s.frame := self^.monsterinfo.currentmove^.firstframe +
(Random(RAND_MAX + 1) mod (self^.monsterinfo.currentmove^.lastframe
- self^.monsterinfo.currentmove^.firstframe + 1));
Result := True;
end;
{ TODO: Determine if the following routines need Interface declarations }
procedure monster_start_go(self: pedict_t);
var
v: vec3_t;
notcombat, fixup: qboolean;
target: Pedict_t;
begin
if (self^.health <= 0) then
Exit;
// check for target to combat_point and change to combattarget
if (self^.target) then
begin
target := Nil;
notcombat := False;
fixup := False;
target := G_Find(target, FOFS(targetname), self^.target);
while ((target <> Nil) do
begin
TRY
if (strcmp(target^.classname, 'point_combat') = 0) then
begin
self^.combattarget := self^.target;
fixup := True;
end
else
begin
notcombat := True;
end;
FINALLY
target := G_Find(target, FOFS(targetname), self^.target);
END;
end;
if (notcombat) AND (self^.combattarget) 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) then
begin
target := Nil;
target := G_Find(target, FOFS(targetname), self^.combattarget);
while (target <> Nil) do
begin
TRY
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, Integer(self^.s.origin[0]), Integer(self^.s.origin[1]), Integer(self^.s.origin[2]),
self^.combattarget, target^.classname, Integer(target^.s.origin[0]), Integer(target^.s.origin[1]),
Integer(target^.s.origin[2]));
end;
FINALLY
target := G_Find(target, FOFS(targetname), self^.combattarget);
END;
end;
end;
if (self^.target) then
begin
self^.movetarget := G_PickTarget(self^.target)
self^.goalentity := self^.movetarget;
if (self^.movetarget = 0) 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: Pedict_t);
begin
if ((self^.spawnflags AND 2) = 0) AND (level.time < 1) then
begin
M_droptofloor(self);
if (self^.groundentity) then
if (M_walkmove(self, 0, 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: Pedict_t);
begin
self^.think := walkmonster_start_go;
monster_start(self);
end;
procedure flymonster_start_go(self: Pedict_t);
begin
if (M_walkmove(self, 0, 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: Pedict_t);
begin
self^.flags := self^.flags OR FL_FLY;
self^.think := flymonster_start_go;
monster_start(self);
end;
procedure swimmonster_start_go(self: Pedict_t);
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: Pedict_t);
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 + -