m_boss2.c (16533B)
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 boss2 24 25 ============================================================================== 26 */ 27 28 #include "g_local.h" 29 #include "m_boss2.h" 30 31 void BossExplode (edict_t *self); 32 33 qboolean infront (edict_t *self, edict_t *other); 34 35 static int sound_pain1; 36 static int sound_pain2; 37 static int sound_pain3; 38 static int sound_death; 39 static int sound_search1; 40 41 void boss2_search (edict_t *self) 42 { 43 if (random() < 0.5) 44 gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0); 45 } 46 47 void boss2_run (edict_t *self); 48 void boss2_stand (edict_t *self); 49 void boss2_dead (edict_t *self); 50 void boss2_attack (edict_t *self); 51 void boss2_attack_mg (edict_t *self); 52 void boss2_reattack_mg (edict_t *self); 53 void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); 54 55 void Boss2Rocket (edict_t *self) 56 { 57 vec3_t forward, right; 58 vec3_t start; 59 vec3_t dir; 60 vec3_t vec; 61 62 AngleVectors (self->s.angles, forward, right, NULL); 63 64 //1 65 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start); 66 VectorCopy (self->enemy->s.origin, vec); 67 vec[2] += self->enemy->viewheight; 68 VectorSubtract (vec, start, dir); 69 VectorNormalize (dir); 70 monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1); 71 72 //2 73 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start); 74 VectorCopy (self->enemy->s.origin, vec); 75 vec[2] += self->enemy->viewheight; 76 VectorSubtract (vec, start, dir); 77 VectorNormalize (dir); 78 monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2); 79 80 //3 81 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start); 82 VectorCopy (self->enemy->s.origin, vec); 83 vec[2] += self->enemy->viewheight; 84 VectorSubtract (vec, start, dir); 85 VectorNormalize (dir); 86 monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3); 87 88 //4 89 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start); 90 VectorCopy (self->enemy->s.origin, vec); 91 vec[2] += self->enemy->viewheight; 92 VectorSubtract (vec, start, dir); 93 VectorNormalize (dir); 94 monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4); 95 } 96 97 void boss2_firebullet_right (edict_t *self) 98 { 99 vec3_t forward, right, target; 100 vec3_t start; 101 102 AngleVectors (self->s.angles, forward, right, NULL); 103 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1], forward, right, start); 104 105 VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target); 106 target[2] += self->enemy->viewheight; 107 VectorSubtract (target, start, forward); 108 VectorNormalize (forward); 109 110 monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_R1); 111 } 112 113 void boss2_firebullet_left (edict_t *self) 114 { 115 vec3_t forward, right, target; 116 vec3_t start; 117 118 AngleVectors (self->s.angles, forward, right, NULL); 119 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1], forward, right, start); 120 121 VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target); 122 123 target[2] += self->enemy->viewheight; 124 VectorSubtract (target, start, forward); 125 VectorNormalize (forward); 126 127 monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_L1); 128 } 129 130 void Boss2MachineGun (edict_t *self) 131 { 132 /* vec3_t forward, right; 133 vec3_t start; 134 vec3_t dir; 135 vec3_t vec; 136 int flash_number; 137 138 AngleVectors (self->s.angles, forward, right, NULL); 139 140 flash_number = MZ2_BOSS2_MACHINEGUN_1 + (self->s.frame - FRAME_attack10); 141 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); 142 143 VectorCopy (self->enemy->s.origin, vec); 144 vec[2] += self->enemy->viewheight; 145 VectorSubtract (vec, start, dir); 146 VectorNormalize (dir); 147 monster_fire_bullet (self, start, dir, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number); 148 */ 149 boss2_firebullet_left(self); 150 boss2_firebullet_right(self); 151 } 152 153 154 mframe_t boss2_frames_stand [] = 155 { 156 ai_stand, 0, NULL, 157 ai_stand, 0, NULL, 158 ai_stand, 0, NULL, 159 ai_stand, 0, NULL, 160 ai_stand, 0, NULL, 161 ai_stand, 0, NULL, 162 ai_stand, 0, NULL, 163 ai_stand, 0, NULL, 164 ai_stand, 0, NULL, 165 ai_stand, 0, NULL, 166 ai_stand, 0, NULL, 167 ai_stand, 0, NULL, 168 ai_stand, 0, NULL, 169 ai_stand, 0, NULL, 170 ai_stand, 0, NULL, 171 ai_stand, 0, NULL, 172 ai_stand, 0, NULL, 173 ai_stand, 0, NULL, 174 ai_stand, 0, NULL, 175 ai_stand, 0, NULL, 176 ai_stand, 0, NULL 177 }; 178 mmove_t boss2_move_stand = {FRAME_stand30, FRAME_stand50, boss2_frames_stand, NULL}; 179 180 mframe_t boss2_frames_fidget [] = 181 { 182 ai_stand, 0, NULL, 183 ai_stand, 0, NULL, 184 ai_stand, 0, NULL, 185 ai_stand, 0, NULL, 186 ai_stand, 0, NULL, 187 ai_stand, 0, NULL, 188 ai_stand, 0, NULL, 189 ai_stand, 0, NULL, 190 ai_stand, 0, NULL, 191 ai_stand, 0, NULL, 192 ai_stand, 0, NULL, 193 ai_stand, 0, NULL, 194 ai_stand, 0, NULL, 195 ai_stand, 0, NULL, 196 ai_stand, 0, NULL, 197 ai_stand, 0, NULL, 198 ai_stand, 0, NULL, 199 ai_stand, 0, NULL, 200 ai_stand, 0, NULL, 201 ai_stand, 0, NULL, 202 ai_stand, 0, NULL, 203 ai_stand, 0, NULL, 204 ai_stand, 0, NULL, 205 ai_stand, 0, NULL, 206 ai_stand, 0, NULL, 207 ai_stand, 0, NULL, 208 ai_stand, 0, NULL, 209 ai_stand, 0, NULL, 210 ai_stand, 0, NULL, 211 ai_stand, 0, NULL 212 }; 213 mmove_t boss2_move_fidget = {FRAME_stand1, FRAME_stand30, boss2_frames_fidget, NULL}; 214 215 mframe_t boss2_frames_walk [] = 216 { 217 ai_walk, 8, NULL, 218 ai_walk, 8, NULL, 219 ai_walk, 8, NULL, 220 ai_walk, 8, NULL, 221 ai_walk, 8, NULL, 222 ai_walk, 8, NULL, 223 ai_walk, 8, NULL, 224 ai_walk, 8, NULL, 225 ai_walk, 8, NULL, 226 ai_walk, 8, NULL, 227 ai_walk, 8, NULL, 228 ai_walk, 8, NULL, 229 ai_walk, 8, NULL, 230 ai_walk, 8, NULL, 231 ai_walk, 8, NULL, 232 ai_walk, 8, NULL, 233 ai_walk, 8, NULL, 234 ai_walk, 8, NULL, 235 ai_walk, 8, NULL, 236 ai_walk, 8, NULL 237 }; 238 mmove_t boss2_move_walk = {FRAME_walk1, FRAME_walk20, boss2_frames_walk, NULL}; 239 240 241 mframe_t boss2_frames_run [] = 242 { 243 ai_run, 8, NULL, 244 ai_run, 8, NULL, 245 ai_run, 8, NULL, 246 ai_run, 8, NULL, 247 ai_run, 8, NULL, 248 ai_run, 8, NULL, 249 ai_run, 8, NULL, 250 ai_run, 8, NULL, 251 ai_run, 8, NULL, 252 ai_run, 8, NULL, 253 ai_run, 8, NULL, 254 ai_run, 8, NULL, 255 ai_run, 8, NULL, 256 ai_run, 8, NULL, 257 ai_run, 8, NULL, 258 ai_run, 8, NULL, 259 ai_run, 8, NULL, 260 ai_run, 8, NULL, 261 ai_run, 8, NULL, 262 ai_run, 8, NULL 263 }; 264 mmove_t boss2_move_run = {FRAME_walk1, FRAME_walk20, boss2_frames_run, NULL}; 265 266 mframe_t boss2_frames_attack_pre_mg [] = 267 { 268 ai_charge, 1, NULL, 269 ai_charge, 1, NULL, 270 ai_charge, 1, NULL, 271 ai_charge, 1, NULL, 272 ai_charge, 1, NULL, 273 ai_charge, 1, NULL, 274 ai_charge, 1, NULL, 275 ai_charge, 1, NULL, 276 ai_charge, 1, boss2_attack_mg 277 }; 278 mmove_t boss2_move_attack_pre_mg = {FRAME_attack1, FRAME_attack9, boss2_frames_attack_pre_mg, NULL}; 279 280 281 // Loop this 282 mframe_t boss2_frames_attack_mg [] = 283 { 284 ai_charge, 1, Boss2MachineGun, 285 ai_charge, 1, Boss2MachineGun, 286 ai_charge, 1, Boss2MachineGun, 287 ai_charge, 1, Boss2MachineGun, 288 ai_charge, 1, Boss2MachineGun, 289 ai_charge, 1, boss2_reattack_mg 290 }; 291 mmove_t boss2_move_attack_mg = {FRAME_attack10, FRAME_attack15, boss2_frames_attack_mg, NULL}; 292 293 mframe_t boss2_frames_attack_post_mg [] = 294 { 295 ai_charge, 1, NULL, 296 ai_charge, 1, NULL, 297 ai_charge, 1, NULL, 298 ai_charge, 1, NULL 299 }; 300 mmove_t boss2_move_attack_post_mg = {FRAME_attack16, FRAME_attack19, boss2_frames_attack_post_mg, boss2_run}; 301 302 mframe_t boss2_frames_attack_rocket [] = 303 { 304 ai_charge, 1, NULL, 305 ai_charge, 1, NULL, 306 ai_charge, 1, NULL, 307 ai_charge, 1, NULL, 308 ai_charge, 1, NULL, 309 ai_charge, 1, NULL, 310 ai_charge, 1, NULL, 311 ai_charge, 1, NULL, 312 ai_charge, 1, NULL, 313 ai_charge, 1, NULL, 314 ai_charge, 1, NULL, 315 ai_charge, 1, NULL, 316 ai_move, -20, Boss2Rocket, 317 ai_charge, 1, NULL, 318 ai_charge, 1, NULL, 319 ai_charge, 1, NULL, 320 ai_charge, 1, NULL, 321 ai_charge, 1, NULL, 322 ai_charge, 1, NULL, 323 ai_charge, 1, NULL, 324 ai_charge, 1, NULL 325 }; 326 mmove_t boss2_move_attack_rocket = {FRAME_attack20, FRAME_attack40, boss2_frames_attack_rocket, boss2_run}; 327 328 mframe_t boss2_frames_pain_heavy [] = 329 { 330 ai_move, 0, NULL, 331 ai_move, 0, NULL, 332 ai_move, 0, NULL, 333 ai_move, 0, NULL, 334 ai_move, 0, NULL, 335 ai_move, 0, NULL, 336 ai_move, 0, NULL, 337 ai_move, 0, NULL, 338 ai_move, 0, NULL, 339 ai_move, 0, NULL, 340 ai_move, 0, NULL, 341 ai_move, 0, NULL, 342 ai_move, 0, NULL, 343 ai_move, 0, NULL, 344 ai_move, 0, NULL, 345 ai_move, 0, NULL, 346 ai_move, 0, NULL, 347 ai_move, 0, NULL 348 }; 349 mmove_t boss2_move_pain_heavy = {FRAME_pain2, FRAME_pain19, boss2_frames_pain_heavy, boss2_run}; 350 351 mframe_t boss2_frames_pain_light [] = 352 { 353 ai_move, 0, NULL, 354 ai_move, 0, NULL, 355 ai_move, 0, NULL, 356 ai_move, 0, NULL 357 }; 358 mmove_t boss2_move_pain_light = {FRAME_pain20, FRAME_pain23, boss2_frames_pain_light, boss2_run}; 359 360 mframe_t boss2_frames_death [] = 361 { 362 ai_move, 0, NULL, 363 ai_move, 0, NULL, 364 ai_move, 0, NULL, 365 ai_move, 0, NULL, 366 ai_move, 0, NULL, 367 ai_move, 0, NULL, 368 ai_move, 0, NULL, 369 ai_move, 0, NULL, 370 ai_move, 0, NULL, 371 ai_move, 0, NULL, 372 ai_move, 0, NULL, 373 ai_move, 0, NULL, 374 ai_move, 0, NULL, 375 ai_move, 0, NULL, 376 ai_move, 0, NULL, 377 ai_move, 0, NULL, 378 ai_move, 0, NULL, 379 ai_move, 0, NULL, 380 ai_move, 0, NULL, 381 ai_move, 0, NULL, 382 ai_move, 0, NULL, 383 ai_move, 0, NULL, 384 ai_move, 0, NULL, 385 ai_move, 0, NULL, 386 ai_move, 0, NULL, 387 ai_move, 0, NULL, 388 ai_move, 0, NULL, 389 ai_move, 0, NULL, 390 ai_move, 0, NULL, 391 ai_move, 0, NULL, 392 ai_move, 0, NULL, 393 ai_move, 0, NULL, 394 ai_move, 0, NULL, 395 ai_move, 0, NULL, 396 ai_move, 0, NULL, 397 ai_move, 0, NULL, 398 ai_move, 0, NULL, 399 ai_move, 0, NULL, 400 ai_move, 0, NULL, 401 ai_move, 0, NULL, 402 ai_move, 0, NULL, 403 ai_move, 0, NULL, 404 ai_move, 0, NULL, 405 ai_move, 0, NULL, 406 ai_move, 0, NULL, 407 ai_move, 0, NULL, 408 ai_move, 0, NULL, 409 ai_move, 0, NULL, 410 ai_move, 0, BossExplode 411 }; 412 mmove_t boss2_move_death = {FRAME_death2, FRAME_death50, boss2_frames_death, boss2_dead}; 413 414 void boss2_stand (edict_t *self) 415 { 416 self->monsterinfo.currentmove = &boss2_move_stand; 417 } 418 419 void boss2_run (edict_t *self) 420 { 421 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 422 self->monsterinfo.currentmove = &boss2_move_stand; 423 else 424 self->monsterinfo.currentmove = &boss2_move_run; 425 } 426 427 void boss2_walk (edict_t *self) 428 { 429 self->monsterinfo.currentmove = &boss2_move_walk; 430 } 431 432 void boss2_attack (edict_t *self) 433 { 434 vec3_t vec; 435 float range; 436 437 VectorSubtract (self->enemy->s.origin, self->s.origin, vec); 438 range = VectorLength (vec); 439 440 if (range <= 125) 441 { 442 self->monsterinfo.currentmove = &boss2_move_attack_pre_mg; 443 } 444 else 445 { 446 if (random() <= 0.6) 447 self->monsterinfo.currentmove = &boss2_move_attack_pre_mg; 448 else 449 self->monsterinfo.currentmove = &boss2_move_attack_rocket; 450 } 451 } 452 453 void boss2_attack_mg (edict_t *self) 454 { 455 self->monsterinfo.currentmove = &boss2_move_attack_mg; 456 } 457 458 void boss2_reattack_mg (edict_t *self) 459 { 460 if ( infront(self, self->enemy) ) 461 if (random() <= 0.7) 462 self->monsterinfo.currentmove = &boss2_move_attack_mg; 463 else 464 self->monsterinfo.currentmove = &boss2_move_attack_post_mg; 465 else 466 self->monsterinfo.currentmove = &boss2_move_attack_post_mg; 467 } 468 469 470 void boss2_pain (edict_t *self, edict_t *other, float kick, int damage) 471 { 472 if (self->health < (self->max_health / 2)) 473 self->s.skinnum = 1; 474 475 if (level.time < self->pain_debounce_time) 476 return; 477 478 self->pain_debounce_time = level.time + 3; 479 // American wanted these at no attenuation 480 if (damage < 10) 481 { 482 gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0); 483 self->monsterinfo.currentmove = &boss2_move_pain_light; 484 } 485 else if (damage < 30) 486 { 487 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0); 488 self->monsterinfo.currentmove = &boss2_move_pain_light; 489 } 490 else 491 { 492 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0); 493 self->monsterinfo.currentmove = &boss2_move_pain_heavy; 494 } 495 } 496 497 void boss2_dead (edict_t *self) 498 { 499 VectorSet (self->mins, -56, -56, 0); 500 VectorSet (self->maxs, 56, 56, 80); 501 self->movetype = MOVETYPE_TOSS; 502 self->svflags |= SVF_DEADMONSTER; 503 self->nextthink = 0; 504 gi.linkentity (self); 505 } 506 507 void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 508 { 509 gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0); 510 self->deadflag = DEAD_DEAD; 511 self->takedamage = DAMAGE_NO; 512 self->count = 0; 513 self->monsterinfo.currentmove = &boss2_move_death; 514 #if 0 515 int n; 516 517 self->s.sound = 0; 518 // check for gib 519 if (self->health <= self->gib_health) 520 { 521 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 522 for (n= 0; n < 2; n++) 523 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 524 for (n= 0; n < 4; n++) 525 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 526 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 527 self->deadflag = DEAD_DEAD; 528 return; 529 } 530 531 if (self->deadflag == DEAD_DEAD) 532 return; 533 534 self->deadflag = DEAD_DEAD; 535 self->takedamage = DAMAGE_YES; 536 self->monsterinfo.currentmove = &boss2_move_death; 537 #endif 538 } 539 540 qboolean Boss2_CheckAttack (edict_t *self) 541 { 542 vec3_t spot1, spot2; 543 vec3_t temp; 544 float chance; 545 trace_t tr; 546 qboolean enemy_infront; 547 int enemy_range; 548 float enemy_yaw; 549 550 if (self->enemy->health > 0) 551 { 552 // see if any entities are in the way of the shot 553 VectorCopy (self->s.origin, spot1); 554 spot1[2] += self->viewheight; 555 VectorCopy (self->enemy->s.origin, spot2); 556 spot2[2] += self->enemy->viewheight; 557 558 tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA); 559 560 // do we have a clear shot? 561 if (tr.ent != self->enemy) 562 return false; 563 } 564 565 enemy_infront = infront(self, self->enemy); 566 enemy_range = range(self, self->enemy); 567 VectorSubtract (self->enemy->s.origin, self->s.origin, temp); 568 enemy_yaw = vectoyaw(temp); 569 570 self->ideal_yaw = enemy_yaw; 571 572 573 // melee attack 574 if (enemy_range == RANGE_MELEE) 575 { 576 if (self->monsterinfo.melee) 577 self->monsterinfo.attack_state = AS_MELEE; 578 else 579 self->monsterinfo.attack_state = AS_MISSILE; 580 return true; 581 } 582 583 // missile attack 584 if (!self->monsterinfo.attack) 585 return false; 586 587 if (level.time < self->monsterinfo.attack_finished) 588 return false; 589 590 if (enemy_range == RANGE_FAR) 591 return false; 592 593 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 594 { 595 chance = 0.4; 596 } 597 else if (enemy_range == RANGE_MELEE) 598 { 599 chance = 0.8; 600 } 601 else if (enemy_range == RANGE_NEAR) 602 { 603 chance = 0.8; 604 } 605 else if (enemy_range == RANGE_MID) 606 { 607 chance = 0.8; 608 } 609 else 610 { 611 return false; 612 } 613 614 if (random () < chance) 615 { 616 self->monsterinfo.attack_state = AS_MISSILE; 617 self->monsterinfo.attack_finished = level.time + 2*random(); 618 return true; 619 } 620 621 if (self->flags & FL_FLY) 622 { 623 if (random() < 0.3) 624 self->monsterinfo.attack_state = AS_SLIDING; 625 else 626 self->monsterinfo.attack_state = AS_STRAIGHT; 627 } 628 629 return false; 630 } 631 632 633 634 /*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight 635 */ 636 void SP_monster_boss2 (edict_t *self) 637 { 638 if (deathmatch->value) 639 { 640 G_FreeEdict (self); 641 return; 642 } 643 644 sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav"); 645 sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav"); 646 sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav"); 647 sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav"); 648 sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav"); 649 650 self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav"); 651 652 self->movetype = MOVETYPE_STEP; 653 self->solid = SOLID_BBOX; 654 self->s.modelindex = gi.modelindex ("models/monsters/boss2/tris.md2"); 655 VectorSet (self->mins, -56, -56, 0); 656 VectorSet (self->maxs, 56, 56, 80); 657 658 self->health = 2000; 659 self->gib_health = -200; 660 self->mass = 1000; 661 662 self->flags |= FL_IMMUNE_LASER; 663 664 self->pain = boss2_pain; 665 self->die = boss2_die; 666 667 self->monsterinfo.stand = boss2_stand; 668 self->monsterinfo.walk = boss2_walk; 669 self->monsterinfo.run = boss2_run; 670 self->monsterinfo.attack = boss2_attack; 671 self->monsterinfo.search = boss2_search; 672 self->monsterinfo.checkattack = Boss2_CheckAttack; 673 gi.linkentity (self); 674 675 self->monsterinfo.currentmove = &boss2_move_stand; 676 self->monsterinfo.scale = MODEL_SCALE; 677 678 flymonster_start (self); 679 }