|
|
1.1 ! root 1: #include "g_local.h" ! 2: ! 3: ! 4: // ! 5: // monster weapons ! 6: // ! 7: ! 8: //FIXME mosnters should call these with a totally accurate direction ! 9: // and we can mess it up based on skill. Spread should be for normal ! 10: // and we can tighten or loosen based on skill. We could muck with ! 11: // the damages too, but I'm not sure that's such a good idea. ! 12: void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype) ! 13: { ! 14: fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN); ! 15: ! 16: gi.WriteByte (svc_muzzleflash2); ! 17: gi.WriteShort (self - g_edicts); ! 18: gi.WriteByte (flashtype); ! 19: gi.multicast (start, MULTICAST_PVS); ! 20: } ! 21: ! 22: 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) ! 23: { ! 24: fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN); ! 25: ! 26: gi.WriteByte (svc_muzzleflash2); ! 27: gi.WriteShort (self - g_edicts); ! 28: gi.WriteByte (flashtype); ! 29: gi.multicast (start, MULTICAST_PVS); ! 30: } ! 31: ! 32: void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect) ! 33: { ! 34: fire_blaster (self, start, dir, damage, speed, effect, false); ! 35: ! 36: gi.WriteByte (svc_muzzleflash2); ! 37: gi.WriteShort (self - g_edicts); ! 38: gi.WriteByte (flashtype); ! 39: gi.multicast (start, MULTICAST_PVS); ! 40: } ! 41: ! 42: void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype) ! 43: { ! 44: fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40); ! 45: ! 46: gi.WriteByte (svc_muzzleflash2); ! 47: gi.WriteShort (self - g_edicts); ! 48: gi.WriteByte (flashtype); ! 49: gi.multicast (start, MULTICAST_PVS); ! 50: } ! 51: ! 52: void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype) ! 53: { ! 54: fire_rocket (self, start, dir, damage, speed, damage+20, damage); ! 55: ! 56: gi.WriteByte (svc_muzzleflash2); ! 57: gi.WriteShort (self - g_edicts); ! 58: gi.WriteByte (flashtype); ! 59: gi.multicast (start, MULTICAST_PVS); ! 60: } ! 61: ! 62: void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype) ! 63: { ! 64: fire_rail (self, start, aimdir, damage, kick); ! 65: ! 66: gi.WriteByte (svc_muzzleflash2); ! 67: gi.WriteShort (self - g_edicts); ! 68: gi.WriteByte (flashtype); ! 69: gi.multicast (start, MULTICAST_PVS); ! 70: } ! 71: ! 72: void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype) ! 73: { ! 74: fire_bfg (self, start, aimdir, damage, speed, damage_radius); ! 75: ! 76: gi.WriteByte (svc_muzzleflash2); ! 77: gi.WriteShort (self - g_edicts); ! 78: gi.WriteByte (flashtype); ! 79: gi.multicast (start, MULTICAST_PVS); ! 80: } ! 81: ! 82: ! 83: ! 84: // ! 85: // Monster utility functions ! 86: // ! 87: ! 88: static void M_FliesOff (edict_t *self) ! 89: { ! 90: self->s.effects &= ~EF_FLIES; ! 91: self->s.sound = 0; ! 92: } ! 93: ! 94: static void M_FliesOn (edict_t *self) ! 95: { ! 96: if (self->waterlevel) ! 97: return; ! 98: self->s.effects |= EF_FLIES; ! 99: self->s.sound = gi.soundindex ("infantry/inflies1.wav"); ! 100: self->think = M_FliesOff; ! 101: self->nextthink = level.time + 60; ! 102: } ! 103: ! 104: void M_FlyCheck (edict_t *self) ! 105: { ! 106: if (self->waterlevel) ! 107: return; ! 108: ! 109: if (random() > 0.5) ! 110: return; ! 111: ! 112: self->think = M_FliesOn; ! 113: self->nextthink = level.time + 5 + 10 * random(); ! 114: } ! 115: ! 116: void AttackFinished (edict_t *self, float time) ! 117: { ! 118: self->monsterinfo.attack_finished = level.time + time; ! 119: } ! 120: ! 121: ! 122: void M_CheckGround (edict_t *ent) ! 123: { ! 124: vec3_t point; ! 125: trace_t trace; ! 126: ! 127: if (ent->flags & (FL_SWIM|FL_FLY)) ! 128: return; ! 129: ! 130: if (ent->velocity[2] > 100) ! 131: { ! 132: ent->groundentity = NULL; ! 133: return; ! 134: } ! 135: ! 136: // if the hull point one-quarter unit down is solid the entity is on ground ! 137: point[0] = ent->s.origin[0]; ! 138: point[1] = ent->s.origin[1]; ! 139: point[2] = ent->s.origin[2] - 0.25; ! 140: ! 141: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID); ! 142: ! 143: // check steepness ! 144: if ( trace.plane.normal[2] < 0.7 && !trace.startsolid) ! 145: { ! 146: ent->groundentity = NULL; ! 147: return; ! 148: } ! 149: ! 150: // ent->groundentity = trace.ent; ! 151: // ent->groundentity_linkcount = trace.ent->linkcount; ! 152: // if (!trace.startsolid && !trace.allsolid) ! 153: // VectorCopy (trace.endpos, ent->s.origin); ! 154: if (!trace.startsolid && !trace.allsolid) ! 155: { ! 156: VectorCopy (trace.endpos, ent->s.origin); ! 157: ent->groundentity = trace.ent; ! 158: ent->groundentity_linkcount = trace.ent->linkcount; ! 159: ent->velocity[2] = 0; ! 160: } ! 161: } ! 162: ! 163: ! 164: void M_CatagorizePosition (edict_t *ent) ! 165: { ! 166: vec3_t point; ! 167: int cont; ! 168: ! 169: // ! 170: // get waterlevel ! 171: // ! 172: point[0] = ent->s.origin[0]; ! 173: point[1] = ent->s.origin[1]; ! 174: point[2] = ent->s.origin[2] + ent->mins[2] + 1; ! 175: cont = gi.pointcontents (point); ! 176: ! 177: if (!(cont & MASK_WATER)) ! 178: { ! 179: ent->waterlevel = 0; ! 180: ent->watertype = 0; ! 181: return; ! 182: } ! 183: ! 184: ent->watertype = cont; ! 185: ent->waterlevel = 1; ! 186: point[2] += 26; ! 187: cont = gi.pointcontents (point); ! 188: if (!(cont & MASK_WATER)) ! 189: return; ! 190: ! 191: ent->waterlevel = 2; ! 192: point[2] += 22; ! 193: cont = gi.pointcontents (point); ! 194: if (cont & MASK_WATER) ! 195: ent->waterlevel = 3; ! 196: } ! 197: ! 198: ! 199: void M_WorldEffects (edict_t *ent) ! 200: { ! 201: int dmg; ! 202: ! 203: if (ent->health > 0) ! 204: { ! 205: if (!(ent->flags & FL_SWIM)) ! 206: { ! 207: if (ent->waterlevel < 3) ! 208: { ! 209: ent->air_finished = level.time + 12; ! 210: } ! 211: else if (ent->air_finished < level.time) ! 212: { // drown! ! 213: if (ent->pain_debounce_time < level.time) ! 214: { ! 215: dmg = 2 + 2 * floor(level.time - ent->air_finished); ! 216: if (dmg > 15) ! 217: dmg = 15; ! 218: T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER); ! 219: ent->pain_debounce_time = level.time + 1; ! 220: } ! 221: } ! 222: } ! 223: else ! 224: { ! 225: if (ent->waterlevel > 0) ! 226: { ! 227: ent->air_finished = level.time + 9; ! 228: } ! 229: else if (ent->air_finished < level.time) ! 230: { // suffocate! ! 231: if (ent->pain_debounce_time < level.time) ! 232: { ! 233: dmg = 2 + 2 * floor(level.time - ent->air_finished); ! 234: if (dmg > 15) ! 235: dmg = 15; ! 236: T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER); ! 237: ent->pain_debounce_time = level.time + 1; ! 238: } ! 239: } ! 240: } ! 241: } ! 242: ! 243: if (ent->waterlevel == 0) ! 244: { ! 245: if (ent->flags & FL_INWATER) ! 246: { ! 247: gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0); ! 248: ent->flags &= ~FL_INWATER; ! 249: } ! 250: return; ! 251: } ! 252: ! 253: if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA)) ! 254: { ! 255: if (ent->damage_debounce_time < level.time) ! 256: { ! 257: ent->damage_debounce_time = level.time + 0.2; ! 258: T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA); ! 259: } ! 260: } ! 261: if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME)) ! 262: { ! 263: if (ent->damage_debounce_time < level.time) ! 264: { ! 265: ent->damage_debounce_time = level.time + 1; ! 266: T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME); ! 267: } ! 268: } ! 269: ! 270: if ( !(ent->flags & FL_INWATER) ) ! 271: { ! 272: if (!(ent->svflags & SVF_DEADMONSTER)) ! 273: { ! 274: if (ent->watertype & CONTENTS_LAVA) ! 275: if (random() <= 0.5) ! 276: gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0); ! 277: else ! 278: gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0); ! 279: else if (ent->watertype & CONTENTS_SLIME) ! 280: gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 281: else if (ent->watertype & CONTENTS_WATER) ! 282: gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 283: } ! 284: ! 285: ent->flags |= FL_INWATER; ! 286: ent->damage_debounce_time = 0; ! 287: } ! 288: } ! 289: ! 290: ! 291: void M_droptofloor (edict_t *ent) ! 292: { ! 293: vec3_t end; ! 294: trace_t trace; ! 295: ! 296: ent->s.origin[2] += 1; ! 297: VectorCopy (ent->s.origin, end); ! 298: end[2] -= 256; ! 299: ! 300: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 301: ! 302: if (trace.fraction == 1 || trace.allsolid) ! 303: return; ! 304: ! 305: VectorCopy (trace.endpos, ent->s.origin); ! 306: ! 307: gi.linkentity (ent); ! 308: M_CheckGround (ent); ! 309: M_CatagorizePosition (ent); ! 310: } ! 311: ! 312: ! 313: void M_SetEffects (edict_t *ent) ! 314: { ! 315: ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN); ! 316: ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE); ! 317: ! 318: if (ent->monsterinfo.aiflags & AI_RESURRECTING) ! 319: { ! 320: ent->s.effects |= EF_COLOR_SHELL; ! 321: ent->s.renderfx |= RF_SHELL_RED; ! 322: } ! 323: ! 324: if (ent->health <= 0) ! 325: return; ! 326: ! 327: if (ent->powerarmor_time > level.time) ! 328: { ! 329: if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN) ! 330: { ! 331: ent->s.effects |= EF_POWERSCREEN; ! 332: } ! 333: else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD) ! 334: { ! 335: ent->s.effects |= EF_COLOR_SHELL; ! 336: ent->s.renderfx |= RF_SHELL_GREEN; ! 337: } ! 338: } ! 339: } ! 340: ! 341: ! 342: void M_MoveFrame (edict_t *self) ! 343: { ! 344: mmove_t *move; ! 345: int index; ! 346: ! 347: move = self->monsterinfo.currentmove; ! 348: self->nextthink = level.time + FRAMETIME; ! 349: ! 350: if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe)) ! 351: { ! 352: self->s.frame = self->monsterinfo.nextframe; ! 353: self->monsterinfo.nextframe = 0; ! 354: } ! 355: else ! 356: { ! 357: if (self->s.frame == move->lastframe) ! 358: { ! 359: if (move->endfunc) ! 360: { ! 361: move->endfunc (self); ! 362: ! 363: // regrab move, endfunc is very likely to change it ! 364: move = self->monsterinfo.currentmove; ! 365: ! 366: // check for death ! 367: if (self->svflags & SVF_DEADMONSTER) ! 368: return; ! 369: } ! 370: } ! 371: ! 372: if (self->s.frame < move->firstframe || self->s.frame > move->lastframe) ! 373: { ! 374: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; ! 375: self->s.frame = move->firstframe; ! 376: } ! 377: else ! 378: { ! 379: if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME)) ! 380: { ! 381: self->s.frame++; ! 382: if (self->s.frame > move->lastframe) ! 383: self->s.frame = move->firstframe; ! 384: } ! 385: } ! 386: } ! 387: ! 388: index = self->s.frame - move->firstframe; ! 389: if (move->frame[index].aifunc) ! 390: if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME)) ! 391: move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale); ! 392: else ! 393: move->frame[index].aifunc (self, 0); ! 394: ! 395: if (move->frame[index].thinkfunc) ! 396: move->frame[index].thinkfunc (self); ! 397: } ! 398: ! 399: ! 400: void monster_think (edict_t *self) ! 401: { ! 402: M_MoveFrame (self); ! 403: if (self->linkcount != self->monsterinfo.linkcount) ! 404: { ! 405: self->monsterinfo.linkcount = self->linkcount; ! 406: M_CheckGround (self); ! 407: } ! 408: M_CatagorizePosition (self); ! 409: M_WorldEffects (self); ! 410: M_SetEffects (self); ! 411: } ! 412: ! 413: ! 414: /* ! 415: ================ ! 416: monster_use ! 417: ! 418: Using a monster makes it angry at the current activator ! 419: ================ ! 420: */ ! 421: void monster_use (edict_t *self, edict_t *other, edict_t *activator) ! 422: { ! 423: if (self->enemy) ! 424: return; ! 425: if (self->health <= 0) ! 426: return; ! 427: if (activator->flags & FL_NOTARGET) ! 428: return; ! 429: if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY)) ! 430: return; ! 431: ! 432: // delay reaction so if the monster is teleported, its sound is still heard ! 433: self->enemy = activator; ! 434: FoundTarget (self); ! 435: } ! 436: ! 437: ! 438: void monster_start_go (edict_t *self); ! 439: ! 440: ! 441: void monster_triggered_spawn (edict_t *self) ! 442: { ! 443: self->s.origin[2] += 1; ! 444: KillBox (self); ! 445: ! 446: self->solid = SOLID_BBOX; ! 447: self->movetype = MOVETYPE_STEP; ! 448: self->svflags &= ~SVF_NOCLIENT; ! 449: self->air_finished = level.time + 12; ! 450: gi.linkentity (self); ! 451: ! 452: monster_start_go (self); ! 453: ! 454: if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET)) ! 455: { ! 456: FoundTarget (self); ! 457: } ! 458: else ! 459: { ! 460: self->enemy = NULL; ! 461: } ! 462: } ! 463: ! 464: void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator) ! 465: { ! 466: // we have a one frame delay here so we don't telefrag the guy who activated us ! 467: self->think = monster_triggered_spawn; ! 468: self->nextthink = level.time + FRAMETIME; ! 469: if (activator->client) ! 470: self->enemy = activator; ! 471: self->use = monster_use; ! 472: } ! 473: ! 474: void monster_triggered_start (edict_t *self) ! 475: { ! 476: self->solid = SOLID_NOT; ! 477: self->movetype = MOVETYPE_NONE; ! 478: self->svflags |= SVF_NOCLIENT; ! 479: self->nextthink = 0; ! 480: self->use = monster_triggered_spawn_use; ! 481: } ! 482: ! 483: ! 484: /* ! 485: ================ ! 486: monster_death_use ! 487: ! 488: When a monster dies, it fires all of its targets with the current ! 489: enemy as activator. ! 490: ================ ! 491: */ ! 492: void monster_death_use (edict_t *self) ! 493: { ! 494: self->flags &= ~(FL_FLY|FL_SWIM); ! 495: self->monsterinfo.aiflags &= AI_GOOD_GUY; ! 496: ! 497: if (self->item) ! 498: { ! 499: Drop_Item (self, self->item); ! 500: self->item = NULL; ! 501: } ! 502: ! 503: if (self->deathtarget) ! 504: self->target = self->deathtarget; ! 505: ! 506: if (!self->target) ! 507: return; ! 508: ! 509: G_UseTargets (self, self->enemy); ! 510: } ! 511: ! 512: ! 513: //============================================================================ ! 514: ! 515: qboolean monster_start (edict_t *self) ! 516: { ! 517: if (deathmatch->value) ! 518: { ! 519: G_FreeEdict (self); ! 520: return false; ! 521: } ! 522: ! 523: if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY)) ! 524: { ! 525: self->spawnflags &= ~4; ! 526: self->spawnflags |= 1; ! 527: // gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin)); ! 528: } ! 529: ! 530: if (!(self->monsterinfo.aiflags & AI_GOOD_GUY)) ! 531: level.total_monsters++; ! 532: ! 533: self->nextthink = level.time + FRAMETIME; ! 534: self->svflags |= SVF_MONSTER; ! 535: self->s.renderfx |= RF_FRAMELERP; ! 536: self->takedamage = DAMAGE_AIM; ! 537: self->air_finished = level.time + 12; ! 538: self->use = monster_use; ! 539: self->max_health = self->health; ! 540: self->clipmask = MASK_MONSTERSOLID; ! 541: ! 542: self->s.skinnum = 0; ! 543: self->deadflag = DEAD_NO; ! 544: self->svflags &= ~SVF_DEADMONSTER; ! 545: ! 546: if (!self->monsterinfo.checkattack) ! 547: self->monsterinfo.checkattack = M_CheckAttack; ! 548: VectorCopy (self->s.origin, self->s.old_origin); ! 549: ! 550: if (st.item) ! 551: { ! 552: self->item = FindItemByClassname (st.item); ! 553: if (!self->item) ! 554: gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item); ! 555: } ! 556: ! 557: // randomize what frame they start on ! 558: if (self->monsterinfo.currentmove) ! 559: self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1)); ! 560: ! 561: return true; ! 562: } ! 563: ! 564: void monster_start_go (edict_t *self) ! 565: { ! 566: vec3_t v; ! 567: ! 568: if (self->health <= 0) ! 569: return; ! 570: ! 571: // check for target to combat_point and change to combattarget ! 572: if (self->target) ! 573: { ! 574: qboolean notcombat; ! 575: qboolean fixup; ! 576: edict_t *target; ! 577: ! 578: target = NULL; ! 579: notcombat = false; ! 580: fixup = false; ! 581: while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL) ! 582: { ! 583: if (strcmp(target->classname, "point_combat") == 0) ! 584: { ! 585: self->combattarget = self->target; ! 586: fixup = true; ! 587: } ! 588: else ! 589: { ! 590: notcombat = true; ! 591: } ! 592: } ! 593: if (notcombat && self->combattarget) ! 594: gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin)); ! 595: if (fixup) ! 596: self->target = NULL; ! 597: } ! 598: ! 599: // validate combattarget ! 600: if (self->combattarget) ! 601: { ! 602: edict_t *target; ! 603: ! 604: target = NULL; ! 605: while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL) ! 606: { ! 607: if (strcmp(target->classname, "point_combat") != 0) ! 608: { ! 609: gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n", ! 610: self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2], ! 611: self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1], ! 612: (int)target->s.origin[2]); ! 613: } ! 614: } ! 615: } ! 616: ! 617: if (self->target) ! 618: { ! 619: self->goalentity = self->movetarget = G_PickTarget(self->target); ! 620: if (!self->movetarget) ! 621: { ! 622: gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin)); ! 623: self->target = NULL; ! 624: self->monsterinfo.pausetime = 100000000; ! 625: self->monsterinfo.stand (self); ! 626: } ! 627: else if (strcmp (self->movetarget->classname, "path_corner") == 0) ! 628: { ! 629: VectorSubtract (self->goalentity->s.origin, self->s.origin, v); ! 630: self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v); ! 631: self->monsterinfo.walk (self); ! 632: self->target = NULL; ! 633: } ! 634: else ! 635: { ! 636: self->goalentity = self->movetarget = NULL; ! 637: self->monsterinfo.pausetime = 100000000; ! 638: self->monsterinfo.stand (self); ! 639: } ! 640: } ! 641: else ! 642: { ! 643: self->monsterinfo.pausetime = 100000000; ! 644: self->monsterinfo.stand (self); ! 645: } ! 646: ! 647: self->think = monster_think; ! 648: self->nextthink = level.time + FRAMETIME; ! 649: } ! 650: ! 651: ! 652: void walkmonster_start_go (edict_t *self) ! 653: { ! 654: if (!(self->spawnflags & 2) && level.time < 1) ! 655: { ! 656: M_droptofloor (self); ! 657: ! 658: if (self->groundentity) ! 659: if (!M_walkmove (self, 0, 0)) ! 660: gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin)); ! 661: } ! 662: ! 663: if (!self->yaw_speed) ! 664: self->yaw_speed = 20; ! 665: self->viewheight = 25; ! 666: ! 667: monster_start_go (self); ! 668: ! 669: if (self->spawnflags & 2) ! 670: monster_triggered_start (self); ! 671: } ! 672: ! 673: void walkmonster_start (edict_t *self) ! 674: { ! 675: self->think = walkmonster_start_go; ! 676: monster_start (self); ! 677: } ! 678: ! 679: ! 680: void flymonster_start_go (edict_t *self) ! 681: { ! 682: if (!M_walkmove (self, 0, 0)) ! 683: gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin)); ! 684: ! 685: if (!self->yaw_speed) ! 686: self->yaw_speed = 10; ! 687: self->viewheight = 25; ! 688: ! 689: monster_start_go (self); ! 690: ! 691: if (self->spawnflags & 2) ! 692: monster_triggered_start (self); ! 693: } ! 694: ! 695: ! 696: void flymonster_start (edict_t *self) ! 697: { ! 698: self->flags |= FL_FLY; ! 699: self->think = flymonster_start_go; ! 700: monster_start (self); ! 701: } ! 702: ! 703: ! 704: void swimmonster_start_go (edict_t *self) ! 705: { ! 706: if (!self->yaw_speed) ! 707: self->yaw_speed = 10; ! 708: self->viewheight = 10; ! 709: ! 710: monster_start_go (self); ! 711: ! 712: if (self->spawnflags & 2) ! 713: monster_triggered_start (self); ! 714: } ! 715: ! 716: void swimmonster_start (edict_t *self) ! 717: { ! 718: self->flags |= FL_SWIM; ! 719: self->think = swimmonster_start_go; ! 720: monster_start (self); ! 721: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.