m_gunner.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. /*
  16. ==============================================================================
  17. GUNNER
  18. ==============================================================================
  19. */
  20. #include "g_local.h"
  21. #include "m_gunner.h"
  22. static int sound_pain;
  23. static int sound_pain2;
  24. static int sound_death;
  25. static int sound_idle;
  26. static int sound_open;
  27. static int sound_search;
  28. static int sound_sight;
  29. void gunner_idlesound (edict_t *self)
  30. {
  31. gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
  32. }
  33. void gunner_sight (edict_t *self, edict_t *other)
  34. {
  35. gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  36. }
  37. void gunner_search (edict_t *self)
  38. {
  39. gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
  40. }
  41. qboolean visible (edict_t *self, edict_t *other);
  42. void GunnerGrenade (edict_t *self);
  43. void GunnerFire (edict_t *self);
  44. void gunner_fire_chain(edict_t *self);
  45. void gunner_refire_chain(edict_t *self);
  46. void gunner_stand (edict_t *self);
  47. mframe_t gunner_frames_fidget [] =
  48. {
  49. ai_stand, 0, NULL,
  50. ai_stand, 0, NULL,
  51. ai_stand, 0, NULL,
  52. ai_stand, 0, NULL,
  53. ai_stand, 0, NULL,
  54. ai_stand, 0, NULL,
  55. ai_stand, 0, NULL,
  56. ai_stand, 0, gunner_idlesound,
  57. ai_stand, 0, NULL,
  58. ai_stand, 0, NULL,
  59. ai_stand, 0, NULL,
  60. ai_stand, 0, NULL,
  61. ai_stand, 0, NULL,
  62. ai_stand, 0, NULL,
  63. ai_stand, 0, NULL,
  64. ai_stand, 0, NULL,
  65. ai_stand, 0, NULL,
  66. ai_stand, 0, NULL,
  67. ai_stand, 0, NULL,
  68. ai_stand, 0, NULL,
  69. ai_stand, 0, NULL,
  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. };
  99. mmove_t gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand};
  100. void gunner_fidget (edict_t *self)
  101. {
  102. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  103. return;
  104. if (random() <= 0.05)
  105. self->monsterinfo.currentmove = &gunner_move_fidget;
  106. }
  107. mframe_t gunner_frames_stand [] =
  108. {
  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. ai_stand, 0, NULL,
  116. ai_stand, 0, NULL,
  117. ai_stand, 0, NULL,
  118. ai_stand, 0, gunner_fidget,
  119. ai_stand, 0, NULL,
  120. ai_stand, 0, NULL,
  121. ai_stand, 0, NULL,
  122. ai_stand, 0, NULL,
  123. ai_stand, 0, NULL,
  124. ai_stand, 0, NULL,
  125. ai_stand, 0, NULL,
  126. ai_stand, 0, NULL,
  127. ai_stand, 0, NULL,
  128. ai_stand, 0, gunner_fidget,
  129. ai_stand, 0, NULL,
  130. ai_stand, 0, NULL,
  131. ai_stand, 0, NULL,
  132. ai_stand, 0, NULL,
  133. ai_stand, 0, NULL,
  134. ai_stand, 0, NULL,
  135. ai_stand, 0, NULL,
  136. ai_stand, 0, NULL,
  137. ai_stand, 0, NULL,
  138. ai_stand, 0, gunner_fidget
  139. };
  140. mmove_t gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL};
  141. void gunner_stand (edict_t *self)
  142. {
  143. self->monsterinfo.currentmove = &gunner_move_stand;
  144. }
  145. mframe_t gunner_frames_walk [] =
  146. {
  147. ai_walk, 0, NULL,
  148. ai_walk, 3, NULL,
  149. ai_walk, 4, NULL,
  150. ai_walk, 5, NULL,
  151. ai_walk, 7, NULL,
  152. ai_walk, 2, NULL,
  153. ai_walk, 6, NULL,
  154. ai_walk, 4, NULL,
  155. ai_walk, 2, NULL,
  156. ai_walk, 7, NULL,
  157. ai_walk, 5, NULL,
  158. ai_walk, 7, NULL,
  159. ai_walk, 4, NULL
  160. };
  161. mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL};
  162. void gunner_walk (edict_t *self)
  163. {
  164. self->monsterinfo.currentmove = &gunner_move_walk;
  165. }
  166. mframe_t gunner_frames_run [] =
  167. {
  168. ai_run, 26, NULL,
  169. ai_run, 9, NULL,
  170. ai_run, 9, NULL,
  171. ai_run, 9, NULL,
  172. ai_run, 15, NULL,
  173. ai_run, 10, NULL,
  174. ai_run, 13, NULL,
  175. ai_run, 6, NULL
  176. };
  177. mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL};
  178. void gunner_run (edict_t *self)
  179. {
  180. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  181. self->monsterinfo.currentmove = &gunner_move_stand;
  182. else
  183. self->monsterinfo.currentmove = &gunner_move_run;
  184. }
  185. mframe_t gunner_frames_runandshoot [] =
  186. {
  187. ai_run, 32, NULL,
  188. ai_run, 15, NULL,
  189. ai_run, 10, NULL,
  190. ai_run, 18, NULL,
  191. ai_run, 8, NULL,
  192. ai_run, 20, NULL
  193. };
  194. mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL};
  195. void gunner_runandshoot (edict_t *self)
  196. {
  197. self->monsterinfo.currentmove = &gunner_move_runandshoot;
  198. }
  199. mframe_t gunner_frames_pain3 [] =
  200. {
  201. ai_move, -3, NULL,
  202. ai_move, 1, NULL,
  203. ai_move, 1, NULL,
  204. ai_move, 0, NULL,
  205. ai_move, 1, NULL
  206. };
  207. mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run};
  208. mframe_t gunner_frames_pain2 [] =
  209. {
  210. ai_move, -2, NULL,
  211. ai_move, 11, NULL,
  212. ai_move, 6, NULL,
  213. ai_move, 2, NULL,
  214. ai_move, -1, NULL,
  215. ai_move, -7, NULL,
  216. ai_move, -2, NULL,
  217. ai_move, -7, NULL
  218. };
  219. mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run};
  220. mframe_t gunner_frames_pain1 [] =
  221. {
  222. ai_move, 2, NULL,
  223. ai_move, 0, NULL,
  224. ai_move, -5, NULL,
  225. ai_move, 3, NULL,
  226. ai_move, -1, NULL,
  227. ai_move, 0, NULL,
  228. ai_move, 0, NULL,
  229. ai_move, 0, NULL,
  230. ai_move, 0, NULL,
  231. ai_move, 1, NULL,
  232. ai_move, 1, NULL,
  233. ai_move, 2, NULL,
  234. ai_move, 1, NULL,
  235. ai_move, 0, NULL,
  236. ai_move, -2, NULL,
  237. ai_move, -2, NULL,
  238. ai_move, 0, NULL,
  239. ai_move, 0, NULL
  240. };
  241. mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run};
  242. void gunner_pain (edict_t *self, edict_t *other, float kick, int damage)
  243. {
  244. if (self->health < (self->max_health / 2))
  245. self->s.skinnum = 1;
  246. if (level.time < self->pain_debounce_time)
  247. return;
  248. self->pain_debounce_time = level.time + 3;
  249. if (rand()&1)
  250. gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
  251. else
  252. gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  253. if (skill->value == 3)
  254. return; // no pain anims in nightmare
  255. if (damage <= 10)
  256. self->monsterinfo.currentmove = &gunner_move_pain3;
  257. else if (damage <= 25)
  258. self->monsterinfo.currentmove = &gunner_move_pain2;
  259. else
  260. self->monsterinfo.currentmove = &gunner_move_pain1;
  261. }
  262. void gunner_dead (edict_t *self)
  263. {
  264. VectorSet (self->mins, -16, -16, -24);
  265. VectorSet (self->maxs, 16, 16, -8);
  266. self->movetype = MOVETYPE_TOSS;
  267. self->svflags |= SVF_DEADMONSTER;
  268. self->nextthink = 0;
  269. gi.linkentity (self);
  270. }
  271. mframe_t gunner_frames_death [] =
  272. {
  273. ai_move, 0, NULL,
  274. ai_move, 0, NULL,
  275. ai_move, 0, NULL,
  276. ai_move, -7, NULL,
  277. ai_move, -3, NULL,
  278. ai_move, -5, NULL,
  279. ai_move, 8, NULL,
  280. ai_move, 6, NULL,
  281. ai_move, 0, NULL,
  282. ai_move, 0, NULL,
  283. ai_move, 0, NULL
  284. };
  285. mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead};
  286. void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  287. {
  288. int n;
  289. // check for gib
  290. if (self->health <= self->gib_health)
  291. {
  292. gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  293. for (n= 0; n < 2; n++)
  294. ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  295. for (n= 0; n < 4; n++)
  296. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  297. ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  298. self->deadflag = DEAD_DEAD;
  299. return;
  300. }
  301. if (self->deadflag == DEAD_DEAD)
  302. return;
  303. // regular death
  304. gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
  305. self->deadflag = DEAD_DEAD;
  306. self->takedamage = DAMAGE_YES;
  307. self->monsterinfo.currentmove = &gunner_move_death;
  308. }
  309. void gunner_duck_down (edict_t *self)
  310. {
  311. if (self->monsterinfo.aiflags & AI_DUCKED)
  312. return;
  313. self->monsterinfo.aiflags |= AI_DUCKED;
  314. if (skill->value >= 2)
  315. {
  316. if (random() > 0.5)
  317. GunnerGrenade (self);
  318. }
  319. self->maxs[2] -= 32;
  320. self->takedamage = DAMAGE_YES;
  321. self->monsterinfo.pausetime = level.time + 1;
  322. gi.linkentity (self);
  323. }
  324. void gunner_duck_hold (edict_t *self)
  325. {
  326. if (level.time >= self->monsterinfo.pausetime)
  327. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  328. else
  329. self->monsterinfo.aiflags |= AI_HOLD_FRAME;
  330. }
  331. void gunner_duck_up (edict_t *self)
  332. {
  333. self->monsterinfo.aiflags &= ~AI_DUCKED;
  334. self->maxs[2] += 32;
  335. self->takedamage = DAMAGE_AIM;
  336. gi.linkentity (self);
  337. }
  338. mframe_t gunner_frames_duck [] =
  339. {
  340. ai_move, 1, gunner_duck_down,
  341. ai_move, 1, NULL,
  342. ai_move, 1, gunner_duck_hold,
  343. ai_move, 0, NULL,
  344. ai_move, -1, NULL,
  345. ai_move, -1, NULL,
  346. ai_move, 0, gunner_duck_up,
  347. ai_move, -1, NULL
  348. };
  349. mmove_t gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run};
  350. void gunner_dodge (edict_t *self, edict_t *attacker, float eta)
  351. {
  352. if (random() > 0.25)
  353. return;
  354. if (!self->enemy)
  355. self->enemy = attacker;
  356. self->monsterinfo.currentmove = &gunner_move_duck;
  357. }
  358. void gunner_opengun (edict_t *self)
  359. {
  360. gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
  361. }
  362. void GunnerFire (edict_t *self)
  363. {
  364. vec3_t start;
  365. vec3_t forward, right;
  366. vec3_t target;
  367. vec3_t aim;
  368. int flash_number;
  369. flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
  370. AngleVectors (self->s.angles, forward, right, NULL);
  371. G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  372. // project enemy back a bit and target there
  373. VectorCopy (self->enemy->s.origin, target);
  374. VectorMA (target, -0.2, self->enemy->velocity, target);
  375. target[2] += self->enemy->viewheight;
  376. VectorSubtract (target, start, aim);
  377. VectorNormalize (aim);
  378. monster_fire_bullet (self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
  379. }
  380. void GunnerGrenade (edict_t *self)
  381. {
  382. vec3_t start;
  383. vec3_t forward, right;
  384. vec3_t aim;
  385. int flash_number;
  386. if (self->s.frame == FRAME_attak105)
  387. flash_number = MZ2_GUNNER_GRENADE_1;
  388. else if (self->s.frame == FRAME_attak108)
  389. flash_number = MZ2_GUNNER_GRENADE_2;
  390. else if (self->s.frame == FRAME_attak111)
  391. flash_number = MZ2_GUNNER_GRENADE_3;
  392. else // (self->s.frame == FRAME_attak114)
  393. flash_number = MZ2_GUNNER_GRENADE_4;
  394. AngleVectors (self->s.angles, forward, right, NULL);
  395. G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  396. //FIXME : do a spread -225 -75 75 225 degrees around forward
  397. VectorCopy (forward, aim);
  398. monster_fire_grenade (self, start, aim, 50, 600, flash_number);
  399. }
  400. mframe_t gunner_frames_attack_chain [] =
  401. {
  402. /*
  403. ai_charge, 0, NULL,
  404. ai_charge, 0, NULL,
  405. ai_charge, 0, NULL,
  406. ai_charge, 0, NULL,
  407. ai_charge, 0, NULL,
  408. ai_charge, 0, NULL,
  409. ai_charge, 0, NULL,
  410. ai_charge, 0, NULL,
  411. */
  412. ai_charge, 0, gunner_opengun,
  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 gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain};
  421. mframe_t gunner_frames_fire_chain [] =
  422. {
  423. ai_charge, 0, GunnerFire,
  424. ai_charge, 0, GunnerFire,
  425. ai_charge, 0, GunnerFire,
  426. ai_charge, 0, GunnerFire,
  427. ai_charge, 0, GunnerFire,
  428. ai_charge, 0, GunnerFire,
  429. ai_charge, 0, GunnerFire,
  430. ai_charge, 0, GunnerFire
  431. };
  432. mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain};
  433. mframe_t gunner_frames_endfire_chain [] =
  434. {
  435. ai_charge, 0, NULL,
  436. ai_charge, 0, NULL,
  437. ai_charge, 0, NULL,
  438. ai_charge, 0, NULL,
  439. ai_charge, 0, NULL,
  440. ai_charge, 0, NULL,
  441. ai_charge, 0, NULL
  442. };
  443. mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run};
  444. mframe_t gunner_frames_attack_grenade [] =
  445. {
  446. ai_charge, 0, NULL,
  447. ai_charge, 0, NULL,
  448. ai_charge, 0, NULL,
  449. ai_charge, 0, NULL,
  450. ai_charge, 0, GunnerGrenade,
  451. ai_charge, 0, NULL,
  452. ai_charge, 0, NULL,
  453. ai_charge, 0, GunnerGrenade,
  454. ai_charge, 0, NULL,
  455. ai_charge, 0, NULL,
  456. ai_charge, 0, GunnerGrenade,
  457. ai_charge, 0, NULL,
  458. ai_charge, 0, NULL,
  459. ai_charge, 0, GunnerGrenade,
  460. ai_charge, 0, NULL,
  461. ai_charge, 0, NULL,
  462. ai_charge, 0, NULL,
  463. ai_charge, 0, NULL,
  464. ai_charge, 0, NULL,
  465. ai_charge, 0, NULL,
  466. ai_charge, 0, NULL
  467. };
  468. mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run};
  469. void gunner_attack(edict_t *self)
  470. {
  471. if (range (self, self->enemy) == RANGE_MELEE)
  472. {
  473. self->monsterinfo.currentmove = &gunner_move_attack_chain;
  474. }
  475. else
  476. {
  477. if (random() <= 0.5)
  478. self->monsterinfo.currentmove = &gunner_move_attack_grenade;
  479. else
  480. self->monsterinfo.currentmove = &gunner_move_attack_chain;
  481. }
  482. }
  483. void gunner_fire_chain(edict_t *self)
  484. {
  485. self->monsterinfo.currentmove = &gunner_move_fire_chain;
  486. }
  487. void gunner_refire_chain(edict_t *self)
  488. {
  489. if (self->enemy->health > 0)
  490. if ( visible (self, self->enemy) )
  491. if (random() <= 0.5)
  492. {
  493. self->monsterinfo.currentmove = &gunner_move_fire_chain;
  494. return;
  495. }
  496. self->monsterinfo.currentmove = &gunner_move_endfire_chain;
  497. }
  498. /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  499. */
  500. void SP_monster_gunner (edict_t *self)
  501. {
  502. if (deathmatch->value)
  503. {
  504. G_FreeEdict (self);
  505. return;
  506. }
  507. sound_death = gi.soundindex ("gunner/death1.wav");
  508. sound_pain = gi.soundindex ("gunner/gunpain2.wav");
  509. sound_pain2 = gi.soundindex ("gunner/gunpain1.wav");
  510. sound_idle = gi.soundindex ("gunner/gunidle1.wav");
  511. sound_open = gi.soundindex ("gunner/gunatck1.wav");
  512. sound_search = gi.soundindex ("gunner/gunsrch1.wav");
  513. sound_sight = gi.soundindex ("gunner/sight1.wav");
  514. gi.soundindex ("gunner/gunatck2.wav");
  515. gi.soundindex ("gunner/gunatck3.wav");
  516. self->movetype = MOVETYPE_STEP;
  517. self->solid = SOLID_BBOX;
  518. self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2");
  519. VectorSet (self->mins, -16, -16, -24);
  520. VectorSet (self->maxs, 16, 16, 32);
  521. self->health = 175;
  522. self->gib_health = -70;
  523. self->mass = 200;
  524. self->pain = gunner_pain;
  525. self->die = gunner_die;
  526. self->monsterinfo.stand = gunner_stand;
  527. self->monsterinfo.walk = gunner_walk;
  528. self->monsterinfo.run = gunner_run;
  529. self->monsterinfo.dodge = gunner_dodge;
  530. self->monsterinfo.attack = gunner_attack;
  531. self->monsterinfo.melee = NULL;
  532. self->monsterinfo.sight = gunner_sight;
  533. self->monsterinfo.search = gunner_search;
  534. gi.linkentity (self);
  535. self->monsterinfo.currentmove = &gunner_move_stand;
  536. self->monsterinfo.scale = MODEL_SCALE;
  537. walkmonster_start (self);
  538. }