190 lines
3.9 KiB
Plaintext
190 lines
3.9 KiB
Plaintext
enumflags { MONSTER_AMBUSH, MONSTER_TELEPORT=4 };
|
|
|
|
/*==========
|
|
monster_death_use
|
|
|
|
when a monster dies, it fires it's targets with its enemy as the activator
|
|
==========*/
|
|
void() monster_death_use =
|
|
{
|
|
// drop to floor
|
|
if (self.flags & FL_FLY)
|
|
self.flags = self.flags - FL_FLY;
|
|
if (self.flags & FL_SWIM)
|
|
self.flags = self.flags - FL_SWIM;
|
|
|
|
// use targets
|
|
activator = self.enemy;
|
|
UseTargets();
|
|
|
|
// bump monster counter
|
|
killed_monsters = killed_monsters + 1;
|
|
WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
|
|
};
|
|
|
|
/*==========
|
|
monster_use
|
|
|
|
using a monster makes it angry if the activator is a player
|
|
==========*/
|
|
static void() monster_use =
|
|
{
|
|
if (self.enemy)
|
|
return;
|
|
if (self.health <= 0)
|
|
return;
|
|
if (activator.classname != "player")
|
|
return;
|
|
if (activator.items & IT_INVISIBILITY)
|
|
return;
|
|
if (activator.flags & FL_NOTARGET)
|
|
return;
|
|
|
|
self.enemy = activator;
|
|
self.nextthink = time + 0.1;
|
|
self.think = FoundTarget;
|
|
};
|
|
|
|
/*==========
|
|
monster_start_go
|
|
==========*/
|
|
static void() monster_start_go =
|
|
{
|
|
// only walkmonsters drop to the floor
|
|
if (self.flags & (FL_MONSTER | FL_FLY | FL_SWIM) == FL_MONSTER)
|
|
{
|
|
self.origin_z = self.origin_z + 1;
|
|
droptofloor();
|
|
}
|
|
|
|
// print console warning if we're stuck in a wall
|
|
if (!walkmove(0, 0))
|
|
{
|
|
dprint(self.classname);
|
|
dprint(" in wall at: ");
|
|
dprint(vtos(self.origin));
|
|
dprint("\n");
|
|
}
|
|
|
|
self.think = self.th_stand;
|
|
self.nextthink = time + 0.01 + random() * 0.5;
|
|
|
|
// if the monster targets a path corner, they will move towards it
|
|
// otherwise, they will fire their targets upon death
|
|
if (self.target != "")
|
|
{
|
|
entity t = find(world, targetname, self.target);
|
|
if (!t)
|
|
{
|
|
dprint(self.classname);
|
|
dprint (" can't find target at: ");
|
|
dprint (vtos(self.origin));
|
|
dprint ("\n");
|
|
return;
|
|
}
|
|
|
|
if (t.classname == "path_corner")
|
|
{
|
|
self.movetarget = self.goalentity = t;
|
|
self.ideal_yaw = vectoyaw(t.origin - self.origin);
|
|
self.think = self.th_walk;
|
|
}
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
monster_teleport_use
|
|
|
|
using a monster with the teleport flag spawns it in
|
|
==========*/
|
|
static void() monster_teleport_use =
|
|
{
|
|
self.use = monster_use;
|
|
self.takedamage = DAMAGE_AIM;
|
|
self.solid = SOLID_SLIDEBOX;
|
|
self.movetype = MOVETYPE_STEP;
|
|
setmodel(self, self.mdl);
|
|
setsize(self, self.pos1, self.pos2);
|
|
|
|
spawn_tdeath(self.origin, self);
|
|
spawn_tfog(self.origin);
|
|
|
|
self.think = self.th_stand;
|
|
self.nextthink = time + 0.1;
|
|
|
|
// if a player activated the monster,
|
|
// get mad unless they're invisible or notarget
|
|
if (activator.classname == "player")
|
|
{
|
|
if (activator.flags & FL_NOTARGET)
|
|
return;
|
|
if (activator.items & IT_INVISIBILITY)
|
|
return;
|
|
self.enemy = activator;
|
|
self.think = FoundTarget;
|
|
self.nextthink = time + 0.1;
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
monster_start
|
|
==========*/
|
|
void(string mod, string hmod, float hp, float fl, vector min, vector max) monster_start =
|
|
{
|
|
total_monsters = total_monsters + 1;
|
|
|
|
self.flags = FL_MONSTER + fl; // FL_FLY or FL_SWIM
|
|
self.headmodel = hmod;
|
|
self.health = hp;
|
|
|
|
if (self.flags & FL_FLY)
|
|
{
|
|
self.yaw_speed = 20;
|
|
self.view_ofs = '0 0 25';
|
|
}
|
|
else if (self.flags & FL_SWIM)
|
|
{
|
|
self.yaw_speed = 10;
|
|
self.view_ofs = '0 0 10';
|
|
}
|
|
else
|
|
{
|
|
self.yaw_speed = 30;
|
|
self.view_ofs = '0 0 25';
|
|
}
|
|
self.ideal_yaw = self.angles_y;
|
|
|
|
// teleport flag
|
|
if (self.spawnflags & MONSTER_TELEPORT)
|
|
{
|
|
if (!self.targetname)
|
|
{
|
|
total_monsters = total_monsters - 1;
|
|
objerror("teleporting monsters must have a targetname\n");
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
self.use = monster_teleport_use;
|
|
self.solid = SOLID_NOT;
|
|
self.movetype = MOVETYPE_NONE;
|
|
setsize(self, min, max);
|
|
// save off fields so we can restore them later
|
|
self.pos1 = min;
|
|
self.pos2 = max;
|
|
self.mdl = mod;
|
|
return;
|
|
}
|
|
|
|
self.solid = SOLID_SLIDEBOX;
|
|
self.movetype = MOVETYPE_STEP;
|
|
setmodel (self, mod);
|
|
setsize (self, min, max);
|
|
|
|
self.use = monster_use;
|
|
self.takedamage = DAMAGE_AIM;
|
|
|
|
self.think = monster_start_go;
|
|
self.nextthink = time + 0.01 + random() * 0.5;
|
|
};
|