m_flyer.c (14678B)
1 /* 2 Copyright (C) 1997-2001 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 /* 21 ============================================================================== 22 23 flyer 24 25 ============================================================================== 26 */ 27 28 #include "g_local.h" 29 #include "m_flyer.h" 30 31 qboolean visible (edict_t *self, edict_t *other); 32 33 static int nextmove; // Used for start/stop frames 34 35 static int sound_sight; 36 static int sound_idle; 37 static int sound_pain1; 38 static int sound_pain2; 39 static int sound_slash; 40 static int sound_sproing; 41 static int sound_die; 42 43 44 void flyer_check_melee(edict_t *self); 45 void flyer_loop_melee (edict_t *self); 46 void flyer_melee (edict_t *self); 47 void flyer_setstart (edict_t *self); 48 void flyer_stand (edict_t *self); 49 void flyer_nextmove (edict_t *self); 50 51 52 void flyer_sight (edict_t *self, edict_t *other) 53 { 54 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); 55 } 56 57 void flyer_idle (edict_t *self) 58 { 59 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0); 60 } 61 62 void flyer_pop_blades (edict_t *self) 63 { 64 gi.sound (self, CHAN_VOICE, sound_sproing, 1, ATTN_NORM, 0); 65 } 66 67 68 mframe_t flyer_frames_stand [] = 69 { 70 ai_stand, 0, NULL, 71 ai_stand, 0, NULL, 72 ai_stand, 0, NULL, 73 ai_stand, 0, NULL, 74 ai_stand, 0, NULL, 75 ai_stand, 0, NULL, 76 ai_stand, 0, NULL, 77 ai_stand, 0, NULL, 78 ai_stand, 0, NULL, 79 ai_stand, 0, NULL, 80 ai_stand, 0, NULL, 81 ai_stand, 0, NULL, 82 ai_stand, 0, NULL, 83 ai_stand, 0, NULL, 84 ai_stand, 0, NULL, 85 ai_stand, 0, NULL, 86 ai_stand, 0, NULL, 87 ai_stand, 0, NULL, 88 ai_stand, 0, NULL, 89 ai_stand, 0, NULL, 90 ai_stand, 0, NULL, 91 ai_stand, 0, NULL, 92 ai_stand, 0, NULL, 93 ai_stand, 0, NULL, 94 ai_stand, 0, NULL, 95 ai_stand, 0, NULL, 96 ai_stand, 0, NULL, 97 ai_stand, 0, NULL, 98 ai_stand, 0, NULL, 99 ai_stand, 0, NULL, 100 ai_stand, 0, NULL, 101 ai_stand, 0, NULL, 102 ai_stand, 0, NULL, 103 ai_stand, 0, NULL, 104 ai_stand, 0, NULL, 105 ai_stand, 0, NULL, 106 ai_stand, 0, NULL, 107 ai_stand, 0, NULL, 108 ai_stand, 0, NULL, 109 ai_stand, 0, NULL, 110 ai_stand, 0, NULL, 111 ai_stand, 0, NULL, 112 ai_stand, 0, NULL, 113 ai_stand, 0, NULL, 114 ai_stand, 0, NULL 115 }; 116 mmove_t flyer_move_stand = {FRAME_stand01, FRAME_stand45, flyer_frames_stand, NULL}; 117 118 119 mframe_t flyer_frames_walk [] = 120 { 121 ai_walk, 5, NULL, 122 ai_walk, 5, NULL, 123 ai_walk, 5, NULL, 124 ai_walk, 5, NULL, 125 ai_walk, 5, NULL, 126 ai_walk, 5, NULL, 127 ai_walk, 5, NULL, 128 ai_walk, 5, NULL, 129 ai_walk, 5, NULL, 130 ai_walk, 5, NULL, 131 ai_walk, 5, NULL, 132 ai_walk, 5, NULL, 133 ai_walk, 5, NULL, 134 ai_walk, 5, NULL, 135 ai_walk, 5, NULL, 136 ai_walk, 5, NULL, 137 ai_walk, 5, NULL, 138 ai_walk, 5, NULL, 139 ai_walk, 5, NULL, 140 ai_walk, 5, NULL, 141 ai_walk, 5, NULL, 142 ai_walk, 5, NULL, 143 ai_walk, 5, NULL, 144 ai_walk, 5, NULL, 145 ai_walk, 5, NULL, 146 ai_walk, 5, NULL, 147 ai_walk, 5, NULL, 148 ai_walk, 5, NULL, 149 ai_walk, 5, NULL, 150 ai_walk, 5, NULL, 151 ai_walk, 5, NULL, 152 ai_walk, 5, NULL, 153 ai_walk, 5, NULL, 154 ai_walk, 5, NULL, 155 ai_walk, 5, NULL, 156 ai_walk, 5, NULL, 157 ai_walk, 5, NULL, 158 ai_walk, 5, NULL, 159 ai_walk, 5, NULL, 160 ai_walk, 5, NULL, 161 ai_walk, 5, NULL, 162 ai_walk, 5, NULL, 163 ai_walk, 5, NULL, 164 ai_walk, 5, NULL, 165 ai_walk, 5, NULL 166 }; 167 mmove_t flyer_move_walk = {FRAME_stand01, FRAME_stand45, flyer_frames_walk, NULL}; 168 169 mframe_t flyer_frames_run [] = 170 { 171 ai_run, 10, NULL, 172 ai_run, 10, NULL, 173 ai_run, 10, NULL, 174 ai_run, 10, NULL, 175 ai_run, 10, NULL, 176 ai_run, 10, NULL, 177 ai_run, 10, NULL, 178 ai_run, 10, NULL, 179 ai_run, 10, NULL, 180 ai_run, 10, NULL, 181 ai_run, 10, NULL, 182 ai_run, 10, NULL, 183 ai_run, 10, NULL, 184 ai_run, 10, NULL, 185 ai_run, 10, NULL, 186 ai_run, 10, NULL, 187 ai_run, 10, NULL, 188 ai_run, 10, NULL, 189 ai_run, 10, NULL, 190 ai_run, 10, NULL, 191 ai_run, 10, NULL, 192 ai_run, 10, NULL, 193 ai_run, 10, NULL, 194 ai_run, 10, NULL, 195 ai_run, 10, NULL, 196 ai_run, 10, NULL, 197 ai_run, 10, NULL, 198 ai_run, 10, NULL, 199 ai_run, 10, NULL, 200 ai_run, 10, NULL, 201 ai_run, 10, NULL, 202 ai_run, 10, NULL, 203 ai_run, 10, NULL, 204 ai_run, 10, NULL, 205 ai_run, 10, NULL, 206 ai_run, 10, NULL, 207 ai_run, 10, NULL, 208 ai_run, 10, NULL, 209 ai_run, 10, NULL, 210 ai_run, 10, NULL, 211 ai_run, 10, NULL, 212 ai_run, 10, NULL, 213 ai_run, 10, NULL, 214 ai_run, 10, NULL, 215 ai_run, 10, NULL 216 }; 217 mmove_t flyer_move_run = {FRAME_stand01, FRAME_stand45, flyer_frames_run, NULL}; 218 219 void flyer_run (edict_t *self) 220 { 221 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 222 self->monsterinfo.currentmove = &flyer_move_stand; 223 else 224 self->monsterinfo.currentmove = &flyer_move_run; 225 } 226 227 void flyer_walk (edict_t *self) 228 { 229 self->monsterinfo.currentmove = &flyer_move_walk; 230 } 231 232 void flyer_stand (edict_t *self) 233 { 234 self->monsterinfo.currentmove = &flyer_move_stand; 235 } 236 237 mframe_t flyer_frames_start [] = 238 { 239 ai_move, 0, NULL, 240 ai_move, 0, NULL, 241 ai_move, 0, NULL, 242 ai_move, 0, NULL, 243 ai_move, 0, NULL, 244 ai_move, 0, flyer_nextmove 245 }; 246 mmove_t flyer_move_start = {FRAME_start01, FRAME_start06, flyer_frames_start, NULL}; 247 248 mframe_t flyer_frames_stop [] = 249 { 250 ai_move, 0, NULL, 251 ai_move, 0, NULL, 252 ai_move, 0, NULL, 253 ai_move, 0, NULL, 254 ai_move, 0, NULL, 255 ai_move, 0, NULL, 256 ai_move, 0, flyer_nextmove 257 }; 258 mmove_t flyer_move_stop = {FRAME_stop01, FRAME_stop07, flyer_frames_stop, NULL}; 259 260 void flyer_stop (edict_t *self) 261 { 262 self->monsterinfo.currentmove = &flyer_move_stop; 263 } 264 265 void flyer_start (edict_t *self) 266 { 267 self->monsterinfo.currentmove = &flyer_move_start; 268 } 269 270 271 mframe_t flyer_frames_rollright [] = 272 { 273 ai_move, 0, NULL, 274 ai_move, 0, NULL, 275 ai_move, 0, NULL, 276 ai_move, 0, NULL, 277 ai_move, 0, NULL, 278 ai_move, 0, NULL, 279 ai_move, 0, NULL, 280 ai_move, 0, NULL, 281 ai_move, 0, NULL 282 }; 283 mmove_t flyer_move_rollright = {FRAME_rollr01, FRAME_rollr09, flyer_frames_rollright, NULL}; 284 285 mframe_t flyer_frames_rollleft [] = 286 { 287 ai_move, 0, NULL, 288 ai_move, 0, NULL, 289 ai_move, 0, NULL, 290 ai_move, 0, NULL, 291 ai_move, 0, NULL, 292 ai_move, 0, NULL, 293 ai_move, 0, NULL, 294 ai_move, 0, NULL, 295 ai_move, 0, NULL 296 }; 297 mmove_t flyer_move_rollleft = {FRAME_rollf01, FRAME_rollf09, flyer_frames_rollleft, NULL}; 298 299 mframe_t flyer_frames_pain3 [] = 300 { 301 ai_move, 0, NULL, 302 ai_move, 0, NULL, 303 ai_move, 0, NULL, 304 ai_move, 0, NULL 305 }; 306 mmove_t flyer_move_pain3 = {FRAME_pain301, FRAME_pain304, flyer_frames_pain3, flyer_run}; 307 308 mframe_t flyer_frames_pain2 [] = 309 { 310 ai_move, 0, NULL, 311 ai_move, 0, NULL, 312 ai_move, 0, NULL, 313 ai_move, 0, NULL 314 }; 315 mmove_t flyer_move_pain2 = {FRAME_pain201, FRAME_pain204, flyer_frames_pain2, flyer_run}; 316 317 mframe_t flyer_frames_pain1 [] = 318 { 319 ai_move, 0, NULL, 320 ai_move, 0, NULL, 321 ai_move, 0, NULL, 322 ai_move, 0, NULL, 323 ai_move, 0, NULL, 324 ai_move, 0, NULL, 325 ai_move, 0, NULL, 326 ai_move, 0, NULL, 327 ai_move, 0, NULL 328 }; 329 mmove_t flyer_move_pain1 = {FRAME_pain101, FRAME_pain109, flyer_frames_pain1, flyer_run}; 330 331 mframe_t flyer_frames_defense [] = 332 { 333 ai_move, 0, NULL, 334 ai_move, 0, NULL, 335 ai_move, 0, NULL, // Hold this frame 336 ai_move, 0, NULL, 337 ai_move, 0, NULL, 338 ai_move, 0, NULL 339 }; 340 mmove_t flyer_move_defense = {FRAME_defens01, FRAME_defens06, flyer_frames_defense, NULL}; 341 342 mframe_t flyer_frames_bankright [] = 343 { 344 ai_move, 0, NULL, 345 ai_move, 0, NULL, 346 ai_move, 0, NULL, 347 ai_move, 0, NULL, 348 ai_move, 0, NULL, 349 ai_move, 0, NULL, 350 ai_move, 0, NULL 351 }; 352 mmove_t flyer_move_bankright = {FRAME_bankr01, FRAME_bankr07, flyer_frames_bankright, NULL}; 353 354 mframe_t flyer_frames_bankleft [] = 355 { 356 ai_move, 0, NULL, 357 ai_move, 0, NULL, 358 ai_move, 0, NULL, 359 ai_move, 0, NULL, 360 ai_move, 0, NULL, 361 ai_move, 0, NULL, 362 ai_move, 0, NULL 363 }; 364 mmove_t flyer_move_bankleft = {FRAME_bankl01, FRAME_bankl07, flyer_frames_bankleft, NULL}; 365 366 367 void flyer_fire (edict_t *self, int flash_number) 368 { 369 vec3_t start; 370 vec3_t forward, right; 371 vec3_t end; 372 vec3_t dir; 373 int effect; 374 375 if ((self->s.frame == FRAME_attak204) || (self->s.frame == FRAME_attak207) || (self->s.frame == FRAME_attak210)) 376 effect = EF_HYPERBLASTER; 377 else 378 effect = 0; 379 AngleVectors (self->s.angles, forward, right, NULL); 380 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); 381 382 VectorCopy (self->enemy->s.origin, end); 383 end[2] += self->enemy->viewheight; 384 VectorSubtract (end, start, dir); 385 386 monster_fire_blaster (self, start, dir, 1, 1000, flash_number, effect); 387 } 388 389 void flyer_fireleft (edict_t *self) 390 { 391 flyer_fire (self, MZ2_FLYER_BLASTER_1); 392 } 393 394 void flyer_fireright (edict_t *self) 395 { 396 flyer_fire (self, MZ2_FLYER_BLASTER_2); 397 } 398 399 400 mframe_t flyer_frames_attack2 [] = 401 { 402 ai_charge, 0, NULL, 403 ai_charge, 0, NULL, 404 ai_charge, 0, NULL, 405 ai_charge, -10, flyer_fireleft, // left gun 406 ai_charge, -10, flyer_fireright, // right gun 407 ai_charge, -10, flyer_fireleft, // left gun 408 ai_charge, -10, flyer_fireright, // right gun 409 ai_charge, -10, flyer_fireleft, // left gun 410 ai_charge, -10, flyer_fireright, // right gun 411 ai_charge, -10, flyer_fireleft, // left gun 412 ai_charge, -10, flyer_fireright, // right gun 413 ai_charge, 0, NULL, 414 ai_charge, 0, NULL, 415 ai_charge, 0, NULL, 416 ai_charge, 0, NULL, 417 ai_charge, 0, NULL, 418 ai_charge, 0, NULL 419 }; 420 mmove_t flyer_move_attack2 = {FRAME_attak201, FRAME_attak217, flyer_frames_attack2, flyer_run}; 421 422 423 void flyer_slash_left (edict_t *self) 424 { 425 vec3_t aim; 426 427 VectorSet (aim, MELEE_DISTANCE, self->mins[0], 0); 428 fire_hit (self, aim, 5, 0); 429 gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0); 430 } 431 432 void flyer_slash_right (edict_t *self) 433 { 434 vec3_t aim; 435 436 VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 0); 437 fire_hit (self, aim, 5, 0); 438 gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0); 439 } 440 441 mframe_t flyer_frames_start_melee [] = 442 { 443 ai_charge, 0, flyer_pop_blades, 444 ai_charge, 0, NULL, 445 ai_charge, 0, NULL, 446 ai_charge, 0, NULL, 447 ai_charge, 0, NULL, 448 ai_charge, 0, NULL 449 }; 450 mmove_t flyer_move_start_melee = {FRAME_attak101, FRAME_attak106, flyer_frames_start_melee, flyer_loop_melee}; 451 452 mframe_t flyer_frames_end_melee [] = 453 { 454 ai_charge, 0, NULL, 455 ai_charge, 0, NULL, 456 ai_charge, 0, NULL 457 }; 458 mmove_t flyer_move_end_melee = {FRAME_attak119, FRAME_attak121, flyer_frames_end_melee, flyer_run}; 459 460 461 mframe_t flyer_frames_loop_melee [] = 462 { 463 ai_charge, 0, NULL, // Loop Start 464 ai_charge, 0, NULL, 465 ai_charge, 0, flyer_slash_left, // Left Wing Strike 466 ai_charge, 0, NULL, 467 ai_charge, 0, NULL, 468 ai_charge, 0, NULL, 469 ai_charge, 0, NULL, 470 ai_charge, 0, flyer_slash_right, // Right Wing Strike 471 ai_charge, 0, NULL, 472 ai_charge, 0, NULL, 473 ai_charge, 0, NULL, 474 ai_charge, 0, NULL // Loop Ends 475 476 }; 477 mmove_t flyer_move_loop_melee = {FRAME_attak107, FRAME_attak118, flyer_frames_loop_melee, flyer_check_melee}; 478 479 void flyer_loop_melee (edict_t *self) 480 { 481 /* if (random() <= 0.5) 482 self->monsterinfo.currentmove = &flyer_move_attack1; 483 else */ 484 self->monsterinfo.currentmove = &flyer_move_loop_melee; 485 } 486 487 488 489 void flyer_attack (edict_t *self) 490 { 491 /* if (random() <= 0.5) 492 self->monsterinfo.currentmove = &flyer_move_attack1; 493 else */ 494 self->monsterinfo.currentmove = &flyer_move_attack2; 495 } 496 497 void flyer_setstart (edict_t *self) 498 { 499 nextmove = ACTION_run; 500 self->monsterinfo.currentmove = &flyer_move_start; 501 } 502 503 void flyer_nextmove (edict_t *self) 504 { 505 if (nextmove == ACTION_attack1) 506 self->monsterinfo.currentmove = &flyer_move_start_melee; 507 else if (nextmove == ACTION_attack2) 508 self->monsterinfo.currentmove = &flyer_move_attack2; 509 else if (nextmove == ACTION_run) 510 self->monsterinfo.currentmove = &flyer_move_run; 511 } 512 513 void flyer_melee (edict_t *self) 514 { 515 // flyer.nextmove = ACTION_attack1; 516 // self->monsterinfo.currentmove = &flyer_move_stop; 517 self->monsterinfo.currentmove = &flyer_move_start_melee; 518 } 519 520 void flyer_check_melee(edict_t *self) 521 { 522 if (range (self, self->enemy) == RANGE_MELEE) 523 if (random() <= 0.8) 524 self->monsterinfo.currentmove = &flyer_move_loop_melee; 525 else 526 self->monsterinfo.currentmove = &flyer_move_end_melee; 527 else 528 self->monsterinfo.currentmove = &flyer_move_end_melee; 529 } 530 531 void flyer_pain (edict_t *self, edict_t *other, float kick, int damage) 532 { 533 int n; 534 535 if (self->health < (self->max_health / 2)) 536 self->s.skinnum = 1; 537 538 if (level.time < self->pain_debounce_time) 539 return; 540 541 self->pain_debounce_time = level.time + 3; 542 if (skill->value == 3) 543 return; // no pain anims in nightmare 544 545 n = rand() % 3; 546 if (n == 0) 547 { 548 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 549 self->monsterinfo.currentmove = &flyer_move_pain1; 550 } 551 else if (n == 1) 552 { 553 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0); 554 self->monsterinfo.currentmove = &flyer_move_pain2; 555 } 556 else 557 { 558 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 559 self->monsterinfo.currentmove = &flyer_move_pain3; 560 } 561 } 562 563 564 void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 565 { 566 gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); 567 BecomeExplosion1(self); 568 } 569 570 571 /*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 572 */ 573 void SP_monster_flyer (edict_t *self) 574 { 575 if (deathmatch->value) 576 { 577 G_FreeEdict (self); 578 return; 579 } 580 581 // fix a map bug in jail5.bsp 582 if (!Q_stricmp(level.mapname, "jail5") && (self->s.origin[2] == -104)) 583 { 584 self->targetname = self->target; 585 self->target = NULL; 586 } 587 588 sound_sight = gi.soundindex ("flyer/flysght1.wav"); 589 sound_idle = gi.soundindex ("flyer/flysrch1.wav"); 590 sound_pain1 = gi.soundindex ("flyer/flypain1.wav"); 591 sound_pain2 = gi.soundindex ("flyer/flypain2.wav"); 592 sound_slash = gi.soundindex ("flyer/flyatck2.wav"); 593 sound_sproing = gi.soundindex ("flyer/flyatck1.wav"); 594 sound_die = gi.soundindex ("flyer/flydeth1.wav"); 595 596 gi.soundindex ("flyer/flyatck3.wav"); 597 598 self->s.modelindex = gi.modelindex ("models/monsters/flyer/tris.md2"); 599 VectorSet (self->mins, -16, -16, -24); 600 VectorSet (self->maxs, 16, 16, 32); 601 self->movetype = MOVETYPE_STEP; 602 self->solid = SOLID_BBOX; 603 604 self->s.sound = gi.soundindex ("flyer/flyidle1.wav"); 605 606 self->health = 50; 607 self->mass = 50; 608 609 self->pain = flyer_pain; 610 self->die = flyer_die; 611 612 self->monsterinfo.stand = flyer_stand; 613 self->monsterinfo.walk = flyer_walk; 614 self->monsterinfo.run = flyer_run; 615 self->monsterinfo.attack = flyer_attack; 616 self->monsterinfo.melee = flyer_melee; 617 self->monsterinfo.sight = flyer_sight; 618 self->monsterinfo.idle = flyer_idle; 619 620 gi.linkentity (self); 621 622 self->monsterinfo.currentmove = &flyer_move_stand; 623 self->monsterinfo.scale = MODEL_SCALE; 624 625 flymonster_start (self); 626 }