29 void monster_fire_bullet(edict_t *
self, vec3_t start, vec3_t dir,
int damage,
int kick,
int hspread,
int vspread,
int flashtype)
35 gi.WriteByte(flashtype);
36 gi.multicast(start, MULTICAST_PVS);
39 void monster_fire_shotgun(edict_t *
self, vec3_t start, vec3_t aimdir,
int damage,
int kick,
int hspread,
int vspread,
int count,
int flashtype)
45 gi.WriteByte(flashtype);
46 gi.multicast(start, MULTICAST_PVS);
49 void monster_fire_blaster(edict_t *
self, vec3_t start, vec3_t dir,
int damage,
int speed,
int flashtype,
int effect)
51 fire_blaster(
self, start, dir, damage, speed, effect, qfalse);
55 gi.WriteByte(flashtype);
56 gi.multicast(start, MULTICAST_PVS);
59 void monster_fire_grenade(edict_t *
self, vec3_t start, vec3_t aimdir,
int damage,
int speed,
int flashtype)
61 fire_grenade(
self, start, aimdir, damage, speed, 2.5, damage + 40);
65 gi.WriteByte(flashtype);
66 gi.multicast(start, MULTICAST_PVS);
69 void monster_fire_rocket(edict_t *
self, vec3_t start, vec3_t dir,
int damage,
int speed,
int flashtype)
71 fire_rocket(
self, start, dir, damage, speed, damage + 20, damage);
75 gi.WriteByte(flashtype);
76 gi.multicast(start, MULTICAST_PVS);
81 fire_rail(
self, start, aimdir, damage, kick);
85 gi.WriteByte(flashtype);
86 gi.multicast(start, MULTICAST_PVS);
89 void monster_fire_bfg(edict_t *
self, vec3_t start, vec3_t aimdir,
int damage,
int speed,
int kick,
float damage_radius,
int flashtype)
91 fire_bfg(
self, start, aimdir, damage, speed, damage_radius);
95 gi.WriteByte(flashtype);
96 gi.multicast(start, MULTICAST_PVS);
107 self->s.effects &= ~EF_FLIES;
113 if (self->waterlevel)
115 self->s.effects |= EF_FLIES;
116 self->s.sound =
gi.soundindex(
"infantry/inflies1.wav");
123 if (self->waterlevel)
135 self->monsterinfo.attack_finished =
level.
time + time;
147 if (ent->velocity[2] > 100) {
148 ent->groundentity = NULL;
153 point[0] = ent->s.origin[0];
154 point[1] = ent->s.origin[1];
155 point[2] = ent->s.origin[2] - 0.25;
157 trace =
gi.trace(ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
160 if (trace.plane.normal[2] < 0.7 && !trace.startsolid) {
161 ent->groundentity = NULL;
169 if (!trace.startsolid && !trace.allsolid) {
170 VectorCopy(trace.endpos, ent->s.origin);
171 ent->groundentity = trace.ent;
172 ent->groundentity_linkcount = trace.ent->linkcount;
173 ent->velocity[2] = 0;
186 point[0] = ent->s.origin[0];
187 point[1] = ent->s.origin[1];
188 point[2] = ent->s.origin[2] + ent->mins[2] + 1;
189 cont =
gi.pointcontents(point);
191 if (!(cont & MASK_WATER)) {
197 ent->watertype = cont;
200 cont =
gi.pointcontents(point);
201 if (!(cont & MASK_WATER))
206 cont =
gi.pointcontents(point);
207 if (cont & MASK_WATER)
216 if (ent->health > 0) {
218 if (ent->waterlevel < 3) {
220 }
else if (ent->air_finished <
level.
time) {
222 if (ent->pain_debounce_time <
level.
time) {
223 dmg = 2 + 2 * floor(
level.
time - ent->air_finished);
227 ent->pain_debounce_time =
level.
time + 1;
231 if (ent->waterlevel > 0) {
233 }
else if (ent->air_finished <
level.
time) {
235 if (ent->pain_debounce_time <
level.
time) {
236 dmg = 2 + 2 * floor(
level.
time - ent->air_finished);
240 ent->pain_debounce_time =
level.
time + 1;
246 if (ent->waterlevel == 0) {
248 gi.sound(ent, CHAN_BODY,
gi.soundindex(
"player/watr_out.wav"), 1, ATTN_NORM, 0);
254 if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags &
FL_IMMUNE_LAVA)) {
255 if (ent->damage_debounce_time <
level.
time) {
256 ent->damage_debounce_time =
level.
time + 0.2;
260 if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags &
FL_IMMUNE_SLIME)) {
261 if (ent->damage_debounce_time <
level.
time) {
262 ent->damage_debounce_time =
level.
time + 1;
268 if (!(ent->svflags & SVF_DEADMONSTER)) {
269 if (ent->watertype & CONTENTS_LAVA)
271 gi.sound(ent, CHAN_BODY,
gi.soundindex(
"player/lava1.wav"), 1, ATTN_NORM, 0);
273 gi.sound(ent, CHAN_BODY,
gi.soundindex(
"player/lava2.wav"), 1, ATTN_NORM, 0);
274 else if (ent->watertype & CONTENTS_SLIME)
275 gi.sound(ent, CHAN_BODY,
gi.soundindex(
"player/watr_in.wav"), 1, ATTN_NORM, 0);
276 else if (ent->watertype & CONTENTS_WATER)
277 gi.sound(ent, CHAN_BODY,
gi.soundindex(
"player/watr_in.wav"), 1, ATTN_NORM, 0);
281 ent->damage_debounce_time = 0;
291 ent->s.origin[2] += 1;
292 VectorCopy(ent->s.origin, end);
295 trace =
gi.trace(ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
297 if (trace.fraction == 1 || trace.allsolid)
300 VectorCopy(trace.endpos, ent->s.origin);
310 ent->s.effects &= ~(EF_COLOR_SHELL | EF_POWERSCREEN);
311 ent->s.renderfx &= ~(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE);
314 ent->s.effects |= EF_COLOR_SHELL;
315 ent->s.renderfx |= RF_SHELL_RED;
318 if (ent->health <= 0)
323 ent->s.effects |= EF_POWERSCREEN;
325 ent->s.effects |= EF_COLOR_SHELL;
326 ent->s.renderfx |= RF_SHELL_GREEN;
337 move =
self->monsterinfo.currentmove;
340 if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->
firstframe) && (self->monsterinfo.nextframe <= move->
lastframe)) {
341 self->s.frame =
self->monsterinfo.nextframe;
342 self->monsterinfo.nextframe = 0;
349 move =
self->monsterinfo.currentmove;
352 if (self->svflags & SVF_DEADMONSTER)
385 if (self->linkcount != self->monsterinfo.linkcount) {
386 self->monsterinfo.linkcount =
self->linkcount;
406 if (self->health <= 0)
410 if (!(activator->client) && !(activator->monsterinfo.aiflags &
AI_GOOD_GUY))
414 self->enemy = activator;
424 self->s.origin[2] += 1;
427 self->solid = SOLID_BBOX;
429 self->svflags &= ~SVF_NOCLIENT;
435 if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags &
FL_NOTARGET)) {
447 if (activator->client)
448 self->enemy = activator;
454 self->solid = SOLID_NOT;
456 self->svflags |= SVF_NOCLIENT;
480 if (self->deathtarget)
481 self->target =
self->deathtarget;
499 if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags &
AI_GOOD_GUY)) {
500 self->spawnflags &= ~4;
501 self->spawnflags |= 1;
509 self->svflags |= SVF_MONSTER;
510 self->s.renderfx |= RF_FRAMELERP;
514 self->max_health =
self->health;
515 self->clipmask = MASK_MONSTERSOLID;
519 self->svflags &= ~SVF_DEADMONSTER;
521 if (!self->monsterinfo.checkattack)
523 VectorCopy(self->s.origin, self->s.old_origin);
528 gi.dprintf(
"%s at %s has bad item: %s\n", self->classname,
vtos(self->s.origin),
st.
item);
532 if (self->monsterinfo.currentmove)
533 self->s.frame =
self->monsterinfo.currentmove->firstframe + (rand() % (
self->monsterinfo.currentmove->lastframe -
self->monsterinfo.currentmove->firstframe + 1));
542 if (self->health <= 0)
554 while ((target =
G_Find(target,
FOFS(targetname), self->target)) != NULL) {
555 if (strcmp(target->classname,
"point_combat") == 0) {
556 self->combattarget =
self->target;
562 if (notcombat && self->combattarget)
563 gi.dprintf(
"%s at %s has target with mixed types\n", self->classname,
vtos(self->s.origin));
569 if (self->combattarget) {
573 while ((target =
G_Find(target,
FOFS(targetname), self->combattarget)) != NULL) {
574 if (strcmp(target->classname,
"point_combat") != 0) {
575 gi.dprintf(
"%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
576 self->classname, (
int)self->s.origin[0], (
int)self->s.origin[1], (
int)self->s.origin[2],
577 self->combattarget, target->classname, (
int)target->s.origin[0], (
int)target->s.origin[1],
578 (
int)target->s.origin[2]);
584 self->goalentity =
self->movetarget =
G_PickTarget(self->target);
585 if (!self->movetarget) {
586 gi.dprintf(
"%s can't find target %s at %s\n", self->classname, self->target,
vtos(self->s.origin));
588 self->monsterinfo.pausetime = 100000000;
589 self->monsterinfo.stand(
self);
590 }
else if (strcmp(self->movetarget->classname,
"path_corner") == 0) {
591 VectorSubtract(self->goalentity->s.origin, self->s.origin, v);
592 self->ideal_yaw =
self->s.angles[YAW] =
vectoyaw(v);
593 self->monsterinfo.walk(
self);
596 self->goalentity =
self->movetarget = NULL;
597 self->monsterinfo.pausetime = 100000000;
598 self->monsterinfo.stand(
self);
601 self->monsterinfo.pausetime = 100000000;
602 self->monsterinfo.stand(
self);
612 if (!(self->spawnflags & 2) &&
level.
time < 1) {
615 if (self->groundentity)
617 gi.dprintf(
"%s in solid at %s\n", self->classname,
vtos(self->s.origin));
620 if (!self->yaw_speed)
621 self->yaw_speed = 20;
622 self->viewheight = 25;
626 if (self->spawnflags & 2)
640 gi.dprintf(
"%s in solid at %s\n", self->classname,
vtos(self->s.origin));
642 if (!self->yaw_speed)
643 self->yaw_speed = 10;
644 self->viewheight = 25;
648 if (self->spawnflags & 2)
663 if (!self->yaw_speed)
664 self->yaw_speed = 10;
665 self->viewheight = 10;
669 if (self->spawnflags & 2)