P_ENEMY.C 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637
  1. // P_enemy.c
  2. #include "DoomDef.h"
  3. #include "P_local.h"
  4. #include "soundst.h"
  5. // Macros
  6. #define MAX_BOSS_SPOTS 8
  7. // Types
  8. typedef struct
  9. {
  10. fixed_t x;
  11. fixed_t y;
  12. angle_t angle;
  13. } BossSpot_t;
  14. // Private Data
  15. static int BossSpotCount;
  16. static BossSpot_t BossSpots[MAX_BOSS_SPOTS];
  17. //----------------------------------------------------------------------------
  18. //
  19. // PROC P_InitMonsters
  20. //
  21. // Called at level load.
  22. //
  23. //----------------------------------------------------------------------------
  24. void P_InitMonsters(void)
  25. {
  26. BossSpotCount = 0;
  27. }
  28. //----------------------------------------------------------------------------
  29. //
  30. // PROC P_AddBossSpot
  31. //
  32. //----------------------------------------------------------------------------
  33. void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle)
  34. {
  35. if(BossSpotCount == MAX_BOSS_SPOTS)
  36. {
  37. I_Error("Too many boss spots.");
  38. }
  39. BossSpots[BossSpotCount].x = x;
  40. BossSpots[BossSpotCount].y = y;
  41. BossSpots[BossSpotCount].angle = angle;
  42. BossSpotCount++;
  43. }
  44. //----------------------------------------------------------------------------
  45. //
  46. // PROC P_RecursiveSound
  47. //
  48. //----------------------------------------------------------------------------
  49. mobj_t *soundtarget;
  50. void P_RecursiveSound(sector_t *sec, int soundblocks)
  51. {
  52. int i;
  53. line_t *check;
  54. sector_t *other;
  55. // Wake up all monsters in this sector
  56. if(sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
  57. { // Already flooded
  58. return;
  59. }
  60. sec->validcount = validcount;
  61. sec->soundtraversed = soundblocks+1;
  62. sec->soundtarget = soundtarget;
  63. for(i = 0; i < sec->linecount; i++)
  64. {
  65. check = sec->lines[i];
  66. if(!(check->flags&ML_TWOSIDED))
  67. {
  68. continue;
  69. }
  70. P_LineOpening(check);
  71. if(openrange <= 0)
  72. { // Closed door
  73. continue;
  74. }
  75. if(sides[check->sidenum[0]].sector == sec)
  76. {
  77. other = sides[check->sidenum[1]].sector;
  78. }
  79. else
  80. {
  81. other = sides[check->sidenum[0]].sector;
  82. }
  83. if(check->flags&ML_SOUNDBLOCK)
  84. {
  85. if(!soundblocks)
  86. {
  87. P_RecursiveSound(other, 1);
  88. }
  89. }
  90. else
  91. {
  92. P_RecursiveSound(other, soundblocks);
  93. }
  94. }
  95. }
  96. //----------------------------------------------------------------------------
  97. //
  98. // PROC P_NoiseAlert
  99. //
  100. // If a monster yells at a player, it will alert other monsters to the
  101. // player.
  102. //
  103. //----------------------------------------------------------------------------
  104. void P_NoiseAlert(mobj_t *target, mobj_t *emmiter)
  105. {
  106. soundtarget = target;
  107. validcount++;
  108. P_RecursiveSound(emmiter->subsector->sector, 0);
  109. }
  110. //----------------------------------------------------------------------------
  111. //
  112. // FUNC P_CheckMeleeRange
  113. //
  114. //----------------------------------------------------------------------------
  115. boolean P_CheckMeleeRange(mobj_t *actor)
  116. {
  117. mobj_t *mo;
  118. fixed_t dist;
  119. if(!actor->target)
  120. {
  121. return(false);
  122. }
  123. mo = actor->target;
  124. dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y);
  125. if(dist >= MELEERANGE)
  126. {
  127. return(false);
  128. }
  129. if(!P_CheckSight(actor, mo))
  130. {
  131. return(false);
  132. }
  133. if(mo->z > actor->z+actor->height)
  134. { // Target is higher than the attacker
  135. return(false);
  136. }
  137. else if(actor->z > mo->z+mo->height)
  138. { // Attacker is higher
  139. return(false);
  140. }
  141. return(true);
  142. }
  143. //----------------------------------------------------------------------------
  144. //
  145. // FUNC P_CheckMissileRange
  146. //
  147. //----------------------------------------------------------------------------
  148. boolean P_CheckMissileRange(mobj_t *actor)
  149. {
  150. fixed_t dist;
  151. if(!P_CheckSight(actor, actor->target))
  152. {
  153. return(false);
  154. }
  155. if(actor->flags&MF_JUSTHIT)
  156. { // The target just hit the enemy, so fight back!
  157. actor->flags &= ~MF_JUSTHIT;
  158. return(true);
  159. }
  160. if(actor->reactiontime)
  161. { // Don't attack yet
  162. return(false);
  163. }
  164. dist = (P_AproxDistance(actor->x-actor->target->x,
  165. actor->y-actor->target->y)>>FRACBITS)-64;
  166. if(!actor->info->meleestate)
  167. { // No melee attack, so fire more frequently
  168. dist -= 128;
  169. }
  170. if(actor->type == MT_IMP)
  171. { // Imp's fly attack from far away
  172. dist >>= 1;
  173. }
  174. if(dist > 200)
  175. {
  176. dist = 200;
  177. }
  178. if(P_Random() < dist)
  179. {
  180. return(false);
  181. }
  182. return(true);
  183. }
  184. /*
  185. ================
  186. =
  187. = P_Move
  188. =
  189. = Move in the current direction
  190. = returns false if the move is blocked
  191. ================
  192. */
  193. fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
  194. fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
  195. #define MAXSPECIALCROSS 8
  196. extern line_t *spechit[MAXSPECIALCROSS];
  197. extern int numspechit;
  198. boolean P_Move(mobj_t *actor)
  199. {
  200. fixed_t tryx, tryy;
  201. line_t *ld;
  202. boolean good;
  203. if(actor->movedir == DI_NODIR)
  204. {
  205. return(false);
  206. }
  207. tryx = actor->x+actor->info->speed*xspeed[actor->movedir];
  208. tryy = actor->y+actor->info->speed*yspeed[actor->movedir];
  209. if(!P_TryMove(actor, tryx, tryy))
  210. { // open any specials
  211. if(actor->flags&MF_FLOAT && floatok)
  212. { // must adjust height
  213. if(actor->z < tmfloorz)
  214. {
  215. actor->z += FLOATSPEED;
  216. }
  217. else
  218. {
  219. actor->z -= FLOATSPEED;
  220. }
  221. actor->flags |= MF_INFLOAT;
  222. return(true);
  223. }
  224. if(!numspechit)
  225. {
  226. return false;
  227. }
  228. actor->movedir = DI_NODIR;
  229. good = false;
  230. while(numspechit--)
  231. {
  232. ld = spechit[numspechit];
  233. // if the special isn't a door that can be opened, return false
  234. if(P_UseSpecialLine(actor, ld))
  235. {
  236. good = true;
  237. }
  238. }
  239. return(good);
  240. }
  241. else
  242. {
  243. actor->flags &= ~MF_INFLOAT;
  244. }
  245. if(!(actor->flags&MF_FLOAT))
  246. {
  247. if(actor->z > actor->floorz)
  248. {
  249. P_HitFloor(actor);
  250. }
  251. actor->z = actor->floorz;
  252. }
  253. return(true);
  254. }
  255. //----------------------------------------------------------------------------
  256. //
  257. // FUNC P_TryWalk
  258. //
  259. // Attempts to move actor in its current (ob->moveangle) direction.
  260. // If blocked by either a wall or an actor returns FALSE.
  261. // If move is either clear of block only by a door, returns TRUE and sets.
  262. // If a door is in the way, an OpenDoor call is made to start it opening.
  263. //
  264. //----------------------------------------------------------------------------
  265. boolean P_TryWalk(mobj_t *actor)
  266. {
  267. if(!P_Move(actor))
  268. {
  269. return(false);
  270. }
  271. actor->movecount = P_Random()&15;
  272. return(true);
  273. }
  274. /*
  275. ================
  276. =
  277. = P_NewChaseDir
  278. =
  279. ================
  280. */
  281. dirtype_t opposite[] =
  282. {DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
  283. DI_NORTH, DI_NORTHWEST, DI_NODIR};
  284. dirtype_t diags[] = {DI_NORTHWEST,DI_NORTHEAST,DI_SOUTHWEST,DI_SOUTHEAST};
  285. void P_NewChaseDir (mobj_t *actor)
  286. {
  287. fixed_t deltax,deltay;
  288. dirtype_t d[3];
  289. dirtype_t tdir, olddir, turnaround;
  290. if (!actor->target)
  291. I_Error ("P_NewChaseDir: called with no target");
  292. olddir = actor->movedir;
  293. turnaround=opposite[olddir];
  294. deltax = actor->target->x - actor->x;
  295. deltay = actor->target->y - actor->y;
  296. if (deltax>10*FRACUNIT)
  297. d[1]= DI_EAST;
  298. else if (deltax<-10*FRACUNIT)
  299. d[1]= DI_WEST;
  300. else
  301. d[1]=DI_NODIR;
  302. if (deltay<-10*FRACUNIT)
  303. d[2]= DI_SOUTH;
  304. else if (deltay>10*FRACUNIT)
  305. d[2]= DI_NORTH;
  306. else
  307. d[2]=DI_NODIR;
  308. // try direct route
  309. if (d[1] != DI_NODIR && d[2] != DI_NODIR)
  310. {
  311. actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
  312. if (actor->movedir != turnaround && P_TryWalk(actor))
  313. return;
  314. }
  315. // try other directions
  316. if (P_Random() > 200 || abs(deltay)>abs(deltax))
  317. {
  318. tdir=d[1];
  319. d[1]=d[2];
  320. d[2]=tdir;
  321. }
  322. if (d[1]==turnaround)
  323. d[1]=DI_NODIR;
  324. if (d[2]==turnaround)
  325. d[2]=DI_NODIR;
  326. if (d[1]!=DI_NODIR)
  327. {
  328. actor->movedir = d[1];
  329. if (P_TryWalk(actor))
  330. return; /*either moved forward or attacked*/
  331. }
  332. if (d[2]!=DI_NODIR)
  333. {
  334. actor->movedir =d[2];
  335. if (P_TryWalk(actor))
  336. return;
  337. }
  338. /* there is no direct path to the player, so pick another direction */
  339. if (olddir!=DI_NODIR)
  340. {
  341. actor->movedir =olddir;
  342. if (P_TryWalk(actor))
  343. return;
  344. }
  345. if (P_Random()&1) /*randomly determine direction of search*/
  346. {
  347. for (tdir=DI_EAST ; tdir<=DI_SOUTHEAST ; tdir++)
  348. {
  349. if (tdir!=turnaround)
  350. {
  351. actor->movedir =tdir;
  352. if ( P_TryWalk(actor) )
  353. return;
  354. }
  355. }
  356. }
  357. else
  358. {
  359. for (tdir=DI_SOUTHEAST ; tdir >= DI_EAST;tdir--)
  360. {
  361. if (tdir!=turnaround)
  362. {
  363. actor->movedir =tdir;
  364. if ( P_TryWalk(actor) )
  365. return;
  366. }
  367. }
  368. }
  369. if (turnaround != DI_NODIR)
  370. {
  371. actor->movedir =turnaround;
  372. if ( P_TryWalk(actor) )
  373. return;
  374. }
  375. actor->movedir = DI_NODIR; // can't move
  376. }
  377. //---------------------------------------------------------------------------
  378. //
  379. // FUNC P_LookForMonsters
  380. //
  381. //---------------------------------------------------------------------------
  382. #define MONS_LOOK_RANGE (20*64*FRACUNIT)
  383. #define MONS_LOOK_LIMIT 64
  384. boolean P_LookForMonsters(mobj_t *actor)
  385. {
  386. int count;
  387. mobj_t *mo;
  388. thinker_t *think;
  389. if(!P_CheckSight(players[0].mo, actor))
  390. { // Player can't see monster
  391. return(false);
  392. }
  393. count = 0;
  394. for(think = thinkercap.next; think != &thinkercap; think = think->next)
  395. {
  396. if(think->function != P_MobjThinker)
  397. { // Not a mobj thinker
  398. continue;
  399. }
  400. mo = (mobj_t *)think;
  401. if(!(mo->flags&MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
  402. { // Not a valid monster
  403. continue;
  404. }
  405. if(P_AproxDistance(actor->x-mo->x, actor->y-mo->y)
  406. > MONS_LOOK_RANGE)
  407. { // Out of range
  408. continue;
  409. }
  410. if(P_Random() < 16)
  411. { // Skip
  412. continue;
  413. }
  414. if(count++ > MONS_LOOK_LIMIT)
  415. { // Stop searching
  416. return(false);
  417. }
  418. if(!P_CheckSight(actor, mo))
  419. { // Out of sight
  420. continue;
  421. }
  422. // Found a target monster
  423. actor->target = mo;
  424. return(true);
  425. }
  426. return(false);
  427. }
  428. /*
  429. ================
  430. =
  431. = P_LookForPlayers
  432. =
  433. = If allaround is false, only look 180 degrees in front
  434. = returns true if a player is targeted
  435. ================
  436. */
  437. boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
  438. {
  439. int c;
  440. int stop;
  441. player_t *player;
  442. sector_t *sector;
  443. angle_t an;
  444. fixed_t dist;
  445. if(!netgame && players[0].health <= 0)
  446. { // Single player game and player is dead, look for monsters
  447. return(P_LookForMonsters(actor));
  448. }
  449. sector = actor->subsector->sector;
  450. c = 0;
  451. stop = (actor->lastlook-1)&3;
  452. for( ; ; actor->lastlook = (actor->lastlook+1)&3 )
  453. {
  454. if (!playeringame[actor->lastlook])
  455. continue;
  456. if (c++ == 2 || actor->lastlook == stop)
  457. return false; // done looking
  458. player = &players[actor->lastlook];
  459. if (player->health <= 0)
  460. continue; // dead
  461. if (!P_CheckSight (actor, player->mo))
  462. continue; // out of sight
  463. if (!allaround)
  464. {
  465. an = R_PointToAngle2 (actor->x, actor->y,
  466. player->mo->x, player->mo->y) - actor->angle;
  467. if (an > ANG90 && an < ANG270)
  468. {
  469. dist = P_AproxDistance (player->mo->x - actor->x,
  470. player->mo->y - actor->y);
  471. // if real close, react anyway
  472. if (dist > MELEERANGE)
  473. continue; // behind back
  474. }
  475. }
  476. if(player->mo->flags&MF_SHADOW)
  477. { // Player is invisible
  478. if((P_AproxDistance(player->mo->x-actor->x,
  479. player->mo->y-actor->y) > 2*MELEERANGE)
  480. && P_AproxDistance(player->mo->momx, player->mo->momy)
  481. < 5*FRACUNIT)
  482. { // Player is sneaking - can't detect
  483. return(false);
  484. }
  485. if(P_Random() < 225)
  486. { // Player isn't sneaking, but still didn't detect
  487. return(false);
  488. }
  489. }
  490. actor->target = player->mo;
  491. return(true);
  492. }
  493. return(false);
  494. }
  495. /*
  496. ===============================================================================
  497. ACTION ROUTINES
  498. ===============================================================================
  499. */
  500. /*
  501. ==============
  502. =
  503. = A_Look
  504. =
  505. = Stay in state until a player is sighted
  506. =
  507. ==============
  508. */
  509. void A_Look (mobj_t *actor)
  510. {
  511. mobj_t *targ;
  512. actor->threshold = 0; // any shot will wake up
  513. targ = actor->subsector->sector->soundtarget;
  514. if (targ && (targ->flags & MF_SHOOTABLE) )
  515. {
  516. actor->target = targ;
  517. if ( actor->flags & MF_AMBUSH )
  518. {
  519. if (P_CheckSight (actor, actor->target))
  520. goto seeyou;
  521. }
  522. else
  523. goto seeyou;
  524. }
  525. if (!P_LookForPlayers (actor, false) )
  526. return;
  527. // go into chase state
  528. seeyou:
  529. if (actor->info->seesound)
  530. {
  531. int sound;
  532. /*
  533. switch (actor->info->seesound)
  534. {
  535. case sfx_posit1:
  536. case sfx_posit2:
  537. case sfx_posit3:
  538. sound = sfx_posit1+P_Random()%3;
  539. break;
  540. case sfx_bgsit1:
  541. case sfx_bgsit2:
  542. sound = sfx_bgsit1+P_Random()%2;
  543. break;
  544. default:
  545. sound = actor->info->seesound;
  546. break;
  547. }
  548. */
  549. sound = actor->info->seesound;
  550. if(actor->flags2&MF2_BOSS)
  551. { // Full volume
  552. S_StartSound(NULL, sound);
  553. }
  554. else
  555. {
  556. S_StartSound(actor, sound);
  557. }
  558. }
  559. P_SetMobjState(actor, actor->info->seestate);
  560. }
  561. /*
  562. ==============
  563. =
  564. = A_Chase
  565. =
  566. = Actor has a melee attack, so it tries to close as fast as possible
  567. =
  568. ==============
  569. */
  570. void A_Chase(mobj_t *actor)
  571. {
  572. int delta;
  573. if(actor->reactiontime)
  574. {
  575. actor->reactiontime--;
  576. }
  577. // Modify target threshold
  578. if(actor->threshold)
  579. {
  580. actor->threshold--;
  581. }
  582. if(gameskill == sk_nightmare)
  583. { // Monsters move faster in nightmare mode
  584. actor->tics -= actor->tics/2;
  585. if(actor->tics < 3)
  586. {
  587. actor->tics = 3;
  588. }
  589. }
  590. //
  591. // turn towards movement direction if not there yet
  592. //
  593. if(actor->movedir < 8)
  594. {
  595. actor->angle &= (7<<29);
  596. delta = actor->angle-(actor->movedir << 29);
  597. if(delta > 0)
  598. {
  599. actor->angle -= ANG90/2;
  600. }
  601. else if(delta < 0)
  602. {
  603. actor->angle += ANG90/2;
  604. }
  605. }
  606. if(!actor->target || !(actor->target->flags&MF_SHOOTABLE))
  607. { // look for a new target
  608. if(P_LookForPlayers(actor, true))
  609. { // got a new target
  610. return;
  611. }
  612. P_SetMobjState(actor, actor->info->spawnstate);
  613. return;
  614. }
  615. //
  616. // don't attack twice in a row
  617. //
  618. if(actor->flags & MF_JUSTATTACKED)
  619. {
  620. actor->flags &= ~MF_JUSTATTACKED;
  621. if (gameskill != sk_nightmare)
  622. P_NewChaseDir (actor);
  623. return;
  624. }
  625. //
  626. // check for melee attack
  627. //
  628. if (actor->info->meleestate && P_CheckMeleeRange (actor))
  629. {
  630. if (actor->info->attacksound)
  631. S_StartSound (actor, actor->info->attacksound);
  632. P_SetMobjState (actor, actor->info->meleestate);
  633. return;
  634. }
  635. //
  636. // check for missile attack
  637. //
  638. if (actor->info->missilestate)
  639. {
  640. if (gameskill < sk_nightmare && actor->movecount)
  641. goto nomissile;
  642. if (!P_CheckMissileRange (actor))
  643. goto nomissile;
  644. P_SetMobjState (actor, actor->info->missilestate);
  645. actor->flags |= MF_JUSTATTACKED;
  646. return;
  647. }
  648. nomissile:
  649. //
  650. // possibly choose another target
  651. //
  652. if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
  653. {
  654. if (P_LookForPlayers(actor,true))
  655. return; // got a new target
  656. }
  657. //
  658. // chase towards player
  659. //
  660. if (--actor->movecount<0 || !P_Move (actor))
  661. {
  662. P_NewChaseDir (actor);
  663. }
  664. //
  665. // make active sound
  666. //
  667. if(actor->info->activesound && P_Random() < 3)
  668. {
  669. if(actor->type == MT_WIZARD && P_Random() < 128)
  670. {
  671. S_StartSound(actor, actor->info->seesound);
  672. }
  673. else if(actor->type == MT_SORCERER2)
  674. {
  675. S_StartSound(NULL, actor->info->activesound);
  676. }
  677. else
  678. {
  679. S_StartSound(actor, actor->info->activesound);
  680. }
  681. }
  682. }
  683. //----------------------------------------------------------------------------
  684. //
  685. // PROC A_FaceTarget
  686. //
  687. //----------------------------------------------------------------------------
  688. void A_FaceTarget(mobj_t *actor)
  689. {
  690. if(!actor->target)
  691. {
  692. return;
  693. }
  694. actor->flags &= ~MF_AMBUSH;
  695. actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
  696. actor->target->y);
  697. if(actor->target->flags&MF_SHADOW)
  698. { // Target is a ghost
  699. actor->angle += (P_Random()-P_Random())<<21;
  700. }
  701. }
  702. //----------------------------------------------------------------------------
  703. //
  704. // PROC A_Pain
  705. //
  706. //----------------------------------------------------------------------------
  707. void A_Pain(mobj_t *actor)
  708. {
  709. if(actor->info->painsound)
  710. {
  711. S_StartSound(actor, actor->info->painsound);
  712. }
  713. }
  714. //----------------------------------------------------------------------------
  715. //
  716. // PROC A_DripBlood
  717. //
  718. //----------------------------------------------------------------------------
  719. void A_DripBlood(mobj_t *actor)
  720. {
  721. mobj_t *mo;
  722. mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
  723. actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
  724. mo->momx = (P_Random()-P_Random())<<10;
  725. mo->momy = (P_Random()-P_Random())<<10;
  726. mo->flags2 |= MF2_LOGRAV;
  727. }
  728. //----------------------------------------------------------------------------
  729. //
  730. // PROC A_KnightAttack
  731. //
  732. //----------------------------------------------------------------------------
  733. void A_KnightAttack(mobj_t *actor)
  734. {
  735. if(!actor->target)
  736. {
  737. return;
  738. }
  739. if(P_CheckMeleeRange(actor))
  740. {
  741. P_DamageMobj(actor->target, actor, actor, HITDICE(3));
  742. S_StartSound(actor, sfx_kgtat2);
  743. return;
  744. }
  745. // Throw axe
  746. S_StartSound(actor, actor->info->attacksound);
  747. if(actor->type == MT_KNIGHTGHOST || P_Random() < 40)
  748. { // Red axe
  749. P_SpawnMissile(actor, actor->target, MT_REDAXE);
  750. return;
  751. }
  752. // Green axe
  753. P_SpawnMissile(actor, actor->target, MT_KNIGHTAXE);
  754. }
  755. //----------------------------------------------------------------------------
  756. //
  757. // PROC A_ImpExplode
  758. //
  759. //----------------------------------------------------------------------------
  760. void A_ImpExplode(mobj_t *actor)
  761. {
  762. mobj_t *mo;
  763. mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK1);
  764. mo->momx = (P_Random() - P_Random ())<<10;
  765. mo->momy = (P_Random() - P_Random ())<<10;
  766. mo->momz = 9*FRACUNIT;
  767. mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK2);
  768. mo->momx = (P_Random() - P_Random ())<<10;
  769. mo->momy = (P_Random() - P_Random ())<<10;
  770. mo->momz = 9*FRACUNIT;
  771. if(actor->special1 == 666)
  772. { // Extreme death crash
  773. P_SetMobjState(actor, S_IMP_XCRASH1);
  774. }
  775. }
  776. //----------------------------------------------------------------------------
  777. //
  778. // PROC A_BeastPuff
  779. //
  780. //----------------------------------------------------------------------------
  781. void A_BeastPuff(mobj_t *actor)
  782. {
  783. if(P_Random() > 64)
  784. {
  785. P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
  786. actor->y+((P_Random()-P_Random())<<10),
  787. actor->z+((P_Random()-P_Random())<<10), MT_PUFFY);
  788. }
  789. }
  790. //----------------------------------------------------------------------------
  791. //
  792. // PROC A_ImpMeAttack
  793. //
  794. //----------------------------------------------------------------------------
  795. void A_ImpMeAttack(mobj_t *actor)
  796. {
  797. if(!actor->target)
  798. {
  799. return;
  800. }
  801. S_StartSound(actor, actor->info->attacksound);
  802. if(P_CheckMeleeRange(actor))
  803. {
  804. P_DamageMobj(actor->target, actor, actor, 5+(P_Random()&7));
  805. }
  806. }
  807. //----------------------------------------------------------------------------
  808. //
  809. // PROC A_ImpMsAttack
  810. //
  811. //----------------------------------------------------------------------------
  812. void A_ImpMsAttack(mobj_t *actor)
  813. {
  814. mobj_t *dest;
  815. angle_t an;
  816. int dist;
  817. if(!actor->target || P_Random() > 64)
  818. {
  819. P_SetMobjState(actor, actor->info->seestate);
  820. return;
  821. }
  822. dest = actor->target;
  823. actor->flags |= MF_SKULLFLY;
  824. S_StartSound(actor, actor->info->attacksound);
  825. A_FaceTarget(actor);
  826. an = actor->angle >> ANGLETOFINESHIFT;
  827. actor->momx = FixedMul(12*FRACUNIT, finecosine[an]);
  828. actor->momy = FixedMul(12*FRACUNIT, finesine[an]);
  829. dist = P_AproxDistance(dest->x-actor->x, dest->y-actor->y);
  830. dist = dist/(12*FRACUNIT);
  831. if(dist < 1)
  832. {
  833. dist = 1;
  834. }
  835. actor->momz = (dest->z+(dest->height>>1)-actor->z)/dist;
  836. }
  837. //----------------------------------------------------------------------------
  838. //
  839. // PROC A_ImpMsAttack2
  840. //
  841. // Fireball attack of the imp leader.
  842. //
  843. //----------------------------------------------------------------------------
  844. void A_ImpMsAttack2(mobj_t *actor)
  845. {
  846. if(!actor->target)
  847. {
  848. return;
  849. }
  850. S_StartSound(actor, actor->info->attacksound);
  851. if(P_CheckMeleeRange(actor))
  852. {
  853. P_DamageMobj(actor->target, actor, actor, 5+(P_Random()&7));
  854. return;
  855. }
  856. P_SpawnMissile(actor, actor->target, MT_IMPBALL);
  857. }
  858. //----------------------------------------------------------------------------
  859. //
  860. // PROC A_ImpDeath
  861. //
  862. //----------------------------------------------------------------------------
  863. void A_ImpDeath(mobj_t *actor)
  864. {
  865. actor->flags &= ~MF_SOLID;
  866. actor->flags2 |= MF2_FOOTCLIP;
  867. if(actor->z <= actor->floorz)
  868. {
  869. P_SetMobjState(actor, S_IMP_CRASH1);
  870. }
  871. }
  872. //----------------------------------------------------------------------------
  873. //
  874. // PROC A_ImpXDeath1
  875. //
  876. //----------------------------------------------------------------------------
  877. void A_ImpXDeath1(mobj_t *actor)
  878. {
  879. actor->flags &= ~MF_SOLID;
  880. actor->flags |= MF_NOGRAVITY;
  881. actor->flags2 |= MF2_FOOTCLIP;
  882. actor->special1 = 666; // Flag the crash routine
  883. }
  884. //----------------------------------------------------------------------------
  885. //
  886. // PROC A_ImpXDeath2
  887. //
  888. //----------------------------------------------------------------------------
  889. void A_ImpXDeath2(mobj_t *actor)
  890. {
  891. actor->flags &= ~MF_NOGRAVITY;
  892. if(actor->z <= actor->floorz)
  893. {
  894. P_SetMobjState(actor, S_IMP_CRASH1);
  895. }
  896. }
  897. //----------------------------------------------------------------------------
  898. //
  899. // FUNC P_UpdateChicken
  900. //
  901. // Returns true if the chicken morphs.
  902. //
  903. //----------------------------------------------------------------------------
  904. boolean P_UpdateChicken(mobj_t *actor, int tics)
  905. {
  906. mobj_t *fog;
  907. fixed_t x;
  908. fixed_t y;
  909. fixed_t z;
  910. mobjtype_t moType;
  911. mobj_t *mo;
  912. mobj_t oldChicken;
  913. actor->special1 -= tics;
  914. if(actor->special1 > 0)
  915. {
  916. return(false);
  917. }
  918. moType = actor->special2;
  919. x = actor->x;
  920. y = actor->y;
  921. z = actor->z;
  922. oldChicken = *actor;
  923. P_SetMobjState(actor, S_FREETARGMOBJ);
  924. mo = P_SpawnMobj(x, y, z, moType);
  925. if(P_TestMobjLocation(mo) == false)
  926. { // Didn't fit
  927. P_RemoveMobj(mo);
  928. mo = P_SpawnMobj(x, y, z, MT_CHICKEN);
  929. mo->angle = oldChicken.angle;
  930. mo->flags = oldChicken.flags;
  931. mo->health = oldChicken.health;
  932. mo->target = oldChicken.target;
  933. mo->special1 = 5*35; // Next try in 5 seconds
  934. mo->special2 = moType;
  935. return(false);
  936. }
  937. mo->angle = oldChicken.angle;
  938. mo->target = oldChicken.target;
  939. fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
  940. S_StartSound(fog, sfx_telept);
  941. return(true);
  942. }
  943. //----------------------------------------------------------------------------
  944. //
  945. // PROC A_ChicAttack
  946. //
  947. //----------------------------------------------------------------------------
  948. void A_ChicAttack(mobj_t *actor)
  949. {
  950. if(P_UpdateChicken(actor, 18))
  951. {
  952. return;
  953. }
  954. if(!actor->target)
  955. {
  956. return;
  957. }
  958. if(P_CheckMeleeRange(actor))
  959. {
  960. P_DamageMobj(actor->target, actor, actor, 1+(P_Random()&1));
  961. }
  962. }
  963. //----------------------------------------------------------------------------
  964. //
  965. // PROC A_ChicLook
  966. //
  967. //----------------------------------------------------------------------------
  968. void A_ChicLook(mobj_t *actor)
  969. {
  970. if(P_UpdateChicken(actor, 10))
  971. {
  972. return;
  973. }
  974. A_Look(actor);
  975. }
  976. //----------------------------------------------------------------------------
  977. //
  978. // PROC A_ChicChase
  979. //
  980. //----------------------------------------------------------------------------
  981. void A_ChicChase(mobj_t *actor)
  982. {
  983. if(P_UpdateChicken(actor, 3))
  984. {
  985. return;
  986. }
  987. A_Chase(actor);
  988. }
  989. //----------------------------------------------------------------------------
  990. //
  991. // PROC A_ChicPain
  992. //
  993. //----------------------------------------------------------------------------
  994. void A_ChicPain(mobj_t *actor)
  995. {
  996. if(P_UpdateChicken(actor, 10))
  997. {
  998. return;
  999. }
  1000. S_StartSound(actor, actor->info->painsound);
  1001. }
  1002. //----------------------------------------------------------------------------
  1003. //
  1004. // PROC A_Feathers
  1005. //
  1006. //----------------------------------------------------------------------------
  1007. void A_Feathers(mobj_t *actor)
  1008. {
  1009. int i;
  1010. int count;
  1011. mobj_t *mo;
  1012. if(actor->health > 0)
  1013. { // Pain
  1014. count = P_Random() < 32 ? 2 : 1;
  1015. }
  1016. else
  1017. { // Death
  1018. count = 5+(P_Random()&3);
  1019. }
  1020. for(i = 0; i < count; i++)
  1021. {
  1022. mo = P_SpawnMobj(actor->x, actor->y, actor->z+20*FRACUNIT,
  1023. MT_FEATHER);
  1024. mo->target = actor;
  1025. mo->momx = (P_Random()-P_Random())<<8;
  1026. mo->momy = (P_Random()-P_Random())<<8;
  1027. mo->momz = FRACUNIT+(P_Random()<<9);
  1028. P_SetMobjState(mo, S_FEATHER1+(P_Random()&7));
  1029. }
  1030. }
  1031. //----------------------------------------------------------------------------
  1032. //
  1033. // PROC A_MummyAttack
  1034. //
  1035. //----------------------------------------------------------------------------
  1036. void A_MummyAttack(mobj_t *actor)
  1037. {
  1038. if(!actor->target)
  1039. {
  1040. return;
  1041. }
  1042. S_StartSound(actor, actor->info->attacksound);
  1043. if(P_CheckMeleeRange(actor))
  1044. {
  1045. P_DamageMobj(actor->target, actor, actor, HITDICE(2));
  1046. S_StartSound(actor, sfx_mumat2);
  1047. return;
  1048. }
  1049. S_StartSound(actor, sfx_mumat1);
  1050. }
  1051. //----------------------------------------------------------------------------
  1052. //
  1053. // PROC A_MummyAttack2
  1054. //
  1055. // Mummy leader missile attack.
  1056. //
  1057. //----------------------------------------------------------------------------
  1058. void A_MummyAttack2(mobj_t *actor)
  1059. {
  1060. mobj_t *mo;
  1061. if(!actor->target)
  1062. {
  1063. return;
  1064. }
  1065. //S_StartSound(actor, actor->info->attacksound);
  1066. if(P_CheckMeleeRange(actor))
  1067. {
  1068. P_DamageMobj(actor->target, actor, actor, HITDICE(2));
  1069. return;
  1070. }
  1071. mo = P_SpawnMissile(actor, actor->target, MT_MUMMYFX1);
  1072. //mo = P_SpawnMissile(actor, actor->target, MT_EGGFX);
  1073. if(mo != NULL)
  1074. {
  1075. mo->special1 = (int)actor->target;
  1076. }
  1077. }
  1078. //----------------------------------------------------------------------------
  1079. //
  1080. // PROC A_MummyFX1Seek
  1081. //
  1082. //----------------------------------------------------------------------------
  1083. void A_MummyFX1Seek(mobj_t *actor)
  1084. {
  1085. P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*20);
  1086. }
  1087. //----------------------------------------------------------------------------
  1088. //
  1089. // PROC A_MummySoul
  1090. //
  1091. //----------------------------------------------------------------------------
  1092. void A_MummySoul(mobj_t *mummy)
  1093. {
  1094. mobj_t *mo;
  1095. mo = P_SpawnMobj(mummy->x, mummy->y, mummy->z+10*FRACUNIT, MT_MUMMYSOUL);
  1096. mo->momz = FRACUNIT;
  1097. }
  1098. //----------------------------------------------------------------------------
  1099. //
  1100. // PROC A_Sor1Pain
  1101. //
  1102. //----------------------------------------------------------------------------
  1103. void A_Sor1Pain(mobj_t *actor)
  1104. {
  1105. actor->special1 = 20; // Number of steps to walk fast
  1106. A_Pain(actor);
  1107. }
  1108. //----------------------------------------------------------------------------
  1109. //
  1110. // PROC A_Sor1Chase
  1111. //
  1112. //----------------------------------------------------------------------------
  1113. void A_Sor1Chase(mobj_t *actor)
  1114. {
  1115. if(actor->special1)
  1116. {
  1117. actor->special1--;
  1118. actor->tics -= 3;
  1119. }
  1120. A_Chase(actor);
  1121. }
  1122. //----------------------------------------------------------------------------
  1123. //
  1124. // PROC A_Srcr1Attack
  1125. //
  1126. // Sorcerer demon attack.
  1127. //
  1128. //----------------------------------------------------------------------------
  1129. void A_Srcr1Attack(mobj_t *actor)
  1130. {
  1131. mobj_t *mo;
  1132. fixed_t momz;
  1133. angle_t angle;
  1134. if(!actor->target)
  1135. {
  1136. return;
  1137. }
  1138. S_StartSound(actor, actor->info->attacksound);
  1139. if(P_CheckMeleeRange(actor))
  1140. {
  1141. P_DamageMobj(actor->target, actor, actor, HITDICE(8));
  1142. return;
  1143. }
  1144. if(actor->health > (actor->info->spawnhealth/3)*2)
  1145. { // Spit one fireball
  1146. P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
  1147. }
  1148. else
  1149. { // Spit three fireballs
  1150. mo = P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
  1151. if(mo)
  1152. {
  1153. momz = mo->momz;
  1154. angle = mo->angle;
  1155. P_SpawnMissileAngle(actor, MT_SRCRFX1, angle-ANGLE_1*3, momz);
  1156. P_SpawnMissileAngle(actor, MT_SRCRFX1, angle+ANGLE_1*3, momz);
  1157. }
  1158. if(actor->health < actor->info->spawnhealth/3)
  1159. { // Maybe attack again
  1160. if(actor->special1)
  1161. { // Just attacked, so don't attack again
  1162. actor->special1 = 0;
  1163. }
  1164. else
  1165. { // Set state to attack again
  1166. actor->special1 = 1;
  1167. P_SetMobjState(actor, S_SRCR1_ATK4);
  1168. }
  1169. }
  1170. }
  1171. }
  1172. //----------------------------------------------------------------------------
  1173. //
  1174. // PROC A_SorcererRise
  1175. //
  1176. //----------------------------------------------------------------------------
  1177. void A_SorcererRise(mobj_t *actor)
  1178. {
  1179. mobj_t *mo;
  1180. actor->flags &= ~MF_SOLID;
  1181. mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCERER2);
  1182. P_SetMobjState(mo, S_SOR2_RISE1);
  1183. mo->angle = actor->angle;
  1184. mo->target = actor->target;
  1185. }
  1186. //----------------------------------------------------------------------------
  1187. //
  1188. // PROC P_DSparilTeleport
  1189. //
  1190. //----------------------------------------------------------------------------
  1191. void P_DSparilTeleport(mobj_t *actor)
  1192. {
  1193. int i;
  1194. fixed_t x;
  1195. fixed_t y;
  1196. fixed_t prevX;
  1197. fixed_t prevY;
  1198. fixed_t prevZ;
  1199. mobj_t *mo;
  1200. if(!BossSpotCount)
  1201. { // No spots
  1202. return;
  1203. }
  1204. i = P_Random();
  1205. do
  1206. {
  1207. i++;
  1208. x = BossSpots[i%BossSpotCount].x;
  1209. y = BossSpots[i%BossSpotCount].y;
  1210. } while(P_AproxDistance(actor->x-x, actor->y-y) < 128*FRACUNIT);
  1211. prevX = actor->x;
  1212. prevY = actor->y;
  1213. prevZ = actor->z;
  1214. if(P_TeleportMove(actor, x, y))
  1215. {
  1216. mo = P_SpawnMobj(prevX, prevY, prevZ, MT_SOR2TELEFADE);
  1217. S_StartSound(mo, sfx_telept);
  1218. P_SetMobjState(actor, S_SOR2_TELE1);
  1219. S_StartSound(actor, sfx_telept);
  1220. actor->z = actor->floorz;
  1221. actor->angle = BossSpots[i%BossSpotCount].angle;
  1222. actor->momx = actor->momy = actor->momz = 0;
  1223. }
  1224. }
  1225. //----------------------------------------------------------------------------
  1226. //
  1227. // PROC A_Srcr2Decide
  1228. //
  1229. //----------------------------------------------------------------------------
  1230. void A_Srcr2Decide(mobj_t *actor)
  1231. {
  1232. static int chance[] =
  1233. {
  1234. 192, 120, 120, 120, 64, 64, 32, 16, 0
  1235. };
  1236. if(!BossSpotCount)
  1237. { // No spots
  1238. return;
  1239. }
  1240. if(P_Random() < chance[actor->health/(actor->info->spawnhealth/8)])
  1241. {
  1242. P_DSparilTeleport(actor);
  1243. }
  1244. }
  1245. //----------------------------------------------------------------------------
  1246. //
  1247. // PROC A_Srcr2Attack
  1248. //
  1249. //----------------------------------------------------------------------------
  1250. void A_Srcr2Attack(mobj_t *actor)
  1251. {
  1252. int chance;
  1253. if(!actor->target)
  1254. {
  1255. return;
  1256. }
  1257. S_StartSound(NULL, actor->info->attacksound);
  1258. if(P_CheckMeleeRange(actor))
  1259. {
  1260. P_DamageMobj(actor->target, actor, actor, HITDICE(20));
  1261. return;
  1262. }
  1263. chance = actor->health < actor->info->spawnhealth/2 ? 96 : 48;
  1264. if(P_Random() < chance)
  1265. { // Wizard spawners
  1266. P_SpawnMissileAngle(actor, MT_SOR2FX2,
  1267. actor->angle-ANG45, FRACUNIT/2);
  1268. P_SpawnMissileAngle(actor, MT_SOR2FX2,
  1269. actor->angle+ANG45, FRACUNIT/2);
  1270. }
  1271. else
  1272. { // Blue bolt
  1273. P_SpawnMissile(actor, actor->target, MT_SOR2FX1);
  1274. }
  1275. }
  1276. //----------------------------------------------------------------------------
  1277. //
  1278. // PROC A_BlueSpark
  1279. //
  1280. //----------------------------------------------------------------------------
  1281. void A_BlueSpark(mobj_t *actor)
  1282. {
  1283. int i;
  1284. mobj_t *mo;
  1285. for(i = 0; i < 2; i++)
  1286. {
  1287. mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SOR2FXSPARK);
  1288. mo->momx = (P_Random()-P_Random())<<9;
  1289. mo->momy = (P_Random()-P_Random())<<9;
  1290. mo->momz = FRACUNIT+(P_Random()<<8);
  1291. }
  1292. }
  1293. //----------------------------------------------------------------------------
  1294. //
  1295. // PROC A_GenWizard
  1296. //
  1297. //----------------------------------------------------------------------------
  1298. void A_GenWizard(mobj_t *actor)
  1299. {
  1300. mobj_t *mo;
  1301. mobj_t *fog;
  1302. mo = P_SpawnMobj(actor->x, actor->y,
  1303. actor->z-mobjinfo[MT_WIZARD].height/2, MT_WIZARD);
  1304. if(P_TestMobjLocation(mo) == false)
  1305. { // Didn't fit
  1306. P_RemoveMobj(mo);
  1307. return;
  1308. }
  1309. actor->momx = actor->momy = actor->momz = 0;
  1310. P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
  1311. actor->flags &= ~MF_MISSILE;
  1312. fog = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TFOG);
  1313. S_StartSound(fog, sfx_telept);
  1314. }
  1315. //----------------------------------------------------------------------------
  1316. //
  1317. // PROC A_Sor2DthInit
  1318. //
  1319. //----------------------------------------------------------------------------
  1320. void A_Sor2DthInit(mobj_t *actor)
  1321. {
  1322. actor->special1 = 7; // Animation loop counter
  1323. P_Massacre(); // Kill monsters early
  1324. }
  1325. //----------------------------------------------------------------------------
  1326. //
  1327. // PROC A_Sor2DthLoop
  1328. //
  1329. //----------------------------------------------------------------------------
  1330. void A_Sor2DthLoop(mobj_t *actor)
  1331. {
  1332. if(--actor->special1)
  1333. { // Need to loop
  1334. P_SetMobjState(actor, S_SOR2_DIE4);
  1335. }
  1336. }
  1337. //----------------------------------------------------------------------------
  1338. //
  1339. // D'Sparil Sound Routines
  1340. //
  1341. //----------------------------------------------------------------------------
  1342. void A_SorZap(mobj_t *actor) {S_StartSound(NULL, sfx_sorzap);}
  1343. void A_SorRise(mobj_t *actor) {S_StartSound(NULL, sfx_sorrise);}
  1344. void A_SorDSph(mobj_t *actor) {S_StartSound(NULL, sfx_sordsph);}
  1345. void A_SorDExp(mobj_t *actor) {S_StartSound(NULL, sfx_sordexp);}
  1346. void A_SorDBon(mobj_t *actor) {S_StartSound(NULL, sfx_sordbon);}
  1347. void A_SorSightSnd(mobj_t *actor) {S_StartSound(NULL, sfx_sorsit);}
  1348. //----------------------------------------------------------------------------
  1349. //
  1350. // PROC A_MinotaurAtk1
  1351. //
  1352. // Melee attack.
  1353. //
  1354. //----------------------------------------------------------------------------
  1355. void A_MinotaurAtk1(mobj_t *actor)
  1356. {
  1357. player_t *player;
  1358. if(!actor->target)
  1359. {
  1360. return;
  1361. }
  1362. S_StartSound(actor, sfx_stfpow);
  1363. if(P_CheckMeleeRange(actor))
  1364. {
  1365. P_DamageMobj(actor->target, actor, actor, HITDICE(4));
  1366. if((player = actor->target->player) != NULL)
  1367. { // Squish the player
  1368. player->deltaviewheight = -16*FRACUNIT;
  1369. }
  1370. }
  1371. }
  1372. //----------------------------------------------------------------------------
  1373. //
  1374. // PROC A_MinotaurDecide
  1375. //
  1376. // Choose a missile attack.
  1377. //
  1378. //----------------------------------------------------------------------------
  1379. #define MNTR_CHARGE_SPEED (13*FRACUNIT)
  1380. void A_MinotaurDecide(mobj_t *actor)
  1381. {
  1382. angle_t angle;
  1383. mobj_t *target;
  1384. int dist;
  1385. target = actor->target;
  1386. if(!target)
  1387. {
  1388. return;
  1389. }
  1390. S_StartSound(actor, sfx_minsit);
  1391. dist = P_AproxDistance(actor->x-target->x, actor->y-target->y);
  1392. if(target->z+target->height > actor->z
  1393. && target->z+target->height < actor->z+actor->height
  1394. && dist < 8*64*FRACUNIT
  1395. && dist > 1*64*FRACUNIT
  1396. && P_Random() < 150)
  1397. { // Charge attack
  1398. // Don't call the state function right away
  1399. P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
  1400. actor->flags |= MF_SKULLFLY;
  1401. A_FaceTarget(actor);
  1402. angle = actor->angle>>ANGLETOFINESHIFT;
  1403. actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
  1404. actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
  1405. actor->special1 = 35/2; // Charge duration
  1406. }
  1407. else if(target->z == target->floorz
  1408. && dist < 9*64*FRACUNIT
  1409. && P_Random() < 220)
  1410. { // Floor fire attack
  1411. P_SetMobjState(actor, S_MNTR_ATK3_1);
  1412. actor->special2 = 0;
  1413. }
  1414. else
  1415. { // Swing attack
  1416. A_FaceTarget(actor);
  1417. // Don't need to call P_SetMobjState because the current state
  1418. // falls through to the swing attack
  1419. }
  1420. }
  1421. //----------------------------------------------------------------------------
  1422. //
  1423. // PROC A_MinotaurCharge
  1424. //
  1425. //----------------------------------------------------------------------------
  1426. void A_MinotaurCharge(mobj_t *actor)
  1427. {
  1428. mobj_t *puff;
  1429. if(actor->special1)
  1430. {
  1431. puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
  1432. puff->momz = 2*FRACUNIT;
  1433. actor->special1--;
  1434. }
  1435. else
  1436. {
  1437. actor->flags &= ~MF_SKULLFLY;
  1438. P_SetMobjState(actor, actor->info->seestate);
  1439. }
  1440. }
  1441. //----------------------------------------------------------------------------
  1442. //
  1443. // PROC A_MinotaurAtk2
  1444. //
  1445. // Swing attack.
  1446. //
  1447. //----------------------------------------------------------------------------
  1448. void A_MinotaurAtk2(mobj_t *actor)
  1449. {
  1450. mobj_t *mo;
  1451. angle_t angle;
  1452. fixed_t momz;
  1453. if(!actor->target)
  1454. {
  1455. return;
  1456. }
  1457. S_StartSound(actor, sfx_minat2);
  1458. if(P_CheckMeleeRange(actor))
  1459. {
  1460. P_DamageMobj(actor->target, actor, actor, HITDICE(5));
  1461. return;
  1462. }
  1463. mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
  1464. if(mo)
  1465. {
  1466. S_StartSound(mo, sfx_minat2);
  1467. momz = mo->momz;
  1468. angle = mo->angle;
  1469. P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/8), momz);
  1470. P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/8), momz);
  1471. P_SpawnMissileAngle(actor, MT_MNTRFX1, angle-(ANG45/16), momz);
  1472. P_SpawnMissileAngle(actor, MT_MNTRFX1, angle+(ANG45/16), momz);
  1473. }
  1474. }
  1475. //----------------------------------------------------------------------------
  1476. //
  1477. // PROC A_MinotaurAtk3
  1478. //
  1479. // Floor fire attack.
  1480. //
  1481. //----------------------------------------------------------------------------
  1482. void A_MinotaurAtk3(mobj_t *actor)
  1483. {
  1484. mobj_t *mo;
  1485. player_t *player;
  1486. if(!actor->target)
  1487. {
  1488. return;
  1489. }
  1490. if(P_CheckMeleeRange(actor))
  1491. {
  1492. P_DamageMobj(actor->target, actor, actor, HITDICE(5));
  1493. if((player = actor->target->player) != NULL)
  1494. { // Squish the player
  1495. player->deltaviewheight = -16*FRACUNIT;
  1496. }
  1497. }
  1498. else
  1499. {
  1500. mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
  1501. if(mo != NULL)
  1502. {
  1503. S_StartSound(mo, sfx_minat1);
  1504. }
  1505. }
  1506. if(P_Random() < 192 && actor->special2 == 0)
  1507. {
  1508. P_SetMobjState(actor, S_MNTR_ATK3_4);
  1509. actor->special2 = 1;
  1510. }
  1511. }
  1512. //----------------------------------------------------------------------------
  1513. //
  1514. // PROC A_MntrFloorFire
  1515. //
  1516. //----------------------------------------------------------------------------
  1517. void A_MntrFloorFire(mobj_t *actor)
  1518. {
  1519. mobj_t *mo;
  1520. actor->z = actor->floorz;
  1521. mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<10),
  1522. actor->y+((P_Random()-P_Random())<<10), ONFLOORZ, MT_MNTRFX3);
  1523. mo->target = actor->target;
  1524. mo->momx = 1; // Force block checking
  1525. P_CheckMissileSpawn(mo);
  1526. }
  1527. //----------------------------------------------------------------------------
  1528. //
  1529. // PROC A_BeastAttack
  1530. //
  1531. //----------------------------------------------------------------------------
  1532. void A_BeastAttack(mobj_t *actor)
  1533. {
  1534. if(!actor->target)
  1535. {
  1536. return;
  1537. }
  1538. S_StartSound(actor, actor->info->attacksound);
  1539. if(P_CheckMeleeRange(actor))
  1540. {
  1541. P_DamageMobj(actor->target, actor, actor, HITDICE(3));
  1542. return;
  1543. }
  1544. P_SpawnMissile(actor, actor->target, MT_BEASTBALL);
  1545. }
  1546. //----------------------------------------------------------------------------
  1547. //
  1548. // PROC A_HeadAttack
  1549. //
  1550. //----------------------------------------------------------------------------
  1551. void A_HeadAttack(mobj_t *actor)
  1552. {
  1553. int i;
  1554. mobj_t *fire;
  1555. mobj_t *baseFire;
  1556. mobj_t *mo;
  1557. mobj_t *target;
  1558. int randAttack;
  1559. static int atkResolve1[] = { 50, 150 };
  1560. static int atkResolve2[] = { 150, 200 };
  1561. int dist;
  1562. // Ice ball (close 20% : far 60%)
  1563. // Fire column (close 40% : far 20%)
  1564. // Whirlwind (close 40% : far 20%)
  1565. // Distance threshold = 8 cells
  1566. target = actor->target;
  1567. if(target == NULL)
  1568. {
  1569. return;
  1570. }
  1571. A_FaceTarget(actor);
  1572. if(P_CheckMeleeRange(actor))
  1573. {
  1574. P_DamageMobj(target, actor, actor, HITDICE(6));
  1575. return;
  1576. }
  1577. dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)
  1578. > 8*64*FRACUNIT;
  1579. randAttack = P_Random();
  1580. if(randAttack < atkResolve1[dist])
  1581. { // Ice ball
  1582. P_SpawnMissile(actor, target, MT_HEADFX1);
  1583. S_StartSound(actor, sfx_hedat2);
  1584. }
  1585. else if(randAttack < atkResolve2[dist])
  1586. { // Fire column
  1587. baseFire = P_SpawnMissile(actor, target, MT_HEADFX3);
  1588. if(baseFire != NULL)
  1589. {
  1590. P_SetMobjState(baseFire, S_HEADFX3_4); // Don't grow
  1591. for(i = 0; i < 5; i++)
  1592. {
  1593. fire = P_SpawnMobj(baseFire->x, baseFire->y,
  1594. baseFire->z, MT_HEADFX3);
  1595. if(i == 0)
  1596. {
  1597. S_StartSound(actor, sfx_hedat1);
  1598. }
  1599. fire->target = baseFire->target;
  1600. fire->angle = baseFire->angle;
  1601. fire->momx = baseFire->momx;
  1602. fire->momy = baseFire->momy;
  1603. fire->momz = baseFire->momz;
  1604. fire->damage = 0;
  1605. fire->health = (i+1)*2;
  1606. P_CheckMissileSpawn(fire);
  1607. }
  1608. }
  1609. }
  1610. else
  1611. { // Whirlwind
  1612. mo = P_SpawnMissile(actor, target, MT_WHIRLWIND);
  1613. if(mo != NULL)
  1614. {
  1615. mo->z -= 32*FRACUNIT;
  1616. mo->special1 = (int)target;
  1617. mo->special2 = 50; // Timer for active sound
  1618. mo->health = 20*TICSPERSEC; // Duration
  1619. S_StartSound(actor, sfx_hedat3);
  1620. }
  1621. }
  1622. }
  1623. //----------------------------------------------------------------------------
  1624. //
  1625. // PROC A_WhirlwindSeek
  1626. //
  1627. //----------------------------------------------------------------------------
  1628. void A_WhirlwindSeek(mobj_t *actor)
  1629. {
  1630. actor->health -= 3;
  1631. if(actor->health < 0)
  1632. {
  1633. actor->momx = actor->momy = actor->momz = 0;
  1634. P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
  1635. actor->flags &= ~MF_MISSILE;
  1636. return;
  1637. }
  1638. if((actor->special2 -= 3) < 0)
  1639. {
  1640. actor->special2 = 58+(P_Random()&31);
  1641. S_StartSound(actor, sfx_hedat3);
  1642. }
  1643. if(actor->special1
  1644. && (((mobj_t *)(actor->special1))->flags&MF_SHADOW))
  1645. {
  1646. return;
  1647. }
  1648. P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*30);
  1649. }
  1650. //----------------------------------------------------------------------------
  1651. //
  1652. // PROC A_HeadIceImpact
  1653. //
  1654. //----------------------------------------------------------------------------
  1655. void A_HeadIceImpact(mobj_t *ice)
  1656. {
  1657. int i;
  1658. angle_t angle;
  1659. mobj_t *shard;
  1660. for(i = 0; i < 8; i++)
  1661. {
  1662. shard = P_SpawnMobj(ice->x, ice->y, ice->z, MT_HEADFX2);
  1663. angle = i*ANG45;
  1664. shard->target = ice->target;
  1665. shard->angle = angle;
  1666. angle >>= ANGLETOFINESHIFT;
  1667. shard->momx = FixedMul(shard->info->speed, finecosine[angle]);
  1668. shard->momy = FixedMul(shard->info->speed, finesine[angle]);
  1669. shard->momz = -.6*FRACUNIT;
  1670. P_CheckMissileSpawn(shard);
  1671. }
  1672. }
  1673. //----------------------------------------------------------------------------
  1674. //
  1675. // PROC A_HeadFireGrow
  1676. //
  1677. //----------------------------------------------------------------------------
  1678. void A_HeadFireGrow(mobj_t *fire)
  1679. {
  1680. fire->health--;
  1681. fire->z += 9*FRACUNIT;
  1682. if(fire->health == 0)
  1683. {
  1684. fire->damage = fire->info->damage;
  1685. P_SetMobjState(fire, S_HEADFX3_4);
  1686. }
  1687. }
  1688. //----------------------------------------------------------------------------
  1689. //
  1690. // PROC A_SnakeAttack
  1691. //
  1692. //----------------------------------------------------------------------------
  1693. void A_SnakeAttack(mobj_t *actor)
  1694. {
  1695. if(!actor->target)
  1696. {
  1697. P_SetMobjState(actor, S_SNAKE_WALK1);
  1698. return;
  1699. }
  1700. S_StartSound(actor, actor->info->attacksound);
  1701. A_FaceTarget(actor);
  1702. P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_A);
  1703. }
  1704. //----------------------------------------------------------------------------
  1705. //
  1706. // PROC A_SnakeAttack2
  1707. //
  1708. //----------------------------------------------------------------------------
  1709. void A_SnakeAttack2(mobj_t *actor)
  1710. {
  1711. if(!actor->target)
  1712. {
  1713. P_SetMobjState(actor, S_SNAKE_WALK1);
  1714. return;
  1715. }
  1716. S_StartSound(actor, actor->info->attacksound);
  1717. A_FaceTarget(actor);
  1718. P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_B);
  1719. }
  1720. //----------------------------------------------------------------------------
  1721. //
  1722. // PROC A_ClinkAttack
  1723. //
  1724. //----------------------------------------------------------------------------
  1725. void A_ClinkAttack(mobj_t *actor)
  1726. {
  1727. int damage;
  1728. if(!actor->target)
  1729. {
  1730. return;
  1731. }
  1732. S_StartSound(actor, actor->info->attacksound);
  1733. if(P_CheckMeleeRange(actor))
  1734. {
  1735. damage = ((P_Random()%7)+3);
  1736. P_DamageMobj(actor->target, actor, actor, damage);
  1737. }
  1738. }
  1739. //----------------------------------------------------------------------------
  1740. //
  1741. // PROC A_GhostOff
  1742. //
  1743. //----------------------------------------------------------------------------
  1744. void A_GhostOff(mobj_t *actor)
  1745. {
  1746. actor->flags &= ~MF_SHADOW;
  1747. }
  1748. //----------------------------------------------------------------------------
  1749. //
  1750. // PROC A_WizAtk1
  1751. //
  1752. //----------------------------------------------------------------------------
  1753. void A_WizAtk1(mobj_t *actor)
  1754. {
  1755. A_FaceTarget(actor);
  1756. actor->flags &= ~MF_SHADOW;
  1757. }
  1758. //----------------------------------------------------------------------------
  1759. //
  1760. // PROC A_WizAtk2
  1761. //
  1762. //----------------------------------------------------------------------------
  1763. void A_WizAtk2(mobj_t *actor)
  1764. {
  1765. A_FaceTarget(actor);
  1766. actor->flags |= MF_SHADOW;
  1767. }
  1768. //----------------------------------------------------------------------------
  1769. //
  1770. // PROC A_WizAtk3
  1771. //
  1772. //----------------------------------------------------------------------------
  1773. void A_WizAtk3(mobj_t *actor)
  1774. {
  1775. mobj_t *mo;
  1776. angle_t angle;
  1777. fixed_t momz;
  1778. actor->flags &= ~MF_SHADOW;
  1779. if(!actor->target)
  1780. {
  1781. return;
  1782. }
  1783. S_StartSound(actor, actor->info->attacksound);
  1784. if(P_CheckMeleeRange(actor))
  1785. {
  1786. P_DamageMobj(actor->target, actor, actor, HITDICE(4));
  1787. return;
  1788. }
  1789. mo = P_SpawnMissile(actor, actor->target, MT_WIZFX1);
  1790. if(mo)
  1791. {
  1792. momz = mo->momz;
  1793. angle = mo->angle;
  1794. P_SpawnMissileAngle(actor, MT_WIZFX1, angle-(ANG45/8), momz);
  1795. P_SpawnMissileAngle(actor, MT_WIZFX1, angle+(ANG45/8), momz);
  1796. }
  1797. }
  1798. //----------------------------------------------------------------------------
  1799. //
  1800. // PROC A_Scream
  1801. //
  1802. //----------------------------------------------------------------------------
  1803. void A_Scream(mobj_t *actor)
  1804. {
  1805. switch(actor->type)
  1806. {
  1807. case MT_CHICPLAYER:
  1808. case MT_SORCERER1:
  1809. case MT_MINOTAUR:
  1810. // Make boss death sounds full volume
  1811. S_StartSound(NULL, actor->info->deathsound);
  1812. break;
  1813. case MT_PLAYER:
  1814. // Handle the different player death screams
  1815. if(actor->special1 < 10)
  1816. { // Wimpy death sound
  1817. S_StartSound(actor, sfx_plrwdth);
  1818. }
  1819. else if(actor->health > -50)
  1820. { // Normal death sound
  1821. S_StartSound(actor, actor->info->deathsound);
  1822. }
  1823. else if(actor->health > -100)
  1824. { // Crazy death sound
  1825. S_StartSound(actor, sfx_plrcdth);
  1826. }
  1827. else
  1828. { // Extreme death sound
  1829. S_StartSound(actor, sfx_gibdth);
  1830. }
  1831. break;
  1832. default:
  1833. S_StartSound(actor, actor->info->deathsound);
  1834. break;
  1835. }
  1836. }
  1837. //---------------------------------------------------------------------------
  1838. //
  1839. // PROC P_DropItem
  1840. //
  1841. //---------------------------------------------------------------------------
  1842. void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
  1843. {
  1844. mobj_t *mo;
  1845. if(P_Random() > chance)
  1846. {
  1847. return;
  1848. }
  1849. mo = P_SpawnMobj(source->x, source->y,
  1850. source->z+(source->height>>1), type);
  1851. mo->momx = (P_Random()-P_Random())<<8;
  1852. mo->momy = (P_Random()-P_Random())<<8;
  1853. mo->momz = FRACUNIT*5+(P_Random()<<10);
  1854. mo->flags |= MF_DROPPED;
  1855. mo->health = special;
  1856. }
  1857. //----------------------------------------------------------------------------
  1858. //
  1859. // PROC A_NoBlocking
  1860. //
  1861. //----------------------------------------------------------------------------
  1862. void A_NoBlocking(mobj_t *actor)
  1863. {
  1864. actor->flags &= ~MF_SOLID;
  1865. // Check for monsters dropping things
  1866. switch(actor->type)
  1867. {
  1868. case MT_MUMMY:
  1869. case MT_MUMMYLEADER:
  1870. case MT_MUMMYGHOST:
  1871. case MT_MUMMYLEADERGHOST:
  1872. P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
  1873. break;
  1874. case MT_KNIGHT:
  1875. case MT_KNIGHTGHOST:
  1876. P_DropItem(actor, MT_AMCBOWWIMPY, 5, 84);
  1877. break;
  1878. case MT_WIZARD:
  1879. P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
  1880. P_DropItem(actor, MT_ARTITOMEOFPOWER, 0, 4);
  1881. break;
  1882. case MT_HEAD:
  1883. P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
  1884. P_DropItem(actor, MT_ARTIEGG, 0, 51);
  1885. break;
  1886. case MT_BEAST:
  1887. P_DropItem(actor, MT_AMCBOWWIMPY, 10, 84);
  1888. break;
  1889. case MT_CLINK:
  1890. P_DropItem(actor, MT_AMSKRDWIMPY, 20, 84);
  1891. break;
  1892. case MT_SNAKE:
  1893. P_DropItem(actor, MT_AMPHRDWIMPY, 5, 84);
  1894. break;
  1895. case MT_MINOTAUR:
  1896. P_DropItem(actor, MT_ARTISUPERHEAL, 0, 51);
  1897. P_DropItem(actor, MT_AMPHRDWIMPY, 10, 84);
  1898. break;
  1899. default:
  1900. break;
  1901. }
  1902. }
  1903. //----------------------------------------------------------------------------
  1904. //
  1905. // PROC A_Explode
  1906. //
  1907. // Handles a bunch of exploding things.
  1908. //
  1909. //----------------------------------------------------------------------------
  1910. void A_Explode(mobj_t *actor)
  1911. {
  1912. int damage;
  1913. damage = 128;
  1914. switch(actor->type)
  1915. {
  1916. case MT_FIREBOMB: // Time Bombs
  1917. actor->z += 32*FRACUNIT;
  1918. actor->flags &= ~MF_SHADOW;
  1919. break;
  1920. case MT_MNTRFX2: // Minotaur floor fire
  1921. damage = 24;
  1922. break;
  1923. case MT_SOR2FX1: // D'Sparil missile
  1924. damage = 80+(P_Random()&31);
  1925. break;
  1926. default:
  1927. break;
  1928. }
  1929. P_RadiusAttack(actor, actor->target, damage);
  1930. P_HitFloor(actor);
  1931. }
  1932. //----------------------------------------------------------------------------
  1933. //
  1934. // PROC A_PodPain
  1935. //
  1936. //----------------------------------------------------------------------------
  1937. void A_PodPain(mobj_t *actor)
  1938. {
  1939. int i;
  1940. int count;
  1941. int chance;
  1942. mobj_t *goo;
  1943. chance = P_Random();
  1944. if(chance < 128)
  1945. {
  1946. return;
  1947. }
  1948. count = chance > 240 ? 2 : 1;
  1949. for(i = 0; i < count; i++)
  1950. {
  1951. goo = P_SpawnMobj(actor->x, actor->y,
  1952. actor->z+48*FRACUNIT, MT_PODGOO);
  1953. goo->target = actor;
  1954. goo->momx = (P_Random()-P_Random())<<9;
  1955. goo->momy = (P_Random()-P_Random())<<9;
  1956. goo->momz = FRACUNIT/2+(P_Random()<<9);
  1957. }
  1958. }
  1959. //----------------------------------------------------------------------------
  1960. //
  1961. // PROC A_RemovePod
  1962. //
  1963. //----------------------------------------------------------------------------
  1964. void A_RemovePod(mobj_t *actor)
  1965. {
  1966. mobj_t *mo;
  1967. if(actor->special2)
  1968. {
  1969. mo = (mobj_t *)actor->special2;
  1970. if(mo->special1 > 0)
  1971. {
  1972. mo->special1--;
  1973. }
  1974. }
  1975. }
  1976. //----------------------------------------------------------------------------
  1977. //
  1978. // PROC A_MakePod
  1979. //
  1980. //----------------------------------------------------------------------------
  1981. #define MAX_GEN_PODS 16
  1982. void A_MakePod(mobj_t *actor)
  1983. {
  1984. mobj_t *mo;
  1985. fixed_t x;
  1986. fixed_t y;
  1987. fixed_t z;
  1988. if(actor->special1 == MAX_GEN_PODS)
  1989. { // Too many generated pods
  1990. return;
  1991. }
  1992. x = actor->x;
  1993. y = actor->y;
  1994. z = actor->z;
  1995. mo = P_SpawnMobj(x, y, ONFLOORZ, MT_POD);
  1996. if(P_CheckPosition(mo, x, y) == false)
  1997. { // Didn't fit
  1998. P_RemoveMobj(mo);
  1999. return;
  2000. }
  2001. P_SetMobjState(mo, S_POD_GROW1);
  2002. P_ThrustMobj(mo, P_Random()<<24, (fixed_t)(4.5*FRACUNIT));
  2003. S_StartSound(mo, sfx_newpod);
  2004. actor->special1++; // Increment generated pod count
  2005. mo->special2 = (int)actor; // Link the generator to the pod
  2006. return;
  2007. }
  2008. //----------------------------------------------------------------------------
  2009. //
  2010. // PROC P_Massacre
  2011. //
  2012. // Kills all monsters.
  2013. //
  2014. //----------------------------------------------------------------------------
  2015. void P_Massacre(void)
  2016. {
  2017. mobj_t *mo;
  2018. thinker_t *think;
  2019. for(think = thinkercap.next; think != &thinkercap;
  2020. think = think->next)
  2021. {
  2022. if(think->function != P_MobjThinker)
  2023. { // Not a mobj thinker
  2024. continue;
  2025. }
  2026. mo = (mobj_t *)think;
  2027. if((mo->flags&MF_COUNTKILL) && (mo->health > 0))
  2028. {
  2029. P_DamageMobj(mo, NULL, NULL, 10000);
  2030. }
  2031. }
  2032. }
  2033. //----------------------------------------------------------------------------
  2034. //
  2035. // PROC A_BossDeath
  2036. //
  2037. // Trigger special effects if all bosses are dead.
  2038. //
  2039. //----------------------------------------------------------------------------
  2040. void A_BossDeath(mobj_t *actor)
  2041. {
  2042. mobj_t *mo;
  2043. thinker_t *think;
  2044. line_t dummyLine;
  2045. static mobjtype_t bossType[6] =
  2046. {
  2047. MT_HEAD,
  2048. MT_MINOTAUR,
  2049. MT_SORCERER2,
  2050. MT_HEAD,
  2051. MT_MINOTAUR,
  2052. -1
  2053. };
  2054. if(gamemap != 8)
  2055. { // Not a boss level
  2056. return;
  2057. }
  2058. if(actor->type != bossType[gameepisode-1])
  2059. { // Not considered a boss in this episode
  2060. return;
  2061. }
  2062. // Make sure all bosses are dead
  2063. for(think = thinkercap.next; think != &thinkercap; think = think->next)
  2064. {
  2065. if(think->function != P_MobjThinker)
  2066. { // Not a mobj thinker
  2067. continue;
  2068. }
  2069. mo = (mobj_t *)think;
  2070. if((mo != actor) && (mo->type == actor->type) && (mo->health > 0))
  2071. { // Found a living boss
  2072. return;
  2073. }
  2074. }
  2075. if(gameepisode > 1)
  2076. { // Kill any remaining monsters
  2077. P_Massacre();
  2078. }
  2079. dummyLine.tag = 666;
  2080. EV_DoFloor(&dummyLine, lowerFloor);
  2081. }
  2082. //----------------------------------------------------------------------------
  2083. //
  2084. // PROC A_ESound
  2085. //
  2086. //----------------------------------------------------------------------------
  2087. void A_ESound(mobj_t *mo)
  2088. {
  2089. int sound;
  2090. switch(mo->type)
  2091. {
  2092. case MT_SOUNDWATERFALL:
  2093. sound = sfx_waterfl;
  2094. break;
  2095. case MT_SOUNDWIND:
  2096. sound = sfx_wind;
  2097. break;
  2098. default:
  2099. break;
  2100. }
  2101. S_StartSound(mo, sound);
  2102. }
  2103. //----------------------------------------------------------------------------
  2104. //
  2105. // PROC A_SpawnTeleGlitter
  2106. //
  2107. //----------------------------------------------------------------------------
  2108. void A_SpawnTeleGlitter(mobj_t *actor)
  2109. {
  2110. mobj_t *mo;
  2111. mo = P_SpawnMobj(actor->x+((P_Random()&31)-16)*FRACUNIT,
  2112. actor->y+((P_Random()&31)-16)*FRACUNIT,
  2113. actor->subsector->sector->floorheight, MT_TELEGLITTER);
  2114. mo->momz = FRACUNIT/4;
  2115. }
  2116. //----------------------------------------------------------------------------
  2117. //
  2118. // PROC A_SpawnTeleGlitter2
  2119. //
  2120. //----------------------------------------------------------------------------
  2121. void A_SpawnTeleGlitter2(mobj_t *actor)
  2122. {
  2123. mobj_t *mo;
  2124. mo = P_SpawnMobj(actor->x+((P_Random()&31)-16)*FRACUNIT,
  2125. actor->y+((P_Random()&31)-16)*FRACUNIT,
  2126. actor->subsector->sector->floorheight, MT_TELEGLITTER2);
  2127. mo->momz = FRACUNIT/4;
  2128. }
  2129. //----------------------------------------------------------------------------
  2130. //
  2131. // PROC A_AccTeleGlitter
  2132. //
  2133. //----------------------------------------------------------------------------
  2134. void A_AccTeleGlitter(mobj_t *actor)
  2135. {
  2136. if(++actor->health > 35)
  2137. {
  2138. actor->momz += actor->momz/2;
  2139. }
  2140. }
  2141. //----------------------------------------------------------------------------
  2142. //
  2143. // PROC A_InitKeyGizmo
  2144. //
  2145. //----------------------------------------------------------------------------
  2146. void A_InitKeyGizmo(mobj_t *gizmo)
  2147. {
  2148. mobj_t *mo;
  2149. statenum_t state;
  2150. switch(gizmo->type)
  2151. {
  2152. case MT_KEYGIZMOBLUE:
  2153. state = S_KGZ_BLUEFLOAT1;
  2154. break;
  2155. case MT_KEYGIZMOGREEN:
  2156. state = S_KGZ_GREENFLOAT1;
  2157. break;
  2158. case MT_KEYGIZMOYELLOW:
  2159. state = S_KGZ_YELLOWFLOAT1;
  2160. break;
  2161. default:
  2162. break;
  2163. }
  2164. mo = P_SpawnMobj(gizmo->x, gizmo->y, gizmo->z+60*FRACUNIT,
  2165. MT_KEYGIZMOFLOAT);
  2166. P_SetMobjState(mo, state);
  2167. }
  2168. //----------------------------------------------------------------------------
  2169. //
  2170. // PROC A_VolcanoSet
  2171. //
  2172. //----------------------------------------------------------------------------
  2173. void A_VolcanoSet(mobj_t *volcano)
  2174. {
  2175. volcano->tics = 105+(P_Random()&127);
  2176. }
  2177. //----------------------------------------------------------------------------
  2178. //
  2179. // PROC A_VolcanoBlast
  2180. //
  2181. //----------------------------------------------------------------------------
  2182. void A_VolcanoBlast(mobj_t *volcano)
  2183. {
  2184. int i;
  2185. int count;
  2186. mobj_t *blast;
  2187. angle_t angle;
  2188. count = 1+(P_Random()%3);
  2189. for(i = 0; i < count; i++)
  2190. {
  2191. blast = P_SpawnMobj(volcano->x, volcano->y,
  2192. volcano->z+44*FRACUNIT, MT_VOLCANOBLAST); // MT_VOLCANOBLAST
  2193. blast->target = volcano;
  2194. angle = P_Random()<<24;
  2195. blast->angle = angle;
  2196. angle >>= ANGLETOFINESHIFT;
  2197. blast->momx = FixedMul(1*FRACUNIT, finecosine[angle]);
  2198. blast->momy = FixedMul(1*FRACUNIT, finesine[angle]);
  2199. blast->momz = (2.5*FRACUNIT)+(P_Random()<<10);
  2200. S_StartSound(blast, sfx_volsht);
  2201. P_CheckMissileSpawn(blast);
  2202. }
  2203. }
  2204. //----------------------------------------------------------------------------
  2205. //
  2206. // PROC A_VolcBallImpact
  2207. //
  2208. //----------------------------------------------------------------------------
  2209. void A_VolcBallImpact(mobj_t *ball)
  2210. {
  2211. int i;
  2212. mobj_t *tiny;
  2213. angle_t angle;
  2214. if(ball->z <= ball->floorz)
  2215. {
  2216. ball->flags |= MF_NOGRAVITY;
  2217. ball->flags2 &= ~MF2_LOGRAV;
  2218. ball->z += 28*FRACUNIT;
  2219. //ball->momz = 3*FRACUNIT;
  2220. }
  2221. P_RadiusAttack(ball, ball->target, 25);
  2222. for(i = 0; i < 4; i++)
  2223. {
  2224. tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_VOLCANOTBLAST);
  2225. tiny->target = ball;
  2226. angle = i*ANG90;
  2227. tiny->angle = angle;
  2228. angle >>= ANGLETOFINESHIFT;
  2229. tiny->momx = FixedMul(FRACUNIT*.7, finecosine[angle]);
  2230. tiny->momy = FixedMul(FRACUNIT*.7, finesine[angle]);
  2231. tiny->momz = FRACUNIT+(P_Random()<<9);
  2232. P_CheckMissileSpawn(tiny);
  2233. }
  2234. }
  2235. //----------------------------------------------------------------------------
  2236. //
  2237. // PROC A_SkullPop
  2238. //
  2239. //----------------------------------------------------------------------------
  2240. void A_SkullPop(mobj_t *actor)
  2241. {
  2242. mobj_t *mo;
  2243. player_t *player;
  2244. actor->flags &= ~MF_SOLID;
  2245. mo = P_SpawnMobj(actor->x, actor->y, actor->z+48*FRACUNIT,
  2246. MT_BLOODYSKULL);
  2247. //mo->target = actor;
  2248. mo->momx = (P_Random()-P_Random())<<9;
  2249. mo->momy = (P_Random()-P_Random())<<9;
  2250. mo->momz = FRACUNIT*2+(P_Random()<<6);
  2251. // Attach player mobj to bloody skull
  2252. player = actor->player;
  2253. actor->player = NULL;
  2254. mo->player = player;
  2255. mo->health = actor->health;
  2256. mo->angle = actor->angle;
  2257. player->mo = mo;
  2258. player->lookdir = 0;
  2259. player->damagecount = 32;
  2260. }
  2261. //----------------------------------------------------------------------------
  2262. //
  2263. // PROC A_CheckSkullFloor
  2264. //
  2265. //----------------------------------------------------------------------------
  2266. void A_CheckSkullFloor(mobj_t *actor)
  2267. {
  2268. if(actor->z <= actor->floorz)
  2269. {
  2270. P_SetMobjState(actor, S_BLOODYSKULLX1);
  2271. }
  2272. }
  2273. //----------------------------------------------------------------------------
  2274. //
  2275. // PROC A_CheckSkullDone
  2276. //
  2277. //----------------------------------------------------------------------------
  2278. void A_CheckSkullDone(mobj_t *actor)
  2279. {
  2280. if(actor->special2 == 666)
  2281. {
  2282. P_SetMobjState(actor, S_BLOODYSKULLX2);
  2283. }
  2284. }
  2285. //----------------------------------------------------------------------------
  2286. //
  2287. // PROC A_CheckBurnGone
  2288. //
  2289. //----------------------------------------------------------------------------
  2290. void A_CheckBurnGone(mobj_t *actor)
  2291. {
  2292. if(actor->special2 == 666)
  2293. {
  2294. P_SetMobjState(actor, S_PLAY_FDTH20);
  2295. }
  2296. }
  2297. //----------------------------------------------------------------------------
  2298. //
  2299. // PROC A_FreeTargMobj
  2300. //
  2301. //----------------------------------------------------------------------------
  2302. void A_FreeTargMobj(mobj_t *mo)
  2303. {
  2304. mo->momx = mo->momy = mo->momz = 0;
  2305. mo->z = mo->ceilingz+4*FRACUNIT;
  2306. mo->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_SOLID);
  2307. mo->flags |= MF_CORPSE|MF_DROPOFF|MF_NOGRAVITY;
  2308. mo->flags2 &= ~(MF2_PASSMOBJ|MF2_LOGRAV);
  2309. mo->player = NULL;
  2310. }
  2311. //----------------------------------------------------------------------------
  2312. //
  2313. // PROC A_AddPlayerCorpse
  2314. //
  2315. //----------------------------------------------------------------------------
  2316. #define BODYQUESIZE 32
  2317. mobj_t *bodyque[BODYQUESIZE];
  2318. int bodyqueslot;
  2319. void A_AddPlayerCorpse(mobj_t *actor)
  2320. {
  2321. if(bodyqueslot >= BODYQUESIZE)
  2322. { // Too many player corpses - remove an old one
  2323. P_RemoveMobj(bodyque[bodyqueslot%BODYQUESIZE]);
  2324. }
  2325. bodyque[bodyqueslot%BODYQUESIZE] = actor;
  2326. bodyqueslot++;
  2327. }
  2328. //----------------------------------------------------------------------------
  2329. //
  2330. // PROC A_FlameSnd
  2331. //
  2332. //----------------------------------------------------------------------------
  2333. void A_FlameSnd(mobj_t *actor)
  2334. {
  2335. S_StartSound(actor, sfx_hedat1); // Burn sound
  2336. }
  2337. //----------------------------------------------------------------------------
  2338. //
  2339. // PROC A_HideThing
  2340. //
  2341. //----------------------------------------------------------------------------
  2342. void A_HideThing(mobj_t *actor)
  2343. {
  2344. //P_UnsetThingPosition(actor);
  2345. actor->flags2 |= MF2_DONTDRAW;
  2346. }
  2347. //----------------------------------------------------------------------------
  2348. //
  2349. // PROC A_UnHideThing
  2350. //
  2351. //----------------------------------------------------------------------------
  2352. void A_UnHideThing(mobj_t *actor)
  2353. {
  2354. //P_SetThingPosition(actor);
  2355. actor->flags2 &= ~MF2_DONTDRAW;
  2356. }