ACTOR.CPP 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "actor.h"
  4. #include "debug4g.h"
  5. #include "engine.h"
  6. #include "trig.h"
  7. #include "gameutil.h"
  8. #include "misc.h"
  9. #include "db.h"
  10. #include "multi.h"
  11. #include "names.h"
  12. #include "screen.h"
  13. #include "sectorfx.h"
  14. #include "triggers.h"
  15. #include "error.h"
  16. #include "globals.h"
  17. #include "seq.h"
  18. #include "eventq.h"
  19. #include "dude.h"
  20. #include "ai.h"
  21. #include "view.h"
  22. #include "warp.h"
  23. #include "tile.h"
  24. #include "player.h"
  25. #include "options.h"
  26. #include "sfx.h"
  27. #include "sound.h" // can be removed once sfx complete
  28. #define kMaxSpareSprites 50
  29. SPRITEHIT gSpriteHit[kMaxXSprites];
  30. static void MakeSplash( SPRITE *pSprite, XSPRITE *pXSprite );
  31. static void FireballCallback( int /* type */, int nXIndex );
  32. //static void FlareCallback( int /* type */, int nXIndex );
  33. struct VECTORDATA
  34. {
  35. DAMAGE_TYPE damageType;
  36. int damageValue;
  37. int maxDist;
  38. struct
  39. {
  40. int nEffect;
  41. int nSoundId;
  42. } impact[kSurfMax];
  43. };
  44. static VECTORDATA gVectorData[kVectorMax] =
  45. {
  46. // kVectorTine
  47. { kDamageStab, 4, M2X(2.25),
  48. {
  49. { -1, -1 }, // kSurfNone
  50. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  51. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  52. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  53. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  54. { ET_Splash2, -1 }, // kSurfWater
  55. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  56. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  57. { -1, -1 }, // kSurfSnow
  58. { -1, -1 }, // kSurfIce
  59. { -1, -1 }, // kSurfLeaves
  60. { -1, -1 }, // kSurfCloth
  61. { -1, kSfxForkWood }, // kSurfPlant
  62. { -1, -1 }, // kSurfGoo
  63. { -1, -1 }, // kSurfLava
  64. }
  65. },
  66. // kVectorShell
  67. { kDamageBullet, 4, 0,
  68. {
  69. { -1, -1 }, // kSurfNone
  70. { ET_Ricochet1, -1 }, // kSurfStone
  71. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  72. { ET_Ricochet2, -1 }, // kSurfWood
  73. { ET_Squib1, -1 }, // kSurfFlesh
  74. { ET_Splash2, -1 }, // kSurfWater
  75. { ET_Ricochet2, -1 }, // kSurfDirt
  76. { ET_Ricochet2, -1 }, // kSurfClay
  77. { -1, -1 }, // kSurfSnow
  78. { -1, -1 }, // kSurfIce
  79. { -1, -1 }, // kSurfLeaves
  80. { -1, -1 }, // kSurfCloth
  81. { -1, -1 }, // kSurfPlant
  82. { -1, -1 }, // kSurfGoo
  83. { -1, -1 }, // kSurfLava
  84. }
  85. },
  86. // kVectorBullet
  87. { kDamageBullet, 4, 0,
  88. {
  89. { -1, -1 }, // kSurfNone
  90. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  91. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  92. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  93. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  94. { ET_Splash2, -1 }, // kSurfWater
  95. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  96. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  97. { -1, -1 }, // kSurfSnow
  98. { -1, -1 }, // kSurfIce
  99. { -1, -1 }, // kSurfLeaves
  100. { -1, -1 }, // kSurfCloth
  101. { -1, kSfxForkWood }, // kSurfPlant
  102. { -1, -1 }, // kSurfGoo
  103. { -1, -1 }, // kSurfLava
  104. }
  105. },
  106. // kVectorBulletAP
  107. { kDamageBullet, 4, 0,
  108. {
  109. { -1, -1 }, // kSurfNone
  110. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  111. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  112. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  113. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  114. { ET_Splash2, -1 }, // kSurfWater
  115. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  116. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  117. { -1, -1 }, // kSurfSnow
  118. { -1, -1 }, // kSurfIce
  119. { -1, -1 }, // kSurfLeaves
  120. { -1, -1 }, // kSurfCloth
  121. { -1, kSfxForkWood }, // kSurfPlant
  122. { -1, -1 }, // kSurfGoo
  123. { -1, -1 }, // kSurfLava
  124. }
  125. },
  126. // kVectorAxe
  127. { kDamageStab, 20, M2X(2.0),
  128. {
  129. { -1, -1 }, // kSurfNone
  130. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  131. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  132. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  133. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  134. { ET_Splash2, -1 }, // kSurfWater
  135. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  136. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  137. { -1, -1 }, // kSurfSnow
  138. { -1, -1 }, // kSurfIce
  139. { -1, -1 }, // kSurfLeaves
  140. { -1, -1 }, // kSurfCloth
  141. { -1, kSfxForkWood }, // kSurfPlant
  142. { -1, -1 }, // kSurfGoo
  143. { -1, -1 }, // kSurfLava
  144. }
  145. },
  146. // kVectorCleaver
  147. { kDamageStab, 10, M2X(2.0),
  148. {
  149. { -1, -1 }, // kSurfNone
  150. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  151. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  152. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  153. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  154. { ET_Splash2, -1 }, // kSurfWater
  155. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  156. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  157. { -1, -1 }, // kSurfSnow
  158. { -1, -1 }, // kSurfIce
  159. { -1, -1 }, // kSurfLeaves
  160. { -1, -1 }, // kSurfCloth
  161. { -1, kSfxForkWood }, // kSurfPlant
  162. { -1, -1 }, // kSurfGoo
  163. { -1, -1 }, // kSurfLava
  164. }
  165. },
  166. // kVectorClaw
  167. { kDamageStab, 20, M2X(2.0),
  168. {
  169. { -1, -1 }, // kSurfNone
  170. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  171. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  172. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  173. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  174. { ET_Splash2, -1 }, // kSurfWater
  175. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  176. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  177. { -1, -1 }, // kSurfSnow
  178. { -1, -1 }, // kSurfIce
  179. { -1, -1 }, // kSurfLeaves
  180. { -1, -1 }, // kSurfCloth
  181. { -1, kSfxForkWood }, // kSurfPlant
  182. { -1, -1 }, // kSurfGoo
  183. { -1, -1 }, // kSurfLava
  184. }
  185. },
  186. // kVectorHoundBite
  187. { kDamageStab, 10, M2X(1.2),
  188. {
  189. { -1, -1 }, // kSurfNone
  190. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  191. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  192. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  193. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  194. { ET_Splash2, -1 }, // kSurfWater
  195. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  196. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  197. { -1, -1 }, // kSurfSnow
  198. { -1, -1 }, // kSurfIce
  199. { -1, -1 }, // kSurfLeaves
  200. { -1, -1 }, // kSurfCloth
  201. { -1, kSfxForkWood }, // kSurfPlant
  202. { -1, -1 }, // kSurfGoo
  203. { -1, -1 }, // kSurfLava
  204. }
  205. },
  206. // kVectorRatBite
  207. { kDamageStab, 4, M2X(1.8),
  208. {
  209. { -1, -1 }, // kSurfNone
  210. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  211. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  212. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  213. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  214. { ET_Splash2, -1 }, // kSurfWater
  215. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  216. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  217. { -1, -1 }, // kSurfSnow
  218. { -1, -1 }, // kSurfIce
  219. { -1, -1 }, // kSurfLeaves
  220. { -1, -1 }, // kSurfCloth
  221. { -1, kSfxForkWood }, // kSurfPlant
  222. { -1, -1 }, // kSurfGoo
  223. { -1, -1 }, // kSurfLava
  224. }
  225. },
  226. // kVectorSpiderBite
  227. { kDamageStab, 8, M2X(1.2),
  228. {
  229. { -1, -1 }, // kSurfNone
  230. { ET_Ricochet1, kSfxForkStone }, // kSurfStone
  231. { ET_Ricochet1, kSfxForkMetal }, // kSurfMetal
  232. { ET_Ricochet2, kSfxForkWood }, // kSurfWood
  233. { ET_Squib1, kSfxForkFlesh }, // kSurfFlesh
  234. { ET_Splash2, -1 }, // kSurfWater
  235. { ET_Ricochet2, kSfxForkWood }, // kSurfDirt
  236. { ET_Ricochet2, kSfxForkWood }, // kSurfClay
  237. { -1, -1 }, // kSurfSnow
  238. { -1, -1 }, // kSurfIce
  239. { -1, -1 }, // kSurfLeaves
  240. { -1, -1 }, // kSurfCloth
  241. { -1, kSfxForkWood }, // kSurfPlant
  242. { -1, -1 }, // kSurfGoo
  243. { -1, -1 }, // kSurfLava
  244. }
  245. },
  246. };
  247. ITEMDATA gItemData[ kMaxItemTypes ] =
  248. {
  249. /*
  250. {cstat, picnum, sh, pal,xr, yr, stat, type, flags},
  251. */
  252. {0, kPicKey1, -8, 0, 32, 32, kStatItem, kItemKey1, 0},
  253. {0, kPicKey2, -8, 0, 32, 32, kStatItem, kItemKey2, 0},
  254. {0, kPicKey3, -8, 0, 32, 32, kStatItem, kItemKey3, 0},
  255. {0, kPicKey4, -8, 0, 32, 32, kStatItem, kItemKey4, 0},
  256. {0, kPicKey5, -8, 0, 32, 32, kStatItem, kItemKey5, 0},
  257. {0, kPicKey6, -8, 0, 32, 32, kStatItem, kItemKey6, 0},
  258. {0, -1, -8, 0, -1, -1, kStatItem, kItemKey7, 0},
  259. {0, kPicDocBag, -8, 0, 48, 48, kStatItem, kItemDoctorBag, 0},
  260. {0, kPicMedPouch, -8, 0, 40, 40, kStatItem, kItemMedPouch, 0},
  261. {0, kPicEssence, -8, 0, 40, 40, kStatItem, kItemLifeEssence, 0},
  262. {0, kAnmLifeSeed, -8, 0, 40, 40, kStatItem, kItemLifeSeed, 0},
  263. {0, kPicPotion, -8, 0, 40, 40, kStatItem, kItemPotion1, 0},
  264. {0, kAnmFeather, -8, 0, 40, 40, kStatItem, kItemFeatherFall, 0},
  265. {0, kAnmInviso, -8, 0, 40, 40, kStatItem, kItemLtdInvisibility, 0},
  266. {0, kPicInvulnerable, -8, 0, 40, 40, kStatItem, kItemInvulnerability, 0},
  267. {0, kPicJumpBoots, -8, 0, 40, 40, kStatItem, kItemJumpBoots, 0},
  268. {0, kPicRavenFlight, -8, 0, 40, 40, kStatItem, kItemRavenFlight, 0},
  269. {0, kPicGunsAkimbo, -8, 0, 40, 40, kStatItem, kItemGunsAkimbo, 0},
  270. {0, kPicDivingSuit, -8, 0, 80, 64, kStatItem, kItemDivingSuit, 0},
  271. {0, kPicGasMask, -8, 0, 40, 40, kStatItem, kItemGasMask, 0},
  272. {0, kAnmClone, -8, 0, 40, 40, kStatItem, kItemClone, 0},
  273. {0, kPicCrystalBall, -8, 0, 40, 40, kStatItem, kItemCrystalBall, 0},
  274. {0, kPicDecoy, -8, 0, 40, 40, kStatItem, kItemDecoy, 0},
  275. {0, kAnmDoppleganger, -8, 0, 40, 40, kStatItem, kItemDoppleganger, 0},
  276. {0, kAnmReflectShots, -8, 0, 40, 40, kStatItem, kItemReflectiveShots, 0},
  277. {0, kPicRoseGlasses, -8, 0, 40, 40, kStatItem, kItemRoseGlasses, 0},
  278. {0, kAnmCloakNDagger, -8, 0, 64, 64, kStatItem, kItemShadowCloak, 0},
  279. {0, kPicShroom1, -8, 0, 48, 48, kStatItem, kItemShroomRage, 0},
  280. {0, kPicShroom2, -8, 0, 48, 48, kStatItem, kItemShroomDelirium, 0},
  281. {0, kPicShroom3, -8, 0, 48, 48, kStatItem, kItemShroomGrow, 0},
  282. {0, kPicShroom4, -8, 0, 48, 48, kStatItem, kItemShroomShrink, 0},
  283. {0, kPicDeathMask, -8, 0, 40, 40, kStatItem, kItemDeathMask, 0},
  284. {0, kPicGoblet, -8, 0, 40, 40, kStatItem, kItemWineGoblet, 0},
  285. {0, kPicBottle1, -8, 0, 40, 40, kStatItem, kItemWineBottle, 0},
  286. {0, kPicSkullGrail, -8, 0, 40, 40, kStatItem, kItemSkullGrail, 0},
  287. {0, kPicSilverGrail, -8, 0, 40, 40, kStatItem, kItemSilverGrail, 0},
  288. {0, kPicTome1, -8, 0, 40, 40, kStatItem, kItemTome, 0},
  289. {0, kPicBlackChest, -8, 0, 40, 40, kStatItem, kItemBlackChest, 0},
  290. {0, kPicWoodChest, -8, 0, 40, 40, kStatItem, kItemWoodenChest, 0},
  291. {0, kPicAsbestosSuit, -8, 0, 80, 64, kStatItem, kItemAsbestosArmor, 0},
  292. };
  293. AMMOITEMDATA gAmmoItemData[kAmmoItemMax - kAmmoItemBase] =
  294. {
  295. /*
  296. {cstat, picnum, sh, pal,xr, yr, flags, count, ammoType, weaponType},
  297. */
  298. {0, kPicSprayCan, -8, 0, 40, 40, 0, kTimerRate*8, kAmmoSprayCan, kWeaponSprayCan},
  299. {0, kPicTNTStick, -8, 0, 48, 48, 0, 1, kAmmoTNTStick, kWeaponTNT},
  300. {0, kPicTNTPak, -8, 0, 48, 48, 0, 7, kAmmoTNTStick, kWeaponTNT},
  301. {0, kPicTNTBox, -8, 0, 48, 48, 0, 14, kAmmoTNTStick, kWeaponTNT},
  302. {0, kPicTNTProx, -8, 0, 48, 48, 0, 1, kAmmoTNTProximity, kWeaponTNT},
  303. {0, kPicTNTRemote, -8, 0, 48, 48, 0, 1, kAmmoTNTRemote, kWeaponTNT},
  304. {0, kPicTNTTimer, -8, 0, 48, 48, 0, 1, kAmmoTNTStick, kWeaponTNT},
  305. {0, kPicShotShells, -8, 0, 48, 48, 0, 4, kAmmoShell},
  306. {0, kPicShellBox, -8, 0, 48, 48, 0, 16, kAmmoShell},
  307. {0, kPicBullets, -8, 0, 48, 48, 0, 8, kAmmoBullet},
  308. {0, kPicBulletBox, -8, 0, 48, 48, 0, 50, kAmmoBullet},
  309. {0, kPicBulletBoxAP, -8, 0, 48, 48, 0, 50, kAmmoBulletAP},
  310. {0, kPicTommyDrum, -8, 0, 48, 48, 0, 100, kAmmoBullet},
  311. {0, kPicSpear, -8, 0, 48, 48, 0, 1, kAmmoSpear},
  312. {0, kPicSpears, -8, 0, 48, 48, 0, 6, kAmmoSpear},
  313. {0, kPicSpearExplode, -8, 0, 48, 48, 0, 6, kAmmoSpearXP},
  314. {0, kPicFlares, -8, 0, 48, 48, 0, 8, kAmmoFlare},
  315. {0, kPicFlareHE, -8, 0, 48, 48, 0, 8, kAmmoFlare},
  316. {0, kPicFlareBurst, -8, 0, 48, 48, 0, 8, kAmmoFlareSB},
  317. };
  318. WEAPONITEMDATA gWeaponItemData[ kWeaponItemMax - kWeaponItemBase ] =
  319. {
  320. /*
  321. {cstat, picnum, sh, pal,xr, yr, flags, weaponType, ammoType, count },
  322. */
  323. { 0, -1, 0, 0, 0, 0, 0, kWeaponNone, kAmmoNone, 0 },
  324. { 0, kPicShotgun, -8, 0, 48, 48, 0, kWeaponShotgun, kAmmoShell, 8 },
  325. { 0, kPicTommyGun, -8, 0, 48, 48, 0, kWeaponTommy, kAmmoBullet, 50 },
  326. { 0, kPicFlareGun, -8, 0, 48, 48, 0, kWeaponFlare, kAmmoFlare, 8 },
  327. { 0, kPicVoodooDoll, -8, 0, 48, 48, 0, kWeaponVoodoo, kAmmoVoodoo, 1 },
  328. { 0, kPicSpearGun, -8, 0, 48, 48, 0, kWeaponSpear, kAmmoSpear, 6 },
  329. { 0, kPicShadowGun, -8, 0, 48, 48, 0, kWeaponShadow, kAmmoNone, 0 },
  330. { 0, -1, 0, 0, 0, 0, 0, kWeaponPitchfork, kAmmoNone, 0 }, // don't actually pick this up
  331. { 0, kPicSprayCan, -8, 0, 48, 48, 0, kWeaponSprayCan, kAmmoSprayCan, kTimerRate*8},
  332. { 0, kPicTNTStick, -8, 0, 48, 48, 0, kWeaponTNT, kAmmoTNTStick, 1},
  333. };
  334. struct MissileType {
  335. short picnum;
  336. int velocity;
  337. int angleOfs;
  338. uchar xrepeat;
  339. uchar yrepeat;
  340. char shade;
  341. } missileInfo[] = {
  342. { kAnmButcherKnife, (M2X(14.0) << 4) / kTimerRate, kAngle90, 40, 40, -16 }, // kMissileButcherKnife
  343. { kAnmFlare, (M2X(20.0) << 4) / kTimerRate, 0, 32, 32, -128 }, // kMissileFlare
  344. { kAnmFlare, (M2X(20.0) << 4) / kTimerRate, 0, 32, 32, -128 }, // kMissileExplodingFlare
  345. { kAnmFlare, (M2X(20.0) << 4) / kTimerRate, 0, 32, 32, -128 }, // kMissileStarburstFlare
  346. { 0, (M2X(4.0) << 4) / kTimerRate, 0, 24, 24, -128 }, // kMissileSprayFlame
  347. { 0, (M2X(16.0) << 4) / kTimerRate, 0, 32, 32, -128 }, // kMissileFireball
  348. { kAnmSpear, (M2X(16.0) << 4) / kTimerRate, kAngle270, 64, 64, -8 }, // kMissileSpear // 18.0
  349. { kAnmEctoSkull, (M2X(16.0) << 4) / kTimerRate, 0, 32, 32, -24 }, // kMissileEctoSkull
  350. { 0, (M2X(6.0) << 4) / kTimerRate, 0, 24, 24, -128 }, // kMissileHoundFire
  351. { 0, (M2X(12.0) << 4) / kTimerRate, 0, 8, 8, 0 }, // kMissileGreenPuke
  352. { 0, (M2X(12.0) << 4) / kTimerRate, 0, 8, 8, 0 }, // kMissileRedPuke
  353. };
  354. static int dragTable[] =
  355. {
  356. 0,
  357. 0x0C00, // kDepthTread
  358. 0x1A00, // kDepthWade
  359. 0x1A00, // kDepthSwim
  360. };
  361. // miscellaneous effects
  362. enum
  363. {
  364. kSeqSprayFlame1 = 0,
  365. kSeqSprayFlame2,
  366. kSeqSkull,
  367. kSeqExplodeC1L, // large concussion on ground
  368. kSeqExplodeC1M, // medium concussion on ground
  369. kSeqExplodeC1S, // small concussion on ground
  370. kSeqExplodeC2L, // large concussion in air
  371. kSeqExplodeC2M, // medium concussion in air
  372. kSeqExplodeC2S, // small concussion in air
  373. kSeqExplodeC2T, // tiny concussion in air
  374. kSeqSplash1,
  375. kSeqSplash2,
  376. kSeqSplash3, // blood spash
  377. kSeqRicochet1,
  378. kSeqGoreWing,
  379. kSeqGoreHead,
  380. kSeqBarrel,
  381. kSeqBloodPool,
  382. kSeqRespawn,
  383. kSeqFlareSmoke,
  384. kSeqSquib1,
  385. kSeqFluorescentLight,
  386. kSeqClearGlass,
  387. kSeqStainedGlass,
  388. kSeqWeb,
  389. kSeqBeam,
  390. kSeqVase1,
  391. kSeqVase2,
  392. kSeqZombieBones,
  393. kSeqSkullExplode,
  394. kSeqMetalGrate1,
  395. kSeqFireball,
  396. kSeqBoneBreak,
  397. kSeqBurningTree1,
  398. kSeqBurningTree2,
  399. kSeqHoundFire,
  400. kSeqMGunDead,
  401. kSeqRicochet2,
  402. kSeqEffectMax,
  403. };
  404. struct THINGINFO
  405. {
  406. short startHealth;
  407. short mass; // in KG
  408. char clipdist;
  409. ushort flags;
  410. int damageShift[kDamageMax]; // use to indicate resistance to damage types
  411. };
  412. static THINGINFO thingInfo[kThingMax - kThingBase] =
  413. {
  414. { // kThingTNTBarrel
  415. 40,
  416. 150,
  417. 32,
  418. kAttrMove | kAttrGravity,
  419. {
  420. kNoDamage, // kDamagePummel
  421. 0, // kDamageFall
  422. 0, // kDamageBurn
  423. 0, // kDamageBullet
  424. 1, // kDamageStab
  425. 0, // kDamageExplode
  426. kNoDamage, // kDamageGas
  427. kNoDamage, // kDamageDrown
  428. kNoDamage, // kDamageSpirit
  429. kNoDamage, // kDamageVoodoo
  430. },
  431. },
  432. { // kThingTNTProxArmed
  433. 5,
  434. 5,
  435. 16,
  436. kAttrMove | kAttrGravity,
  437. {
  438. kNoDamage, // kDamagePummel
  439. kNoDamage, // kDamageFall
  440. 0, // kDamageBurn
  441. 0, // kDamageBullet
  442. kNoDamage, // kDamageStab
  443. 0, // kDamageExplode
  444. kNoDamage, // kDamageGas
  445. kNoDamage, // kDamageDrown
  446. kNoDamage, // kDamageSpirit
  447. kNoDamage, // kDamageVoodoo
  448. },
  449. },
  450. { // kThingTNTRemArmed
  451. 5,
  452. 5,
  453. 16,
  454. kAttrMove | kAttrGravity,
  455. {
  456. kNoDamage, // kDamagePummel
  457. kNoDamage, // kDamageFall
  458. 0, // kDamageBurn
  459. 0, // kDamageBullet
  460. kNoDamage, // kDamageStab
  461. 0, // kDamageExplode
  462. kNoDamage, // kDamageGas
  463. kNoDamage, // kDamageDrown
  464. kNoDamage, // kDamageSpirit
  465. kNoDamage, // kDamageVoodoo
  466. },
  467. },
  468. { // kThingBlueVase
  469. 1,
  470. 20,
  471. 32,
  472. kAttrMove | kAttrGravity,
  473. {
  474. kNoDamage, // kDamagePummel
  475. 0, // kDamageFall
  476. kNoDamage, // kDamageBurn
  477. 0, // kDamageBullet
  478. 0, // kDamageStab
  479. 0, // kDamageExplode
  480. kNoDamage, // kDamageGas
  481. kNoDamage, // kDamageDrown
  482. kNoDamage, // kDamageSpirit
  483. kNoDamage, // kDamageVoodoo
  484. },
  485. },
  486. { // kThingBrownVase
  487. 1,
  488. 150,
  489. 32,
  490. kAttrMove | kAttrGravity,
  491. {
  492. kNoDamage, // kDamagePummel
  493. 0, // kDamageFall
  494. kNoDamage, // kDamageBurn
  495. 0, // kDamageBullet
  496. 0, // kDamageStab
  497. 0, // kDamageExplode
  498. kNoDamage, // kDamageGas
  499. kNoDamage, // kDamageDrown
  500. kNoDamage, // kDamageSpirit
  501. kNoDamage, // kDamageVoodoo
  502. },
  503. },
  504. { // kThingCrateFace
  505. 10,
  506. 0,
  507. 0,
  508. 0,
  509. {
  510. kNoDamage, // kDamagePummel
  511. kNoDamage, // kDamageFall
  512. kNoDamage, // kDamageBurn
  513. kNoDamage, // kDamageBullet
  514. kNoDamage, // kDamageStab
  515. 0, // kDamageExplode
  516. kNoDamage, // kDamageGas
  517. kNoDamage, // kDamageDrown
  518. kNoDamage, // kDamageSpirit
  519. kNoDamage, // kDamageVoodoo
  520. },
  521. },
  522. { // kThingClearGlass
  523. 1,
  524. 0,
  525. 0,
  526. 0,
  527. {
  528. 0, // kDamagePummel
  529. 0, // kDamageFall
  530. kNoDamage, // kDamageBurn
  531. 0, // kDamageBullet
  532. 0, // kDamageStab
  533. 0, // kDamageExplode
  534. kNoDamage, // kDamageGas
  535. kNoDamage, // kDamageDrown
  536. kNoDamage, // kDamageSpirit
  537. kNoDamage, // kDamageVoodoo
  538. },
  539. },
  540. { // kThingFluorescent
  541. 1,
  542. 0,
  543. 0,
  544. 0,
  545. {
  546. 0, // kDamagePummel
  547. kNoDamage, // kDamageFall
  548. kNoDamage, // kDamageBurn
  549. 0, // kDamageBullet
  550. 0, // kDamageStab
  551. 0, // kDamageExplode
  552. kNoDamage, // kDamageGas
  553. kNoDamage, // kDamageDrown
  554. kNoDamage, // kDamageSpirit
  555. kNoDamage, // kDamageVoodoo
  556. },
  557. },
  558. { // kThingWallCrack
  559. 8,
  560. 0,
  561. 0,
  562. 0,
  563. {
  564. kNoDamage, // kDamagePummel
  565. kNoDamage, // kDamageFall
  566. kNoDamage, // kDamageBurn
  567. kNoDamage, // kDamageBullet
  568. kNoDamage, // kDamageStab
  569. 0, // kDamageExplode
  570. kNoDamage, // kDamageGas
  571. kNoDamage, // kDamageDrown
  572. kNoDamage, // kDamageSpirit
  573. kNoDamage, // kDamageVoodoo
  574. },
  575. },
  576. { // kThingWoodBeam
  577. 8,
  578. 0,
  579. 0,
  580. 0,
  581. {
  582. 0, // kDamagePummel
  583. kNoDamage, // kDamageFall
  584. kNoDamage, // kDamageBurn
  585. 0, // kDamageBullet
  586. 0, // kDamageStab
  587. 0, // kDamageExplode
  588. kNoDamage, // kDamageGas
  589. kNoDamage, // kDamageDrown
  590. kNoDamage, // kDamageSpirit
  591. kNoDamage, // kDamageVoodoo
  592. },
  593. },
  594. { // kThingWeb
  595. 4,
  596. 0,
  597. 0,
  598. 0,
  599. {
  600. 0, // kDamagePummel
  601. kNoDamage, // kDamageFall
  602. 0, // kDamageBurn
  603. 1, // kDamageBullet
  604. 0, // kDamageStab
  605. 0, // kDamageExplode
  606. kNoDamage, // kDamageGas
  607. kNoDamage, // kDamageDrown
  608. kNoDamage, // kDamageSpirit
  609. kNoDamage, // kDamageVoodoo
  610. },
  611. },
  612. { // kThingMetalGrate1
  613. 20,
  614. 0,
  615. 0,
  616. 0,
  617. {
  618. 3, // kDamagePummel
  619. kNoDamage, // kDamageFall
  620. kNoDamage, // kDamageBurn
  621. 2, // kDamageBullet
  622. 4, // kDamageStab
  623. 1, // kDamageExplode
  624. kNoDamage, // kDamageGas
  625. kNoDamage, // kDamageDrown
  626. kNoDamage, // kDamageSpirit
  627. kNoDamage, // kDamageVoodoo
  628. },
  629. },
  630. { // kThingBurnableTree
  631. 1,
  632. 0,
  633. 0,
  634. 0,
  635. {
  636. kNoDamage, // kDamagePummel
  637. kNoDamage, // kDamageFall
  638. 0, // kDamageBurn
  639. kNoDamage, // kDamageBullet
  640. kNoDamage, // kDamageStab
  641. kNoDamage, // kDamageExplode
  642. kNoDamage, // kDamageGas
  643. kNoDamage, // kDamageDrown
  644. 0, // kDamageSpirit
  645. kNoDamage, // kDamageVoodoo
  646. },
  647. },
  648. { // kThingMachineGun
  649. 50,
  650. 0,
  651. 0,
  652. 0,
  653. {
  654. kNoDamage, // kDamagePummel
  655. kNoDamage, // kDamageFall
  656. kNoDamage, // kDamageBurn
  657. 2, // kDamageBullet
  658. 2, // kDamageStab
  659. 1, // kDamageExplode
  660. kNoDamage, // kDamageGas
  661. kNoDamage, // kDamageDrown
  662. kNoDamage, // kDamageSpirit
  663. kNoDamage, // kDamageVoodoo
  664. },
  665. },
  666. { // kThingTNTStick
  667. 5,
  668. 2,
  669. 16,
  670. kAttrMove | kAttrGravity,
  671. {
  672. 0, // kDamagePummel
  673. kNoDamage, // kDamageFall
  674. 0, // kDamageBurn
  675. 0, // kDamageBullet
  676. 0, // kDamageStab
  677. 0, // kDamageExplode
  678. kNoDamage, // kDamageGas
  679. kNoDamage, // kDamageDrown
  680. kNoDamage, // kDamageSpirit
  681. kNoDamage, // kDamageVoodoo
  682. },
  683. },
  684. { // kThingTNTBundle
  685. 5,
  686. 14,
  687. 16,
  688. kAttrMove | kAttrGravity,
  689. {
  690. 0, // kDamagePummel
  691. kNoDamage, // kDamageFall
  692. 0, // kDamageBurn
  693. 0, // kDamageBullet
  694. 0, // kDamageStab
  695. 0, // kDamageExplode
  696. kNoDamage, // kDamageGas
  697. kNoDamage, // kDamageDrown
  698. kNoDamage, // kDamageSpirit
  699. kNoDamage, // kDamageVoodoo
  700. },
  701. },
  702. { // kThingBoneClub
  703. 5,
  704. 6,
  705. 16,
  706. kAttrMove | kAttrGravity,
  707. {
  708. kNoDamage, // kDamagePummel
  709. kNoDamage, // kDamageFall
  710. kNoDamage, // kDamageBurn
  711. kNoDamage, // kDamageBullet
  712. kNoDamage, // kDamageStab
  713. kNoDamage, // kDamageExplode
  714. kNoDamage, // kDamageGas
  715. kNoDamage, // kDamageDrown
  716. kNoDamage, // kDamageSpirit
  717. kNoDamage, // kDamageVoodoo
  718. },
  719. },
  720. { // kThingZombieBones
  721. 8,
  722. 3,
  723. 16,
  724. kAttrMove | kAttrGravity,
  725. {
  726. 0, // kDamagePummel
  727. 0, // kDamageFall
  728. kNoDamage, // kDamageBurn
  729. 0, // kDamageBullet
  730. 0, // kDamageStab
  731. 0, // kDamageExplode
  732. kNoDamage, // kDamageGas
  733. kNoDamage, // kDamageDrown
  734. kNoDamage, // kDamageSpirit
  735. kNoDamage, // kDamageVoodoo
  736. },
  737. },
  738. { // kThingWaterDrip
  739. 0, // startHealth
  740. 1, // mass
  741. 1, // clipDist
  742. kAttrGravity,
  743. {
  744. kNoDamage, // kDamagePummel
  745. kNoDamage, // kDamageFall
  746. kNoDamage, // kDamageBurn
  747. kNoDamage, // kDamageBullet
  748. kNoDamage, // kDamageStab
  749. kNoDamage, // kDamageExplode
  750. kNoDamage, // kDamageGas
  751. kNoDamage, // kDamageDrown
  752. kNoDamage, // kDamageSpirit
  753. kNoDamage, // kDamageVoodoo
  754. },
  755. },
  756. { // kThingBloodDrip
  757. 0, // startHealth
  758. 1, // mass
  759. 1, // clipDist
  760. kAttrGravity,
  761. {
  762. kNoDamage, // kDamagePummel
  763. kNoDamage, // kDamageFall
  764. kNoDamage, // kDamageBurn
  765. kNoDamage, // kDamageBullet
  766. kNoDamage, // kDamageStab
  767. kNoDamage, // kDamageExplode
  768. kNoDamage, // kDamageGas
  769. kNoDamage, // kDamageDrown
  770. kNoDamage, // kDamageSpirit
  771. kNoDamage, // kDamageVoodoo
  772. },
  773. },
  774. { // kThingBubble
  775. 0, // startHealth
  776. -1, // mass
  777. 1, // clipDist
  778. kAttrMove,
  779. {
  780. kNoDamage, // kDamagePummel
  781. kNoDamage, // kDamageFall
  782. kNoDamage, // kDamageBurn
  783. kNoDamage, // kDamageBullet
  784. kNoDamage, // kDamageStab
  785. kNoDamage, // kDamageExplode
  786. kNoDamage, // kDamageGas
  787. kNoDamage, // kDamageDrown
  788. kNoDamage, // kDamageSpirit
  789. kNoDamage, // kDamageVoodoo
  790. },
  791. },
  792. { // kThingBubbles
  793. 0, // startHealth
  794. -1, // mass
  795. 1, // clipDist
  796. kAttrMove,
  797. {
  798. kNoDamage, // kDamagePummel
  799. kNoDamage, // kDamageFall
  800. kNoDamage, // kDamageBurn
  801. kNoDamage, // kDamageBullet
  802. kNoDamage, // kDamageStab
  803. kNoDamage, // kDamageExplode
  804. kNoDamage, // kDamageGas
  805. kNoDamage, // kDamageDrown
  806. kNoDamage, // kDamageSpirit
  807. kNoDamage, // kDamageVoodoo
  808. },
  809. },
  810. { // kThingGibSmall
  811. 0, // startHealth
  812. 2, // mass
  813. 4, // clipDist
  814. kAttrMove | kAttrGravity,
  815. {
  816. kNoDamage, // kDamagePummel
  817. kNoDamage, // kDamageFall
  818. kNoDamage, // kDamageBurn
  819. kNoDamage, // kDamageBullet
  820. kNoDamage, // kDamageStab
  821. kNoDamage, // kDamageExplode
  822. kNoDamage, // kDamageGas
  823. kNoDamage, // kDamageDrown
  824. kNoDamage, // kDamageSpirit
  825. kNoDamage, // kDamageVoodoo
  826. },
  827. },
  828. };
  829. void actAllocateSpares( void )
  830. {
  831. /*
  832. dprintf("Creating spare sprites\n");
  833. for (int i = 0; i < kMaxSpareSprites; i++)
  834. {
  835. int nSprite = insertsprite( 0, kStatSpares );
  836. dassert(nSprite != -1);
  837. dbInsertXSprite(nSprite);
  838. sprite[nSprite].cstat |= kSpriteInvisible;
  839. }
  840. */
  841. }
  842. /*******************************************************************************
  843. FUNCTION: actInit()
  844. DESCRIPTION: Initialize the actor subsystem. Locks all sequences, and
  845. preloads all tiles for sequences used in the map.
  846. NOTES:
  847. *******************************************************************************/
  848. void actInit( void )
  849. {
  850. int nSprite;
  851. BOOL used[kDudeMax - kDudeBase];
  852. memset(used, FALSE, sizeof(used));
  853. // allocate sprites to use for effects
  854. actAllocateSpares();
  855. // see which dudes are present
  856. for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  857. {
  858. SPRITE *pSprite = &sprite[nSprite];
  859. if ( pSprite->type < kDudeBase || pSprite->type >= kDudeMax )
  860. {
  861. dprintf("ERROR IN SPRITE %i\n", nSprite);
  862. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  863. }
  864. used[pSprite->type - kDudeBase] = TRUE;
  865. }
  866. // preload tiles for dude sequences
  867. dprintf("Preload dude sequence tiles\n");
  868. for (int i = 0; i < kDudeMax - kDudeBase; i++)
  869. {
  870. if ( used[i] )
  871. {
  872. // only preload art for idle sequence
  873. // if ( dudeInfo[i].pSeq[0] != NULL )
  874. // dudeInfo[i].pSeq[0]->Preload();
  875. }
  876. }
  877. // initialize all dudes
  878. for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  879. {
  880. SPRITE *pSprite = &sprite[nSprite];
  881. int nXSprite = pSprite->extra;
  882. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  883. XSPRITE *pXSprite = &xsprite[nXSprite];
  884. int dudeIndex = pSprite->type - kDudeBase;
  885. pSprite->cstat |= kSpriteBlocking | kSpriteHitscan;
  886. pSprite->clipdist = dudeInfo[dudeIndex].clipdist;
  887. pSprite->flags = kAttrMove | kAttrGravity | kAttrFalling;
  888. pSprite->xvel = pSprite->yvel = pSprite->zvel = 0;
  889. pXSprite->health = dudeInfo[dudeIndex].startHealth << 4;
  890. if ( gSysRes.Lookup( dudeInfo[dudeIndex].seqStartID + kSeqDudeIdle, ".SEQ") != NULL )
  891. seqSpawn(dudeInfo[dudeIndex].seqStartID + kSeqDudeIdle, SS_SPRITE, nXSprite);
  892. }
  893. // initialize all things
  894. for (nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  895. {
  896. SPRITE *pSprite = &sprite[nSprite];
  897. int nXSprite = pSprite->extra;
  898. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  899. XSPRITE *pXSprite = &xsprite[nXSprite];
  900. int thingIndex = pSprite->type - kThingBase;
  901. pSprite->cstat |= kSpriteBlocking; // | kSpriteHitscan should be handled in BSTUB by hitbit
  902. pSprite->clipdist = thingInfo[thingIndex].clipdist;
  903. pSprite->flags = thingInfo[thingIndex].flags;
  904. pSprite->xvel = pSprite->yvel = pSprite->zvel = 0;
  905. pXSprite->health = thingInfo[thingIndex].startHealth << 4;
  906. switch(pSprite->type)
  907. {
  908. case kThingMachineGun:
  909. pXSprite->state = 0; // these must start off
  910. break;
  911. default:
  912. pXSprite->state = 1;
  913. break;
  914. }
  915. }
  916. aiInit();
  917. }
  918. #define kGlobalForceShift 26 // arbitrary scale for all concussion
  919. static void ConcussSprite( int nSource, int nSprite, int x, int y, int z, int ticks )
  920. {
  921. SPRITE *pSprite = &sprite[nSprite];
  922. int dx = pSprite->x - x;
  923. int dy = pSprite->y - y;
  924. int dz = (pSprite->z - z) >> 4;
  925. int dist2 = ClipLow(dx * dx + dy * dy + dz * dz, 32 << 4);
  926. int nTile = pSprite->picnum;
  927. int area = tilesizx[nTile] * pSprite->xrepeat * tilesizy[nTile] * pSprite->yrepeat >> 12;
  928. int force = divscale(ticks, dist2, kGlobalForceShift);
  929. if ( pSprite->flags & kAttrMove )
  930. {
  931. int mass = 0;
  932. if ( pSprite->type >= kDudeBase && pSprite->type < kDudeMax )
  933. mass = dudeInfo[pSprite->type - kDudeBase].mass;
  934. else if ( pSprite->type >= kThingBase && pSprite->type < kThingMax )
  935. mass = thingInfo[pSprite->type - kThingBase].mass;
  936. else
  937. ThrowError("Unexpected type encountered in ConcussSprite()", ES_ERROR);
  938. dassert(mass != 0);
  939. int impulse = muldiv(force, area, qabs(mass));
  940. dx = mulscale16(impulse, dx);
  941. dy = mulscale16(impulse, dy);
  942. dz = mulscale16(impulse, dz);
  943. pSprite->xvel += dx;
  944. pSprite->yvel += dy;
  945. pSprite->zvel += dz;
  946. }
  947. actDamageSprite(nSource, nSprite, kDamageExplode, force);
  948. }
  949. /*******************************************************************************
  950. FUNCTION: ReflectVector()
  951. DESCRIPTION: Reflects a vector off a wall
  952. PARAMETERS: nFraction is elasticity (0x10000 == perfectly elastic)
  953. *******************************************************************************/
  954. static void ReflectVector( short *dx, short *dy, int nWall, int nFraction )
  955. {
  956. // calculate normal for wall
  957. int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4;
  958. int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4;
  959. int dotProduct = *dx * nx + *dy * ny;
  960. int length2 = nx * nx + ny * ny;
  961. dassert(length2 > 0);
  962. int dot2 = dotProduct + mulscale16r(dotProduct, nFraction);
  963. int sd = divscale16(dot2, length2);
  964. *dx -= mulscale16r(nx, sd);
  965. *dy -= mulscale16r(ny, sd);
  966. }
  967. static void DropPickupObject( int nActor, int nObject )
  968. {
  969. dassert( nActor >= 0 && nActor < kMaxSprites && sprite[nActor].statnum < kMaxStatus );
  970. dassert( (nObject >= kItemBase && nObject < kItemMax)
  971. || (nObject >= kAmmoItemBase && nObject < kAmmoItemMax)
  972. || (nObject >= kWeaponItemBase && nObject < kWeaponItemMax) );
  973. // create a sprite for the dropped ammo
  974. SPRITE *pActor = &sprite[nActor];
  975. int nSprite = actSpawnSprite( pActor->sectnum, pActor->x, pActor->y, sector[pActor->sectnum].floorz, kStatItem, FALSE );
  976. SPRITE *pSprite = &sprite[ nSprite ];
  977. if ( nObject >= kItemBase && nObject < kItemMax )
  978. {
  979. int nItemIndex = nObject - kItemBase;
  980. pSprite->type = (short)nObject;
  981. pSprite->picnum = gItemData[nItemIndex].picnum;
  982. pSprite->shade = gItemData[nItemIndex].shade ;
  983. pSprite->xrepeat = gItemData[nItemIndex].xrepeat;
  984. pSprite->yrepeat = gItemData[nItemIndex].yrepeat;
  985. if (nObject >= kItemKey1 && nObject <= kItemKey7)
  986. {
  987. // PF/NN: should this be in bloodbath too?
  988. if ( gNetMode == kNetModeCoop ) // force permanent keys in Coop mode
  989. {
  990. dbInsertXSprite( nSprite );
  991. XSPRITE *pXSprite = &xsprite[ pSprite->extra ];
  992. pXSprite->respawn = kRespawnPermanent;
  993. pXSprite->respawnTime = 0;
  994. }
  995. }
  996. }
  997. else if ( nObject >= kAmmoItemBase && nObject < kAmmoItemMax )
  998. {
  999. int nAmmoIndex = nObject - kAmmoItemBase;
  1000. pSprite->type = (short)nObject;
  1001. pSprite->picnum = gAmmoItemData[nAmmoIndex].picnum;
  1002. pSprite->shade = gAmmoItemData[nAmmoIndex].shade ;
  1003. pSprite->xrepeat = gAmmoItemData[nAmmoIndex].xrepeat;
  1004. pSprite->yrepeat = gAmmoItemData[nAmmoIndex].yrepeat;
  1005. }
  1006. else if ( nObject >= kWeaponItemBase && nObject < kWeaponItemMax )
  1007. {
  1008. int nWeaponIndex = nObject - kWeaponItemBase;
  1009. pSprite->type = (short)nObject;
  1010. pSprite->picnum = gWeaponItemData[nWeaponIndex].picnum;
  1011. pSprite->shade = gWeaponItemData[nWeaponIndex].shade ;
  1012. pSprite->xrepeat = gWeaponItemData[nWeaponIndex].xrepeat;
  1013. pSprite->yrepeat = gWeaponItemData[nWeaponIndex].yrepeat;
  1014. }
  1015. else
  1016. ThrowError("Unhandled nObject passed to DropPickupObject()", ES_ERROR);
  1017. }
  1018. BOOL actHealDude( XSPRITE *pXDude, int healValue, int maxHealthClip)
  1019. {
  1020. dassert(pXDude != NULL);
  1021. healValue <<= 4; // fix this later in the calling code
  1022. maxHealthClip <<= 4;
  1023. if ( pXDude->health < maxHealthClip )
  1024. {
  1025. pXDude->health = ClipHigh(pXDude->health + healValue, maxHealthClip);
  1026. dprintf("Health=%d\n", pXDude->health >> 4);
  1027. return TRUE;
  1028. }
  1029. return FALSE;
  1030. }
  1031. void actKillSprite( int nSource, int nSprite, DAMAGE_TYPE damageType )
  1032. {
  1033. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  1034. SPRITE *pSprite = &sprite[nSprite];
  1035. SPRITE *pSource = &sprite[nSource];
  1036. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  1037. int dudeIndex = pSprite->type - kDudeBase;
  1038. DUDEINFO *pDudeInfo = &dudeInfo[dudeIndex];
  1039. int nXSprite = pSprite->extra;
  1040. dassert(nXSprite > 0);
  1041. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  1042. pXSprite->moveState = kMoveStill;
  1043. // handle first cerberus head death
  1044. if (pSprite->type == kDudeCerberus)
  1045. {
  1046. seqSpawn(dudeInfo[dudeIndex].seqStartID + kSeqDudeDeath1, SS_SPRITE, nXSprite);
  1047. return;
  1048. }
  1049. actPostSprite( nSprite, kStatThing );
  1050. trTriggerSprite( nSprite, pXSprite, kCommandOff ); // trigger death message
  1051. pSprite->flags |= kAttrMove | kAttrGravity | kAttrFalling;
  1052. if ( IsPlayerSprite(nSprite) )
  1053. {
  1054. PLAYER *pPlayer = &gPlayer[pSprite->type - kDudePlayer1];
  1055. powerupClear( pPlayer );
  1056. dprintf("health = %i\n",pXSprite->health);
  1057. if (pXSprite->health == 0)
  1058. pPlayer->deathTime = 0;
  1059. if ( IsPlayerSprite(nSource) )
  1060. {
  1061. int nKilledIndex = pSprite->type - kDudePlayer1;
  1062. int nKillerIndex = pSource->type - kDudePlayer1;
  1063. PLAYER *pFragger = &gPlayer[nKillerIndex];
  1064. if (nSource == nSprite) // fragged yourself, eh?
  1065. {
  1066. pPlayer->fragCount--;
  1067. pPlayer->fragInfo[nKillerIndex]--; // frags against self is negative
  1068. }
  1069. else
  1070. {
  1071. pFragger->fragCount++;
  1072. pFragger->fragInfo[nKilledIndex]++; // frags against others are positive
  1073. }
  1074. }
  1075. // drop pickup items
  1076. for (int i = 1; i < 8; i++)
  1077. if ( pPlayer->hasKey[i] )
  1078. DropPickupObject(nSprite, kItemKey1 + i - 1);
  1079. if ( pPlayer->hasWeapon[kWeaponShotgun] )
  1080. DropPickupObject(nSprite, kWeaponItemShotgun);
  1081. if ( pPlayer->hasWeapon[kWeaponTommy] )
  1082. DropPickupObject(nSprite, kWeaponItemTommyGun);
  1083. if ( pPlayer->hasWeapon[kWeaponFlare] )
  1084. DropPickupObject(nSprite, kWeaponItemFlareGun);
  1085. if ( pPlayer->hasWeapon[kWeaponSpear] )
  1086. DropPickupObject(nSprite, kWeaponItemSpearGun);
  1087. if ( pPlayer->hasWeapon[kWeaponShadow] )
  1088. DropPickupObject(nSprite, kWeaponItemShadowGun);
  1089. }
  1090. if ( pXSprite->key > 0 )
  1091. DropPickupObject( nSprite, kItemKey1 + pXSprite->key - 1 );
  1092. int deathType;
  1093. switch (damageType)
  1094. {
  1095. case kDamageFall:
  1096. case kDamageExplode:
  1097. deathType = kSeqDudeDeath2;
  1098. // sfxStart3DSound(nXSprite, kSfxThingSplat);
  1099. break;
  1100. case kDamageBurn:
  1101. deathType = kSeqDudeDeath3;
  1102. // sfxStart3DSound(nXSprite, kSfxThingBurn);
  1103. break;
  1104. default:
  1105. deathType = kSeqDudeDeath1;
  1106. break;
  1107. }
  1108. // are we missing this sequence? if so, just delete it
  1109. if ( gSysRes.Lookup( dudeInfo[dudeIndex].seqStartID + deathType, ".SEQ") == NULL )
  1110. {
  1111. dprintf("sprite missing death sequence: deleted\n");
  1112. seqKill(SS_SPRITE, nXSprite); // make sure we remove any active sequence
  1113. actPostSprite( nSprite, kStatFree );
  1114. return;
  1115. }
  1116. switch (pSprite->type)
  1117. {
  1118. case kDudeAxeZombie:
  1119. if (pSprite->owner >= 0)
  1120. {
  1121. PLAYER *pPlayer = &gPlayer[sprite[pSprite->owner].type - kDudePlayer1];
  1122. playerDeleteLackey( pPlayer, nSprite );
  1123. }
  1124. seqSpawn(dudeInfo[dudeIndex].seqStartID + deathType, SS_SPRITE, nXSprite);
  1125. break;
  1126. case kDudeFatZombie:
  1127. // if ( damageType == kDamageBurn )
  1128. // {
  1129. // int thingIndex = kThingZombieBones - kThingBase;
  1130. //
  1131. // pSprite->type = kThingZombieBones;
  1132. // pSprite->clipdist = thingInfo[thingIndex].clipdist;
  1133. // pSprite->flags = thingInfo[thingIndex].flags;
  1134. // pSprite->xvel = pSprite->yvel = pSprite->zvel = 0;
  1135. // pXSprite->health = thingInfo[thingIndex].startHealth << 4;
  1136. // }
  1137. seqSpawn(dudeInfo[dudeIndex].seqStartID + deathType, SS_SPRITE, nXSprite);
  1138. break;
  1139. default:
  1140. dprintf("spawning sprite %i death sequence %x\n", nSprite, dudeInfo[dudeIndex].seqStartID + deathType);
  1141. seqSpawn(dudeInfo[dudeIndex].seqStartID + deathType, SS_SPRITE, nXSprite);
  1142. break;
  1143. }
  1144. // drop any items or weapons
  1145. if (pSprite->type == kDudeTommyCultist)
  1146. {
  1147. int nDropCheck = Random(100);
  1148. // constants? table?
  1149. if (nDropCheck < 80)
  1150. DropPickupObject( nSprite, kAmmoItemBullets );
  1151. else if (nDropCheck < 95)
  1152. DropPickupObject( nSprite, kAmmoItemBulletBox );
  1153. else
  1154. DropPickupObject( nSprite, kWeaponItemTommyGun );
  1155. }
  1156. else if (pSprite->type == kDudeShotgunCultist)
  1157. {
  1158. int nDropCheck = Random(100);
  1159. if (nDropCheck < 40)
  1160. DropPickupObject( nSprite, kAmmoItemShells );
  1161. else if (nDropCheck < 75)
  1162. DropPickupObject( nSprite, kAmmoItemShellBox );
  1163. else
  1164. DropPickupObject( nSprite, kWeaponItemShotgun );
  1165. }
  1166. // SpawnGibs( nSprite, pXSprite );
  1167. // gib generator
  1168. if ( damageType == kDamageExplode )
  1169. {
  1170. int angle, velocity = 120;
  1171. // thing gibs
  1172. for (int i = 0; i < kGibMax && pDudeInfo->gib[i].chance > 0; i++)
  1173. {
  1174. if ( Random(256) < pDudeInfo->gib[i].chance )
  1175. {
  1176. int nGib = actCloneSprite(pSprite);
  1177. changespritestat( (short)nGib, kStatThing );
  1178. SPRITE *pGib = &sprite[nGib];
  1179. angle = Random(kAngle360);
  1180. pGib->type = kThingGibSmall;
  1181. pGib->picnum = pDudeInfo->gib[i].tile;
  1182. pGib->xvel += mulscale30(velocity, Cos(angle));
  1183. pGib->yvel += mulscale30(velocity, Sin(angle));
  1184. pGib->zvel -= 128; // toss it in the air a bit
  1185. pGib->cstat &= ~kSpriteBlocking & ~kSpriteHitscan;
  1186. pGib->flags = kAttrMove | kAttrGravity | kAttrFalling;
  1187. pGib->pal = kPLUNormal;
  1188. }
  1189. }
  1190. // debris gibs
  1191. for (i = 0; i < 50; i++)
  1192. {
  1193. int nGib = actCloneSprite(pSprite);
  1194. changespritestat( (short)nGib, kStatDebris);
  1195. SPRITE *pGib = &sprite[nGib];
  1196. pGib->picnum = 2053; // "worm" giblet
  1197. pGib->xvel += BiRandom(500);
  1198. pGib->yvel += BiRandom(500);
  1199. pGib->zvel += BiRandom(500);
  1200. pGib->cstat &= ~kSpriteBlocking & ~kSpriteHitscan;
  1201. pGib->flags = kAttrMove | kAttrGravity | kAttrFalling;
  1202. pGib->pal = kPLUNormal;
  1203. }
  1204. }
  1205. }
  1206. void actDamageSprite( int nSource, int nSprite, DAMAGE_TYPE nDamageType, int nDamage )
  1207. {
  1208. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  1209. SPRITE *pSprite = &sprite[nSprite];
  1210. int nXSprite = pSprite->extra;
  1211. if (nXSprite < 0)
  1212. return;
  1213. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  1214. XSPRITE *pXSprite = &xsprite[nXSprite];
  1215. if (pXSprite->health == 0) // it's already toast
  1216. return;
  1217. switch ( pSprite->statnum )
  1218. {
  1219. case kStatDude:
  1220. {
  1221. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  1222. // calculate and apply damage to the dude or player sprite
  1223. int nShift = dudeInfo[pSprite->type - kDudeBase].damageShift[nDamageType];
  1224. nDamage = (nShift >= kNoDamage) ? 0 : nDamage >> nShift;
  1225. pXSprite->health = ClipLow(pXSprite->health - nDamage, 0);
  1226. // process results and effects of damage
  1227. if ( IsPlayerSprite(pSprite) )
  1228. playerDamageSprite( &gPlayer[pSprite->type - kDudePlayer1], nSource, nDamage );
  1229. else
  1230. aiDamageSprite( pSprite, pXSprite, nSource, nDamageType, nDamage );
  1231. // kill dudes lacking health to sustain life
  1232. if (pXSprite->health == 0)
  1233. {
  1234. // prevent dudes from exploding from weak explosion damage
  1235. if ( nDamageType == kDamageExplode && nDamage < (5 << 4) )
  1236. nDamageType = kDamagePummel;
  1237. if ( IsPlayerSprite(pSprite) )
  1238. sfxStart3DSound(nXSprite, kSfxPlayDie);
  1239. actKillSprite(nSource, nSprite, nDamageType);
  1240. }
  1241. break;
  1242. }
  1243. case kStatThing:
  1244. case kStatProximity:
  1245. {
  1246. dassert(pSprite->type >= kThingBase && pSprite->type < kThingMax);
  1247. int thingIndex = pSprite->type - kThingBase;
  1248. nDamage >>= thingInfo[thingIndex].damageShift[nDamageType];
  1249. pXSprite->health = ClipLow(pXSprite->health - nDamage, 0);
  1250. if (pXSprite->health == 0)
  1251. {
  1252. pSprite->owner = (short)nSource;
  1253. trTriggerSprite(nSprite, pXSprite, kCommandOff);
  1254. switch ( pSprite->type )
  1255. {
  1256. case kThingMachineGun:
  1257. seqSpawn(kSeqMGunDead, SS_SPRITE, pSprite->extra);
  1258. sfxStart3DSound(nXSprite, kSfxMGDie);
  1259. break;
  1260. case kThingBlueVase:
  1261. seqSpawn(kSeqVase1, SS_SPRITE, pSprite->extra);
  1262. sfxStart3DSound(nXSprite, kSfxPotteryHit);
  1263. if (pXSprite->data1 > 0)
  1264. DropPickupObject( nSprite, pXSprite->data1 );
  1265. if (pXSprite->data2 > 0)
  1266. DropPickupObject( nSprite, pXSprite->data2 );
  1267. break;
  1268. case kThingBrownVase:
  1269. seqSpawn(kSeqVase2, SS_SPRITE, pSprite->extra);
  1270. sfxStart3DSound(nXSprite, kSfxPotteryHit);
  1271. if (pXSprite->data1 > 0)
  1272. DropPickupObject( nSprite, pXSprite->data1 );
  1273. if (pXSprite->data2 > 0)
  1274. DropPickupObject( nSprite, pXSprite->data2 );
  1275. break;
  1276. case kThingClearGlass:
  1277. pSprite->yrepeat >>= 1;
  1278. seqSpawn(kSeqClearGlass, SS_SPRITE, pSprite->extra);
  1279. sfxStart3DSound(nXSprite, kSfxGlassHit);
  1280. break;
  1281. case kThingFluorescent:
  1282. seqSpawn(kSeqFluorescentLight, SS_SPRITE, pSprite->extra);
  1283. break;
  1284. case kThingWoodBeam:
  1285. seqSpawn(kSeqBeam, SS_SPRITE, pSprite->extra);
  1286. break;
  1287. case kThingWeb:
  1288. seqSpawn(kSeqWeb, SS_SPRITE, pSprite->extra);
  1289. break;
  1290. case kThingMetalGrate1:
  1291. seqSpawn(kSeqMetalGrate1, SS_SPRITE, pSprite->extra);
  1292. break;
  1293. case kThingFlammableTree:
  1294. if (pXSprite->data1 == 0)
  1295. seqSpawn(kSeqBurningTree1, SS_SPRITE, pSprite->extra);
  1296. else if (pXSprite->data1 == 1)
  1297. seqSpawn(kSeqBurningTree2, SS_SPRITE, pSprite->extra);
  1298. sfxStart3DSound(nXSprite, kSfxBurn);
  1299. break;
  1300. case kThingZombieBones:
  1301. dprintf("damaging zombie bones\n");
  1302. if ( seqGetStatus(SS_SPRITE, nXSprite) < 0 ) // body finished burning
  1303. seqSpawn(kSeqZombieBones, SS_SPRITE, pSprite->extra);
  1304. break;
  1305. }
  1306. }
  1307. break;
  1308. }
  1309. }
  1310. }
  1311. void actImpactMissile( int nSprite, int hitInfo )
  1312. {
  1313. SPRITE *pMissile = &sprite[nSprite];
  1314. int hitType = hitInfo & kHitTypeMask;
  1315. int hitObject = hitInfo & kHitIndexMask;
  1316. int nXMissile = pMissile->extra;
  1317. switch (pMissile->type)
  1318. {
  1319. case kMissileFireball:
  1320. actExplodeSprite( nSprite );
  1321. break;
  1322. case kMissileFlare:
  1323. case kMissileExplodingFlare:
  1324. case kMissileStarburstFlare:
  1325. {
  1326. XSPRITE *pXMissile = &xsprite[pMissile->extra];
  1327. if (pMissile->type == kMissileExplodingFlare || pMissile->type == kMissileStarburstFlare)
  1328. {
  1329. actExplodeSprite( nSprite );
  1330. break;
  1331. }
  1332. if ( hitType == kHitSprite && sprite[hitObject].extra > 0 )
  1333. {
  1334. SPRITE *pObject = &sprite[hitObject];
  1335. XSPRITE *pXObject = &xsprite[pObject->extra];
  1336. pMissile->picnum = kAnmFlareBurn;
  1337. pXMissile->target = hitObject;
  1338. pXMissile->targetZ = pMissile->z - pObject->z;
  1339. pXMissile->goalAng = getangle( pMissile->x - pObject->x, pMissile->y - pObject->y ) - pObject->ang;
  1340. pXMissile->state = 1;
  1341. actAddBurnTime(pMissile->owner, pXObject, 8 * kTimerRate);
  1342. actDamageSprite(pMissile->owner, hitObject, kDamageStab, 10 << 4);
  1343. actPostSprite( nSprite, kStatFlare );
  1344. evPost(nSprite, SS_SPRITE, 8 * kTimerRate); // callback to flare
  1345. }
  1346. else
  1347. {
  1348. // ADD: spawn an explosion later
  1349. actPostSprite( nSprite, kStatFree );
  1350. }
  1351. break;
  1352. }
  1353. case kMissileSprayFlame:
  1354. case kMissileHoundFire:
  1355. // seqKill(SS_SPRITE, nXMissile);
  1356. // deletesprite((short)nSprite);
  1357. if ( hitType == kHitSprite && sprite[hitObject].extra > 0 )
  1358. {
  1359. XSPRITE *pXObject = &xsprite[sprite[hitObject].extra];
  1360. actAddBurnTime( pMissile->owner, pXObject, kFrameTicks );
  1361. }
  1362. break;
  1363. case kMissileEctoSkull:
  1364. actPostSprite( nSprite, kStatEffect );
  1365. seqSpawn(kSeqSkullExplode, SS_SPRITE, pMissile->extra);
  1366. if ( hitType == kHitSprite && sprite[hitObject].statnum == kStatDude )
  1367. {
  1368. actDamageSprite(pMissile->owner, hitObject, kDamageSpirit, 50 << 4);
  1369. SPRITE *pDude = &sprite[pMissile->owner];
  1370. XSPRITE *pXDude = &xsprite[pDude->extra];
  1371. if ( pXDude->health > 0 )
  1372. actHealDude(pXDude, 25);
  1373. }
  1374. break;
  1375. case kMissileButcherKnife:
  1376. actPostSprite( nSprite, kStatEffect );
  1377. pMissile->cstat &= ~kSpriteWall;
  1378. pMissile->type = kNothing;
  1379. seqSpawn(kSeqSkullExplode, SS_SPRITE, pMissile->extra);
  1380. if ( hitType == kHitSprite && sprite[hitObject].statnum == kStatDude )
  1381. {
  1382. actDamageSprite(pMissile->owner, hitObject, kDamageSpirit, 15 << 4);
  1383. SPRITE *pDude = &sprite[pMissile->owner];
  1384. XSPRITE *pXDude = &xsprite[pDude->extra];
  1385. int dudeIndex = pDude->type - kDudeBase;
  1386. if ( pXDude->health > 0 )
  1387. actHealDude(pXDude, 10, dudeInfo[dudeIndex].startHealth);
  1388. }
  1389. break;
  1390. default:
  1391. seqKill(SS_SPRITE, nXMissile);
  1392. actPostSprite( nSprite, kStatFree );
  1393. if (hitType == kHitSprite)
  1394. actDamageSprite(pMissile->owner, hitObject, kDamagePummel, 5 << 4);
  1395. break;
  1396. }
  1397. }
  1398. void ProcessTouchObjects( int nSprite, int nXSprite )
  1399. {
  1400. SPRITE *pSprite = &sprite[nSprite];
  1401. XSPRITE *pXSprite = &xsprite[nXSprite];
  1402. SPRITEHIT *pSpriteHit = &gSpriteHit[nXSprite];
  1403. int nHitObject = pSpriteHit->ceilHit & kHitIndexMask;
  1404. switch( pSpriteHit->ceilHit & kHitTypeMask )
  1405. {
  1406. case kHitSprite:
  1407. if ( sprite[nHitObject].extra > 0 )
  1408. {
  1409. SPRITE *pHit = &sprite[nHitObject];
  1410. XSPRITE *pXHit = &xsprite[pHit->extra];
  1411. switch ( pHit->type )
  1412. {
  1413. case kTrapSawBlade:
  1414. if ( pXHit->state )
  1415. {
  1416. pXHit->data1 = 1;
  1417. pXHit->data2 = ClipHigh(pXHit->data2 + 2 * kFrameTicks, kTimerRate * 5);
  1418. actDamageSprite(nSprite, nSprite, kDamageStab, 4);
  1419. }
  1420. else
  1421. actDamageSprite(nSprite, nSprite, kDamageStab, 1);
  1422. break;
  1423. }
  1424. }
  1425. break;
  1426. case kHitWall:
  1427. case kHitSector:
  1428. break;
  1429. }
  1430. nHitObject = pSpriteHit->moveHit & kHitIndexMask;
  1431. switch( pSpriteHit->moveHit & kHitTypeMask )
  1432. {
  1433. case kHitSprite:
  1434. break;
  1435. case kHitWall:
  1436. case kHitSector:
  1437. break;
  1438. }
  1439. nHitObject = pSpriteHit->floorHit & kHitIndexMask;
  1440. switch( pSpriteHit->floorHit & kHitTypeMask )
  1441. {
  1442. case kHitSprite:
  1443. if ( sprite[nHitObject].extra > 0 )
  1444. {
  1445. SPRITE *pHit = &sprite[nHitObject];
  1446. XSPRITE *pXHit = &xsprite[pHit->extra];
  1447. switch ( pHit->type )
  1448. {
  1449. case kTrapSawBlade:
  1450. if ( pXHit->state )
  1451. {
  1452. pXHit->data1 = 1;
  1453. pXHit->data2 = ClipHigh(pXHit->data2 + 2 * kFrameTicks, kTimerRate * 5);
  1454. actDamageSprite(nSprite, nSprite, kDamageStab, 4);
  1455. }
  1456. else
  1457. actDamageSprite(nSprite, nSprite, kDamageStab, 1);
  1458. break;
  1459. }
  1460. }
  1461. break;
  1462. case kHitWall:
  1463. case kHitSector:
  1464. break;
  1465. }
  1466. }
  1467. #define kMinZVel (6 << 4)
  1468. #define kAirDrag 0x0100
  1469. static int MoveThing( int nSprite, char cliptype )
  1470. {
  1471. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  1472. SPRITE *pSprite = &sprite[nSprite];
  1473. int nXSprite = pSprite->extra;
  1474. XSPRITE *pXSprite = &xsprite[nXSprite];
  1475. if ( !(pSprite->flags & kAttrFalling) && !pSprite->xvel && !pSprite->yvel && !pSprite->zvel )
  1476. return 0;
  1477. short nSector = pSprite->sectnum;
  1478. dassert(nSector >= 0 && nSector < kMaxSectors);
  1479. gSpriteHit[nXSprite].ceilHit = 0;
  1480. gSpriteHit[nXSprite].floorHit = 0;
  1481. gSpriteHit[nXSprite].moveHit = 0;
  1482. int zTop, zBot;
  1483. GetSpriteExtents(pSprite, &zTop, &zBot);
  1484. if ( pSprite->xvel || pSprite->yvel )
  1485. {
  1486. short oldcstat = pSprite->cstat;
  1487. pSprite->cstat &= ~kSpriteBlocking & ~kSpriteHitscan;
  1488. gSpriteHit[nXSprite].moveHit = ClipMove(&pSprite->x, &pSprite->y, &pSprite->z, &nSector,
  1489. pSprite->xvel * kFrameTicks >> 4, pSprite->yvel * kFrameTicks >> 4, pSprite->clipdist << 2,
  1490. (pSprite->z - zTop) / 4, (zBot - pSprite->z) / 4, cliptype);
  1491. pSprite->cstat = oldcstat;
  1492. if ((nSector != pSprite->sectnum) && (nSector >= 0))
  1493. changespritesect((short)nSprite, nSector);
  1494. switch (gSpriteHit[nXSprite].moveHit & kHitTypeMask)
  1495. {
  1496. case kHitWall:
  1497. {
  1498. int nWall = gSpriteHit[nXSprite].moveHit & kHitIndexMask;
  1499. ReflectVector(&pSprite->xvel, &pSprite->yvel, nWall, 0x4000);
  1500. pSprite->zvel = (short)mulscale16(pSprite->zvel, 0xC000);
  1501. break;
  1502. }
  1503. // need to handle sprite collisions here....
  1504. }
  1505. }
  1506. long ceilz, ceilhit, floorz, floorhit;
  1507. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, pSprite->clipdist << 2, cliptype);
  1508. if ( pSprite->zvel )
  1509. {
  1510. pSprite->z += pSprite->zvel * kFrameTicks;
  1511. pSprite->zvel -= mulscale16r(pSprite->zvel, kAirDrag);
  1512. }
  1513. if ( (pSprite->flags & kAttrGravity) && zBot < floorz )
  1514. {
  1515. pSprite->z += kGravity * kFrameTicks * kFrameTicks / 2;
  1516. pSprite->zvel += kGravity * kFrameTicks;
  1517. pSprite->flags |= kAttrFalling;
  1518. }
  1519. // check for warping in linked sectors
  1520. int nUpper = gUpperLink[nSector], nLower = gLowerLink[nSector];
  1521. if ( nUpper >= 0 && pSprite->z < sprite[nUpper].z )
  1522. {
  1523. nLower = sprite[nUpper].owner;
  1524. changespritesect((short)nSprite, sprite[nLower].sectnum);
  1525. pSprite->x += sprite[nLower].x - sprite[nUpper].x;
  1526. pSprite->y += sprite[nLower].y - sprite[nUpper].y;
  1527. pSprite->z += sprite[nLower].z - sprite[nUpper].z;
  1528. viewBackupSpriteLoc(nSprite, pSprite); // prevent interpolation
  1529. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, pSprite->clipdist << 2, cliptype);
  1530. }
  1531. else if ( nLower >= 0 && pSprite->z > sprite[nLower].z )
  1532. {
  1533. nUpper = sprite[nLower].owner;
  1534. changespritesect((short)nSprite, sprite[nUpper].sectnum);
  1535. pSprite->x += sprite[nUpper].x - sprite[nLower].x;
  1536. pSprite->y += sprite[nUpper].y - sprite[nLower].y;
  1537. pSprite->z += sprite[nUpper].z - sprite[nLower].z;
  1538. viewBackupSpriteLoc(nSprite, pSprite); // prevent interpolation
  1539. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, pSprite->clipdist << 2, cliptype);
  1540. }
  1541. GetSpriteExtents(pSprite, &zTop, &zBot);
  1542. // hit floor?
  1543. if ( zBot >= floorz )
  1544. {
  1545. gSpriteHit[nXSprite].floorHit = floorhit;
  1546. pSprite->z += floorz - zBot;
  1547. if ( pSprite->flags & kAttrFalling )
  1548. {
  1549. pSprite->xvel = (short)mulscale16(pSprite->xvel, 0xC000);
  1550. pSprite->yvel = (short)mulscale16(pSprite->yvel, 0xC000);
  1551. pSprite->zvel = (short)mulscale16(-pSprite->zvel, 0x4000);
  1552. if ( qabs(pSprite->zvel) < kMinZVel)
  1553. {
  1554. pSprite->zvel = 0;
  1555. pSprite->flags &= ~kAttrFalling;
  1556. }
  1557. return kHitFloor | nSector;
  1558. }
  1559. pSprite->zvel = 0;
  1560. }
  1561. // hit ceiling
  1562. if ( zTop < ceilz && ((ceilhit & kHitTypeMask) != kHitSector || !(sector[nSector].ceilingstat & kSectorParallax)) )
  1563. {
  1564. gSpriteHit[nXSprite].ceilHit = ceilhit;
  1565. pSprite->z += ClipLow(ceilz - zTop, 0);
  1566. pSprite->xvel = (short)mulscale16(pSprite->xvel, 0xC000);
  1567. pSprite->yvel = (short)mulscale16(pSprite->yvel, 0xC000);
  1568. pSprite->zvel = (short)mulscale16(-pSprite->zvel, 0x4000);
  1569. // return kHitCeiling | nSector;
  1570. }
  1571. // drag and friction
  1572. if ( pSprite->xvel || pSprite->yvel )
  1573. {
  1574. // air drag
  1575. pSprite->xvel -= mulscale16r(pSprite->xvel, kAirDrag);
  1576. pSprite->yvel -= mulscale16r(pSprite->yvel, kAirDrag);
  1577. if ( !(pSprite->flags & kAttrFalling) )
  1578. {
  1579. // sliding
  1580. int vel = qdist(pSprite->xvel, pSprite->yvel);
  1581. int nFrict = ClipHigh(kFrameTicks * kGroundFriction, vel);
  1582. if ( (floorhit & kHitTypeMask) == kHitSprite )
  1583. {
  1584. int nUnderSprite = floorhit & kHitIndexMask;
  1585. if ( (sprite[nUnderSprite].cstat & kSpriteRMask) == kSpriteFace )
  1586. {
  1587. // push it off the face sprite
  1588. pSprite->xvel += mulscale(kFrameTicks, pSprite->x - sprite[nUnderSprite].x, 6);
  1589. pSprite->yvel += mulscale(kFrameTicks, pSprite->y - sprite[nUnderSprite].y, 6);
  1590. return gSpriteHit[nXSprite].moveHit;
  1591. }
  1592. }
  1593. if (vel > 0)
  1594. {
  1595. nFrict = divscale16(nFrict, vel);
  1596. pSprite->xvel -= mulscale16(nFrict, pSprite->xvel);
  1597. pSprite->yvel -= mulscale16(nFrict, pSprite->yvel);
  1598. }
  1599. }
  1600. }
  1601. return gSpriteHit[nXSprite].moveHit;
  1602. }
  1603. static void MoveDebris( int nSprite )
  1604. {
  1605. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  1606. SPRITE *pSprite = &sprite[nSprite];
  1607. int nXSprite = pSprite->extra;
  1608. short nSector = pSprite->sectnum;
  1609. dassert(nSector >= 0 && nSector < kMaxSectors);
  1610. if ( pSprite->xvel || pSprite->yvel )
  1611. {
  1612. pSprite->x += pSprite->xvel * kFrameTicks >> 4;
  1613. pSprite->y += pSprite->yvel * kFrameTicks >> 4;
  1614. // air drag
  1615. pSprite->xvel -= mulscale16r(pSprite->xvel, kAirDrag);
  1616. pSprite->yvel -= mulscale16r(pSprite->yvel, kAirDrag);
  1617. }
  1618. if ( pSprite->zvel )
  1619. {
  1620. pSprite->z += pSprite->zvel * kFrameTicks;
  1621. pSprite->zvel -= mulscale16r(pSprite->zvel, kAirDrag);
  1622. }
  1623. if ( pSprite->flags & kAttrGravity )
  1624. {
  1625. pSprite->z += kGravity * kFrameTicks * kFrameTicks / 2;
  1626. pSprite->zvel += kGravity * kFrameTicks;
  1627. }
  1628. if ( !FindSector(pSprite->x, pSprite->y, pSprite->z, &nSector) )
  1629. {
  1630. actPostSprite(nSprite, kStatFree);
  1631. return;
  1632. }
  1633. if ( nSector != pSprite->sectnum )
  1634. changespritesect((short)nSprite, nSector);
  1635. }
  1636. #define kScreamVel 1200 // zvel at which player screams
  1637. #define kGruntVel 700
  1638. #define kDudeDrag 0x2800
  1639. #define kMinDudeVel (2 << 4)
  1640. static void MoveDude( int nSprite )
  1641. {
  1642. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  1643. SPRITE *pSprite = &sprite[nSprite];
  1644. int nXSprite = pSprite->extra;
  1645. XSPRITE *pXSprite = &xsprite[nXSprite];
  1646. if ( !(pSprite->flags & kAttrFalling) && !pSprite->xvel && !pSprite->yvel && !pSprite->zvel )
  1647. return;
  1648. PLAYER *pPlayer = NULL;
  1649. if ( IsPlayerSprite(pSprite) )
  1650. pPlayer = &gPlayer[pSprite->type - kDudePlayer1];
  1651. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  1652. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  1653. int zTop, zBot;
  1654. GetSpriteExtents(pSprite, &zTop, &zBot);
  1655. int floorDist = (zBot - pSprite->z) / 4;
  1656. int ceilDist = (pSprite->z - zTop) / 4;
  1657. int clipDist = pSprite->clipdist << 2;
  1658. short nSector = pSprite->sectnum;
  1659. dassert(nSector >= 0 && nSector < kMaxSectors);
  1660. // if ( !(pSprite->xvel || pSprite->yvel || pSprite->zvel) && fWasOnFloor )
  1661. // return;
  1662. gSpriteHit[nXSprite].ceilHit = 0;
  1663. gSpriteHit[nXSprite].floorHit = 0;
  1664. gSpriteHit[nXSprite].moveHit = 0;
  1665. if ( pSprite->xvel || pSprite->yvel )
  1666. {
  1667. int oldX = pSprite->x;
  1668. int oldY = pSprite->y;
  1669. if ( pPlayer && gNoClip )
  1670. {
  1671. pSprite->x += pSprite->xvel * kFrameTicks >> 4;
  1672. pSprite->y += pSprite->yvel * kFrameTicks >> 4;
  1673. updatesector( pSprite->x, pSprite->y, &nSector);
  1674. if (nSector == -1)
  1675. {
  1676. pSprite->x = oldX;
  1677. pSprite->y = oldY;
  1678. nSector = pSprite->sectnum;
  1679. }
  1680. }
  1681. else
  1682. {
  1683. short oldcstat = pSprite->cstat;
  1684. pSprite->cstat &= ~kSpriteBlocking & ~kSpriteHitscan;
  1685. gSpriteHit[nXSprite].moveHit = ClipMove(
  1686. &pSprite->x, &pSprite->y, &pSprite->z, &nSector,
  1687. pSprite->xvel * kFrameTicks >> 4, pSprite->yvel * kFrameTicks >> 4, clipDist,
  1688. ceilDist, floorDist, 0);
  1689. pSprite->cstat = oldcstat;
  1690. }
  1691. if ( pPlayer )
  1692. {
  1693. if ( nSector != pSprite->sectnum && nSector >= 0 )
  1694. {
  1695. // process sector exit/enter triggers
  1696. int nXSector;
  1697. nXSector = sector[pSprite->sectnum].extra;
  1698. if ( nXSector > 0 && xsector[nXSector].triggerExit )
  1699. trTriggerSector(pSprite->sectnum, &xsector[nXSector], kCommandSectorExit);
  1700. nXSector = sector[nSector].extra;
  1701. if ( nXSector > 0 && xsector[nXSector].triggerEnter )
  1702. trTriggerSector(nSector, &xsector[nXSector], kCommandSectorEnter);
  1703. }
  1704. }
  1705. if ( nSector != pSprite->sectnum )
  1706. changespritesect((short)nSprite, nSector);
  1707. switch (gSpriteHit[nXSprite].moveHit & kHitTypeMask)
  1708. {
  1709. case kHitWall:
  1710. {
  1711. int nWall = gSpriteHit[nXSprite].moveHit & kHitIndexMask;
  1712. WALL *pWall = &wall[nWall];
  1713. // don't bounce off wall if not fully blocking
  1714. if ( pWall->nextsector != -1 )
  1715. {
  1716. SECTOR *pSector = &sector[pWall->nextsector];
  1717. if ( pSector->floorz > zTop || pSector->ceilingz < zBot )
  1718. {
  1719. ReflectVector(&pSprite->xvel, &pSprite->yvel, nWall, 0);
  1720. break;
  1721. }
  1722. }
  1723. ReflectVector(&pSprite->xvel, &pSprite->yvel, nWall, 0x4000);
  1724. pSprite->zvel = (short)mulscale16(pSprite->zvel, 0xC000);
  1725. break;
  1726. }
  1727. // need to handle sprite collisions here....
  1728. }
  1729. }
  1730. long ceilz, ceilhit, floorz, floorhit;
  1731. if ( pPlayer )
  1732. clipDist += 16; // increase clipdist to allow jumping onto ledges
  1733. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, clipDist, 0);
  1734. if ( pSprite->zvel )
  1735. {
  1736. pSprite->z += pSprite->zvel * kFrameTicks;
  1737. pSprite->zvel -= mulscale16r(pSprite->zvel, kAirDrag);
  1738. }
  1739. if ( pPlayer && pSprite->zvel > kScreamVel && !pPlayer->fScreamed )
  1740. {
  1741. pPlayer->fScreamed = TRUE;
  1742. sfxStart3DSound(nXSprite, kSfxPlayFall);
  1743. }
  1744. if ( (pSprite->flags & kAttrGravity) && zBot < floorz )
  1745. {
  1746. pSprite->z += kGravity * kFrameTicks * kFrameTicks / 2;
  1747. pSprite->zvel += kGravity * kFrameTicks;
  1748. pSprite->flags |= kAttrFalling;
  1749. }
  1750. // check for warping in linked sectors
  1751. int nUpper = gUpperLink[nSector], nLower = gLowerLink[nSector];
  1752. if ( nUpper >= 0 && pSprite->z < sprite[nUpper].z )
  1753. {
  1754. nLower = sprite[nUpper].owner;
  1755. changespritesect((short)nSprite, sprite[nLower].sectnum);
  1756. pSprite->x += sprite[nLower].x - sprite[nUpper].x;
  1757. pSprite->y += sprite[nLower].y - sprite[nUpper].y;
  1758. pSprite->z += sprite[nLower].z - sprite[nUpper].z;
  1759. viewBackupSpriteLoc(nSprite, pSprite); // prevent interpolation
  1760. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, clipDist, 0);
  1761. }
  1762. else if ( nLower >= 0 && pSprite->z > sprite[nLower].z )
  1763. {
  1764. nUpper = sprite[nLower].owner;
  1765. changespritesect((short)nSprite, sprite[nUpper].sectnum);
  1766. pSprite->x += sprite[nUpper].x - sprite[nLower].x;
  1767. pSprite->y += sprite[nUpper].y - sprite[nLower].y;
  1768. pSprite->z += sprite[nUpper].z - sprite[nLower].z;
  1769. viewBackupSpriteLoc(nSprite, pSprite); // prevent interpolation
  1770. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, clipDist, 0);
  1771. }
  1772. GetSpriteExtents(pSprite, &zTop, &zBot);
  1773. if ( pPlayer && zBot >= floorz)
  1774. {
  1775. long floorz2 = floorz, floorhit2 = floorhit;
  1776. GetZRange(pSprite, &ceilz, &ceilhit, &floorz, &floorhit, pSprite->clipdist << 2, 0);
  1777. if ( zBot <= floorz && pSprite->z - floorz2 < floorDist )
  1778. {
  1779. floorz = floorz2;
  1780. floorhit2 = floorhit;
  1781. }
  1782. }
  1783. // hit floor?
  1784. if ( zBot >= floorz )
  1785. {
  1786. gSpriteHit[nXSprite].floorHit = floorhit;
  1787. pSprite->z += floorz - zBot;
  1788. if ( pSprite->flags & kAttrFalling )
  1789. {
  1790. // need some way of converting fall damge to a non-linear curve
  1791. int fallDamage = mulscale16(pSprite->zvel, pSprite->zvel);
  1792. fallDamage = mulscale(fallDamage, fallDamage, 1);
  1793. if ( fallDamage > (20 << 4) )
  1794. actDamageSprite(nSprite, nSprite, kDamageFall, fallDamage);
  1795. if ( pPlayer && pXSprite->health > 0 )
  1796. {
  1797. pPlayer->fScreamed = FALSE;
  1798. if ( pSprite->zvel > kGruntVel )
  1799. sfxStart3DSound(nXSprite, kSfxPlayLand);
  1800. }
  1801. pSprite->xvel = (short)mulscale16(pSprite->xvel, 0xC000);
  1802. pSprite->yvel = (short)mulscale16(pSprite->yvel, 0xC000);
  1803. pSprite->zvel = (short)mulscale16(-pSprite->zvel, 0x2000);
  1804. if ( pSprite->zvel > -kMinZVel )
  1805. {
  1806. pSprite->zvel = 0;
  1807. pSprite->flags &= ~kAttrFalling;
  1808. }
  1809. int nSurfType = tileGetSurfType(floorhit);
  1810. if ( nSurfType == kSurfWater )
  1811. {
  1812. actSpawnEffect(pSprite->sectnum, pSprite->x, pSprite->y, floorz, ET_Splash1);
  1813. }
  1814. return;
  1815. }
  1816. pSprite->zvel = 0;
  1817. }
  1818. // hit ceiling
  1819. if ( zTop < ceilz && ((ceilhit & kHitTypeMask) != kHitSector || !(sector[nSector].ceilingstat & kSectorParallax)) )
  1820. {
  1821. pSprite->z += ClipLow(ceilz - zTop, 0);
  1822. pSprite->xvel = (short)mulscale16(pSprite->xvel, 0xC000);
  1823. pSprite->yvel = (short)mulscale16(pSprite->yvel, 0xC000);
  1824. pSprite->zvel = (short)mulscale16(-pSprite->zvel, 0x2000);
  1825. }
  1826. if ( zTop <= ceilz )
  1827. gSpriteHit[nXSprite].ceilHit = ceilhit;
  1828. // drag and friction
  1829. if ( pSprite->xvel || pSprite->yvel )
  1830. {
  1831. // air drag
  1832. pSprite->xvel -= mulscale16(pSprite->xvel, kAirDrag);
  1833. pSprite->yvel -= mulscale16(pSprite->yvel, kAirDrag);
  1834. if ( !(pSprite->flags & kAttrFalling) )
  1835. {
  1836. if ( (floorhit & kHitTypeMask) == kHitSprite )
  1837. {
  1838. int nUnderSprite = floorhit & kHitIndexMask;
  1839. if ( (sprite[nUnderSprite].cstat & kSpriteRMask) == kSpriteFace )
  1840. {
  1841. // push it off the face sprite
  1842. pSprite->xvel += mulscale(kFrameTicks, pSprite->x - sprite[nUnderSprite].x, 6);
  1843. pSprite->yvel += mulscale(kFrameTicks, pSprite->y - sprite[nUnderSprite].y, 6);
  1844. return;
  1845. }
  1846. }
  1847. // movement drag
  1848. pSprite->xvel -= (sshort)mulscale16r(pSprite->xvel, kDudeDrag);
  1849. pSprite->yvel -= (sshort)mulscale16r(pSprite->yvel, kDudeDrag);
  1850. if ( qdist(pSprite->xvel, pSprite->yvel) < kMinDudeVel )
  1851. pSprite->xvel = pSprite->yvel = 0;
  1852. }
  1853. }
  1854. ProcessTouchObjects( nSprite, nXSprite );
  1855. }
  1856. // missiles are self-propelled and are unaffected by gravity
  1857. static int MoveMissile( int nSprite )
  1858. {
  1859. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  1860. SPRITE *pSprite = &sprite[nSprite];
  1861. return movesprite((short)nSprite, pSprite->xvel, pSprite->yvel, pSprite->zvel,
  1862. 4 << 8, 4 << 8, 1, kFrameTicks);
  1863. }
  1864. void actExplodeSprite( int nSprite )
  1865. {
  1866. SPRITE *pSprite = &sprite[nSprite];
  1867. int nXSprite = pSprite->extra;
  1868. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  1869. // already exploding?
  1870. if (pSprite->statnum == kStatExplosion)
  1871. return;
  1872. switch ( pSprite->type )
  1873. {
  1874. case kMissileExplodingFlare:
  1875. case kMissileStarburstFlare:
  1876. seqSpawn(kSeqExplodeC2T, SS_SPRITE, nXSprite);
  1877. break;
  1878. case kThingTNTStick:
  1879. if ( gSpriteHit[nXSprite].floorHit == 0 )
  1880. seqSpawn(kSeqExplodeC2S, SS_SPRITE, nXSprite);
  1881. else
  1882. seqSpawn(kSeqExplodeC1S, SS_SPRITE, nXSprite);
  1883. break;
  1884. case kThingTNTProxArmed:
  1885. case kThingTNTRemArmed:
  1886. case kThingTNTBundle:
  1887. // if ( gSpriteHit[nXSprite].floorHit == 0 )
  1888. seqSpawn(kSeqExplodeC2M, SS_SPRITE, nXSprite);
  1889. // else
  1890. // seqSpawn(kSeqExplodeC1M, SS_SPRITE, nXSprite);
  1891. break;
  1892. case kThingTNTBarrel:
  1893. {
  1894. // spawn an explosion effect
  1895. int nEffect = actSpawnSprite( pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, kStatExplosion, TRUE );
  1896. sprite[nEffect].owner = pSprite->owner; // set owner for frag/targeting
  1897. // place barrel on the respawn list or just delete it
  1898. if ( actCheckRespawn( nSprite ) )
  1899. {
  1900. XSPRITE *pXSprite = &xsprite[nXSprite];
  1901. pXSprite->state = 0;
  1902. pXSprite->health = thingInfo[kThingTNTBarrel - kThingBase].startHealth << 4;
  1903. }
  1904. else
  1905. actPostSprite( nSprite, kStatFree );
  1906. // reset locals to point at the effect, not the barrel
  1907. nSprite = nEffect;
  1908. pSprite = &sprite[nEffect];
  1909. nXSprite = pSprite->extra;
  1910. seqSpawn(kSeqExplodeC2L, SS_SPRITE, nXSprite);
  1911. break;
  1912. }
  1913. default:
  1914. seqSpawn(kSeqExplodeC2M, SS_SPRITE, nXSprite);
  1915. break;
  1916. }
  1917. pSprite->xvel = pSprite->yvel = pSprite->zvel = 0;
  1918. actPostSprite( nSprite, kStatExplosion );
  1919. pSprite->flags &= ~(kAttrMove | kAttrGravity);
  1920. sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxExplodeCS);
  1921. }
  1922. void actProcessSprites(void)
  1923. {
  1924. int nSprite;
  1925. int nDude, nNextDude;
  1926. // process proximity triggered sprites
  1927. for (nSprite = headspritestat[kStatProximity]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  1928. {
  1929. SPRITE *pSprite = &sprite[nSprite];
  1930. int nXSprite = pSprite->extra;
  1931. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  1932. XSPRITE *pXSprite = &xsprite[nXSprite];
  1933. for (nDude = headspritestat[kStatDude]; nDude >= 0; nDude = nNextDude)
  1934. {
  1935. nNextDude = nextspritestat[nDude];
  1936. if ( CheckProximity(&sprite[nDude], pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, 64) )
  1937. trTriggerSprite(nSprite, pXSprite, kCommandSpriteProximity);
  1938. }
  1939. }
  1940. // process things for effects
  1941. for (nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  1942. {
  1943. SPRITE *pSprite = &sprite[nSprite];
  1944. if ( pSprite->extra > 0 )
  1945. {
  1946. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  1947. if ( actGetBurnTime(pXSprite) > 0 )
  1948. {
  1949. pXSprite->burnTime = ClipLow(pXSprite->burnTime - kFrameTicks, 0);
  1950. actDamageSprite( pXSprite->burnSource, nSprite, kDamageBurn, 4 * kFrameTicks );
  1951. }
  1952. }
  1953. }
  1954. // process things for movement
  1955. for (nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  1956. {
  1957. SPRITE *pSprite = &sprite[nSprite];
  1958. if ( pSprite->flags & (kAttrMove | kAttrGravity) )
  1959. {
  1960. viewBackupSpriteLoc(nSprite, pSprite);
  1961. int hitInfo = MoveThing(nSprite, 1);
  1962. if (hitInfo != 0)
  1963. {
  1964. int nXSprite = pSprite->extra;
  1965. if (nXSprite > 0)
  1966. {
  1967. XSPRITE *pXSprite = &xsprite[nXSprite];
  1968. if ( pXSprite->triggerProximity )
  1969. trTriggerSprite(nSprite, pXSprite, kCommandOff);
  1970. switch( pSprite->type )
  1971. {
  1972. case kThingWaterDrip:
  1973. case kThingBloodDrip:
  1974. MakeSplash(pSprite, pXSprite);
  1975. break;
  1976. case kThingBoneClub:
  1977. seqSpawn(kSeqBoneBreak, SS_SPRITE, nXSprite);
  1978. if ( (hitInfo & kHitTypeMask) == kHitSprite )
  1979. actDamageSprite( pSprite->owner, hitInfo & kHitIndexMask, kDamagePummel, 12 );
  1980. break;
  1981. }
  1982. }
  1983. }
  1984. }
  1985. }
  1986. // process debris sprites
  1987. for (nSprite = headspritestat[kStatDebris]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  1988. {
  1989. SPRITE *pSprite = &sprite[nSprite];
  1990. viewBackupSpriteLoc(nSprite, pSprite);
  1991. MoveDebris(nSprite);
  1992. }
  1993. // process missile sprites
  1994. for (nSprite = headspritestat[kStatMissile]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  1995. {
  1996. SPRITE *pSprite = &sprite[nSprite];
  1997. viewBackupSpriteLoc(nSprite, pSprite);
  1998. int hitInfo = MoveMissile(nSprite);
  1999. // process impacts
  2000. if (hitInfo != 0)
  2001. actImpactMissile( nSprite, hitInfo );
  2002. }
  2003. // process explosions
  2004. for (nSprite = headspritestat[kStatExplosion]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  2005. {
  2006. SPRITE *pSprite = &sprite[nSprite];
  2007. int x = pSprite->x, y = pSprite->y, z = pSprite->z, nSector = pSprite->sectnum;
  2008. int nAffected;
  2009. int radius = tilesizx[pSprite->picnum] * pSprite->xrepeat >> 6;
  2010. for (nAffected = headspritestat[kStatDude]; nAffected >= 0; nAffected = nextspritestat[nAffected])
  2011. {
  2012. if ( CheckProximity(&sprite[nAffected], x, y, z, nSector, radius) )
  2013. ConcussSprite(pSprite->owner, nAffected, x, y, z, kFrameTicks);
  2014. }
  2015. for (nAffected = headspritestat[kStatThing]; nAffected >= 0; nAffected = nextspritestat[nAffected])
  2016. {
  2017. if ( CheckProximity(&sprite[nAffected], x, y, z, nSector, radius) )
  2018. ConcussSprite(pSprite->owner, nAffected, x, y, z, kFrameTicks);
  2019. }
  2020. for (nAffected = headspritestat[kStatProximity]; nAffected >= 0; nAffected = nextspritestat[nAffected])
  2021. {
  2022. if ( CheckProximity(&sprite[nAffected], x, y, z, nSector, radius) )
  2023. ConcussSprite(pSprite->owner, nAffected, x, y, z, kFrameTicks);
  2024. }
  2025. }
  2026. // process traps for effects
  2027. for (nSprite = headspritestat[kStatTraps]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  2028. {
  2029. SPRITE *pSprite = &sprite[nSprite];
  2030. if ( pSprite->extra > 0 )
  2031. {
  2032. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  2033. switch( pSprite->type )
  2034. {
  2035. case kTrapSawBlade:
  2036. pXSprite->data2 = ClipLow(pXSprite->data2 - kFrameTicks, 0);
  2037. break;
  2038. }
  2039. }
  2040. }
  2041. // process dudes for effects
  2042. for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  2043. {
  2044. SPRITE *pSprite = &sprite[nSprite];
  2045. if ( pSprite->extra > 0 )
  2046. {
  2047. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  2048. if ( actGetBurnTime(pXSprite) > 0 )
  2049. {
  2050. pXSprite->burnTime = ClipLow(pXSprite->burnTime - kFrameTicks, 0);
  2051. actDamageSprite( pXSprite->burnSource, nSprite, kDamageBurn, 2 * kFrameTicks );
  2052. }
  2053. }
  2054. }
  2055. // process dudes for movement
  2056. for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  2057. {
  2058. SPRITE *pSprite = &sprite[nSprite];
  2059. int nSector = pSprite->sectnum;
  2060. viewBackupSpriteLoc(nSprite, pSprite);
  2061. // special sector processing
  2062. if ( sector[nSector].extra > 0 )
  2063. {
  2064. int nXSector = sector[ nSector ]. extra;
  2065. dassert(nXSector > 0 && nXSector < kMaxXSectors);
  2066. dassert(xsector[nXSector].reference == nSector);
  2067. XSECTOR *pXSector = &xsector[nXSector];
  2068. if ( pXSector->panVel && (pXSector->panAlways || pXSector->busy))
  2069. {
  2070. int windDrag = 0x0200; // 16:16 fixed point fraction
  2071. int panVel = pXSector->panVel;
  2072. int panAngle = pXSector->panAngle;
  2073. if ( !pXSector->panAlways && pXSector->busy )
  2074. panVel = mulscale16(panVel, pXSector->busy);
  2075. if (sector[nSector].floorstat & kSectorRelAlign)
  2076. {
  2077. panAngle += GetWallAngle(sector[nSector].wallptr) + kAngle90;
  2078. panAngle &= kAngleMask;
  2079. }
  2080. if (pXSector->wind)
  2081. {
  2082. int windX = mulscale30(panVel, Cos(panAngle)) - pSprite->xvel;
  2083. int windY = mulscale30(panVel, Sin(panAngle)) - pSprite->yvel;
  2084. pSprite->xvel += mulscale16(kFrameTicks * windX, windDrag);
  2085. pSprite->yvel += mulscale16(kFrameTicks * windY, windDrag);
  2086. }
  2087. }
  2088. // handle water dragging
  2089. if ( pXSector->depth > 0 )
  2090. {
  2091. if ( pSprite->z >= sector[nSector].floorz )
  2092. {
  2093. int pushDrag = dragTable[pXSector->depth];
  2094. int panVel = 0;
  2095. int panAngle = pXSector->panAngle;
  2096. if (pXSector->panAlways || pXSector->state || pXSector->busy)
  2097. {
  2098. panVel = pXSector->panVel;
  2099. if ( !pXSector->panAlways && pXSector->busy )
  2100. panVel = mulscale16(panVel, pXSector->busy);
  2101. }
  2102. if (sector[nSector].floorstat & kSectorRelAlign)
  2103. {
  2104. panAngle += GetWallAngle(sector[nSector].wallptr) + kAngle90;
  2105. panAngle &= kAngleMask;
  2106. }
  2107. int pushX = mulscale30(panVel, Cos(panAngle)) - pSprite->xvel;
  2108. int pushY = mulscale30(panVel, Sin(panAngle)) - pSprite->yvel;
  2109. int nDrag = ClipHigh(kFrameTicks * pushDrag, 0x10000);
  2110. pSprite->xvel += mulscale16(pushX, nDrag);
  2111. pSprite->yvel += mulscale16(pushY, nDrag);
  2112. }
  2113. } else if ( pXSector->underwater ) // handle underwater dragging
  2114. {
  2115. int pushDrag = dragTable[pXSector->depth];
  2116. int panVel = 0;
  2117. int panAngle = pXSector->panAngle;
  2118. if (pXSector->panAlways || pXSector->state || pXSector->busy)
  2119. {
  2120. panVel = pXSector->panVel;
  2121. if ( !pXSector->panAlways && pXSector->busy )
  2122. panVel = mulscale16(panVel, pXSector->busy);
  2123. }
  2124. if (sector[nSector].floorstat & kSectorRelAlign)
  2125. {
  2126. panAngle += GetWallAngle(sector[nSector].wallptr) + kAngle90;
  2127. panAngle &= kAngleMask;
  2128. }
  2129. int pushX = mulscale30(panVel, Cos(panAngle)) - pSprite->xvel;
  2130. int pushY = mulscale30(panVel, Sin(panAngle)) - pSprite->yvel;
  2131. pSprite->xvel += mulscale16(kFrameTicks * pushX, pushDrag);
  2132. pSprite->yvel += mulscale16(kFrameTicks * pushY, pushDrag);
  2133. }
  2134. }
  2135. MoveDude(nSprite);
  2136. }
  2137. // process flares to keep them burning on dudes
  2138. for (nSprite = headspritestat[kStatFlare]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  2139. {
  2140. SPRITE *pSprite = &sprite[nSprite];
  2141. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  2142. SPRITE *pTarget = &sprite[pXSprite->target];
  2143. viewBackupSpriteLoc(nSprite, pSprite);
  2144. int nAngle = pTarget->ang + pXSprite->goalAng;
  2145. int x = pTarget->x + mulscale30r( Cos(nAngle), pTarget->clipdist << 1 ); // halfway into clipdist
  2146. int y = pTarget->y + mulscale30r( Sin(nAngle), pTarget->clipdist << 1 );
  2147. int z = pTarget->z + pXSprite->targetZ;
  2148. setsprite((short)pXSprite->reference, x, y, z);
  2149. }
  2150. aiProcessDudes();
  2151. }
  2152. /***********************************************************************
  2153. * actSpawnSprite()
  2154. *
  2155. * Spawns a new sprite at the specified world coordinates.
  2156. **********************************************************************/
  2157. int actSpawnSprite( short nSector, int x, int y, int z, short nStatus, BOOL bAddXSprite )
  2158. {
  2159. int nSprite = insertsprite( nSector, nStatus );
  2160. if (nSprite >= 0)
  2161. sprite[nSprite].extra = -1;
  2162. else
  2163. {
  2164. dprintf("Out of sprites -- reclaiming sprite from purge list\n");
  2165. nSprite = headspritestat[kStatPurge];
  2166. dassert(nSprite >= 0);
  2167. changespritesect((short)nSprite, nSector);
  2168. changespritestat((short)nSprite, nStatus);
  2169. }
  2170. setsprite( (short)nSprite, x, y, z );
  2171. SPRITE *pSprite = &sprite[nSprite];
  2172. pSprite->type = 0;
  2173. viewBackupSpriteLoc(nSprite, pSprite);
  2174. // optionally create an xsprite
  2175. if ( bAddXSprite && pSprite->extra == -1 )
  2176. {
  2177. int nXSprite = dbInsertXSprite(nSprite);
  2178. gSpriteHit[nXSprite].floorHit = 0;
  2179. gSpriteHit[nXSprite].ceilHit = 0;
  2180. }
  2181. return nSprite;
  2182. }
  2183. int actCloneSprite( SPRITE *pSourceSprite )
  2184. {
  2185. int nSprite = insertsprite( pSourceSprite->sectnum, pSourceSprite->statnum);
  2186. if ( nSprite < 0 )
  2187. {
  2188. dprintf("Out of sprites -- reclaiming sprite from purge list\n");
  2189. nSprite = headspritestat[kStatPurge];
  2190. dassert(nSprite >= 0);
  2191. changespritesect((short)nSprite, pSourceSprite->sectnum);
  2192. changespritestat((short)nSprite, pSourceSprite->statnum);
  2193. }
  2194. SPRITE *pSprite = &sprite[nSprite];
  2195. *pSprite = *pSourceSprite;
  2196. viewBackupSpriteLoc(nSprite, pSprite);
  2197. // don't copy xsprite
  2198. pSprite->extra = -1;
  2199. return nSprite;
  2200. }
  2201. int actSpawnThing( short nSector, int x, int y, int z, int thingType )
  2202. {
  2203. dassert( thingType >= kThingBase && thingType < kThingMax );
  2204. int nThing = actSpawnSprite(nSector, x, y, z, kStatThing, TRUE );
  2205. SPRITE *pThing = &sprite[nThing];
  2206. pThing->type = (short)thingType;
  2207. int thingIndex = thingType - kThingBase;
  2208. int nXThing = pThing->extra;
  2209. dassert(nXThing > 0 && nXThing < kMaxXSprites);
  2210. XSPRITE *pXThing = &xsprite[nXThing];
  2211. pThing->clipdist = thingInfo[thingIndex].clipdist;
  2212. pThing->flags = thingInfo[thingIndex].flags;
  2213. if ( pThing->flags & kAttrGravity )
  2214. pThing->flags |= kAttrFalling;
  2215. pThing->pal = 0;
  2216. pXThing->health = thingInfo[thingIndex].startHealth << 4;
  2217. SetBitString(show2dsprite, nThing);
  2218. switch (thingType)
  2219. {
  2220. case kThingTNTStick:
  2221. pThing->shade = -32;
  2222. pThing->picnum = 2169;
  2223. pThing->cstat |= kSpriteHitscan;
  2224. pThing->xrepeat = pThing->yrepeat = 32;
  2225. break;
  2226. case kThingTNTBundle:
  2227. pThing->shade = -32;
  2228. pThing->picnum = 2172;
  2229. pThing->cstat |= kSpriteHitscan;
  2230. pThing->xrepeat = pThing->yrepeat = 32;
  2231. break;
  2232. case kThingTNTProxArmed:
  2233. pThing->shade = -16;
  2234. pThing->picnum = kAnmTNTProxArmed;
  2235. pThing->cstat |= kSpriteHitscan;
  2236. pThing->xrepeat = pThing->yrepeat = 32;
  2237. break;
  2238. case kThingTNTRemArmed:
  2239. pThing->shade = -16;
  2240. pThing->picnum = kAnmTNTRemArmed;
  2241. pThing->cstat |= kSpriteHitscan;
  2242. pThing->xrepeat = pThing->yrepeat = 32;
  2243. break;
  2244. case kThingBoneClub:
  2245. pThing->shade = 0;
  2246. pThing->picnum = kAnmBoneClub;
  2247. pThing->cstat |= kSpriteHitscan;
  2248. pThing->xrepeat = pThing->yrepeat = 32;
  2249. break;
  2250. case kThingWaterDrip:
  2251. pThing->picnum = kAnmDrip;
  2252. pThing->pal = kPLUCold;
  2253. //pThing->cstat |= kSpriteTranslucent | kSpriteTranslucentR;
  2254. pThing->shade = 0; // -12;
  2255. break;
  2256. case kThingBloodDrip:
  2257. pThing->picnum = kAnmDrip;
  2258. pThing->pal = kPLURed;
  2259. //pThing->cstat |= kSpriteTranslucent | kSpriteTranslucentR;
  2260. pThing->shade = 0; // -12;
  2261. break;
  2262. }
  2263. return nThing;
  2264. }
  2265. int actFireThing( int nActor, int z, int nSlope, int thingType, int velocity )
  2266. {
  2267. dassert( thingType >= kThingBase && thingType < kThingMax );
  2268. SPRITE *pActor = &sprite[nActor];
  2269. int nThing = actSpawnThing(pActor->sectnum,
  2270. pActor->x + mulscale30(pActor->clipdist << 2, Cos(pActor->ang)),
  2271. pActor->y + mulscale30(pActor->clipdist << 2, Sin(pActor->ang)),
  2272. z, thingType);
  2273. SPRITE *pThing = &sprite[nThing];
  2274. pThing->owner = (short)nActor;
  2275. pThing->ang = pActor->ang;
  2276. pThing->xvel = (short)mulscale30(velocity, Cos(pActor->ang));
  2277. pThing->yvel = (short)mulscale30(velocity, Sin(pActor->ang));
  2278. pThing->zvel = (short)mulscale(velocity, nSlope, 14);
  2279. pThing->xvel += pActor->xvel / 2;
  2280. pThing->yvel += pActor->yvel / 2;
  2281. pThing->zvel += pActor->zvel / 2;
  2282. return nThing;
  2283. }
  2284. void actFireMissile( int nActor, int z, int dx, int dy, int dz, int missileType )
  2285. {
  2286. dassert( missileType >= kMissileBase && missileType < kMissileMax );
  2287. SPRITE *pActor = &sprite[nActor];
  2288. int nSprite = actSpawnSprite(pActor->sectnum,
  2289. pActor->x + mulscale30(pActor->clipdist << 1, Cos(pActor->ang)),
  2290. pActor->y + mulscale30(pActor->clipdist << 1, Sin(pActor->ang)),
  2291. z, kStatMissile, TRUE );
  2292. SPRITE *pSprite = &sprite[nSprite];
  2293. pSprite->type = (short)missileType;
  2294. MissileType *pMissType = &missileInfo[ missileType - kMissileBase ];
  2295. int velocity = pMissType->velocity;
  2296. pSprite->shade = pMissType->shade;
  2297. pSprite->pal = 0;
  2298. pSprite->clipdist = 16;
  2299. pSprite->flags = kAttrMove;
  2300. pSprite->xrepeat = pMissType->xrepeat;
  2301. pSprite->yrepeat = pMissType->yrepeat;
  2302. pSprite->picnum = pMissType->picnum;
  2303. pSprite->ang = (short)((pActor->ang +
  2304. missileInfo[missileType - kMissileBase].angleOfs) & kAngleMask);
  2305. pSprite->xvel = (short)mulscale(velocity, dx, 14);
  2306. pSprite->yvel = (short)mulscale(velocity, dy, 14);
  2307. pSprite->zvel = (short)mulscale(velocity, dz, 14);
  2308. pSprite->owner = (short)nActor;
  2309. SetBitString(show2dsprite, nSprite);
  2310. int nXSprite = pSprite->extra;
  2311. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  2312. XSPRITE *pXSprite = &xsprite[nXSprite];
  2313. switch( missileType )
  2314. {
  2315. case kMissileButcherKnife:
  2316. pSprite->cstat |= kSpriteWall;
  2317. break;
  2318. case kMissileSpear:
  2319. pSprite->cstat |= kSpriteWall;
  2320. break;
  2321. case kMissileEctoSkull:
  2322. seqSpawn(kSeqSkull, SS_SPRITE, nXSprite);
  2323. break;
  2324. case kMissileFireball:
  2325. seqSpawn(kSeqFireball, SS_SPRITE, nXSprite, &FireballCallback);
  2326. break;
  2327. case kMissileHoundFire:
  2328. seqSpawn(kSeqHoundFire, SS_SPRITE, nXSprite);
  2329. pSprite->xvel += (pActor->xvel / 2) + BiRandom(50);
  2330. pSprite->yvel += (pActor->yvel / 2) + BiRandom(50);
  2331. pSprite->zvel += (pActor->zvel / 2) + BiRandom(50);
  2332. break;
  2333. case kMissileSprayFlame:
  2334. if ( Chance(0x8000) )
  2335. seqSpawn(kSeqSprayFlame1, SS_SPRITE, nXSprite);
  2336. else
  2337. seqSpawn(kSeqSprayFlame2, SS_SPRITE, nXSprite);
  2338. pSprite->xvel += (pActor->xvel / 2) + BiRandom(50);
  2339. pSprite->yvel += (pActor->yvel / 2) + BiRandom(50);
  2340. pSprite->zvel += (pActor->zvel / 2) + BiRandom(50);
  2341. break;
  2342. case kMissileStarburstFlare:
  2343. evPost(nSprite, SS_SPRITE, kTimerRate/6 ); // callback to flare
  2344. break;
  2345. case kMissileFlare:
  2346. case kMissileExplodingFlare:
  2347. //seqSpawn(kSeqFlare, SS_SPRITE, nXSprite, &FlareCallback);
  2348. //pSprite->pal = kPLURed;
  2349. break;
  2350. default:
  2351. break;
  2352. }
  2353. }
  2354. /***********************************************************************
  2355. * actSpawnEffect()
  2356. *
  2357. * Spawns an effect sprite at the specified world coordinates.
  2358. **********************************************************************/
  2359. SPRITE *actSpawnEffect( short nSector, int x, int y, int z, int nEffect )
  2360. {
  2361. int nSprite = actSpawnSprite(nSector, x, y, z, kStatEffect, TRUE);
  2362. SPRITE *pSprite = &sprite[nSprite];
  2363. int nXSprite = pSprite->extra;
  2364. dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
  2365. switch( nEffect )
  2366. {
  2367. case ET_Splash1: // splash from dude landing in water
  2368. seqSpawn(kSeqSplash1, SS_SPRITE, nXSprite);
  2369. break;
  2370. case ET_Splash2: // splash from bullet hitting water
  2371. seqSpawn(kSeqSplash2, SS_SPRITE, nXSprite);
  2372. break;
  2373. case ET_Ricochet1: // bullet ricochet off stone/metal
  2374. if ( Chance(0x8000) )
  2375. pSprite->cstat |= kSpriteFlipX;
  2376. seqSpawn(kSeqRicochet1, SS_SPRITE, nXSprite);
  2377. break;
  2378. case ET_Ricochet2: // bullet ricochet off wood/dirt/clay
  2379. if ( Chance(0x8000) )
  2380. pSprite->cstat |= kSpriteFlipX;
  2381. seqSpawn(kSeqRicochet2, SS_SPRITE, nXSprite);
  2382. break;
  2383. case ET_Squib1:
  2384. if ( Chance(0x8000) )
  2385. pSprite->cstat |= kSpriteFlipX;
  2386. seqSpawn(kSeqSquib1, SS_SPRITE, nXSprite);
  2387. break;
  2388. case ET_SmokeTrail:
  2389. if ( Chance(0x8000) )
  2390. pSprite->cstat |= kSpriteFlipX;
  2391. if ( Chance(0x8000) )
  2392. pSprite->cstat |= kSpriteFlipY;
  2393. seqSpawn(kSeqFlareSmoke, SS_SPRITE, nXSprite);
  2394. break;
  2395. default:
  2396. // don't have a sequence yet, so just delete it for now
  2397. dprintf("actSpawnEffect: missing sequence\n");
  2398. actPostSprite( nSprite, kStatFree );
  2399. return NULL;
  2400. }
  2401. return pSprite;
  2402. }
  2403. BOOL actCheckRespawn( int nSprite )
  2404. {
  2405. SPRITE *pSprite = &sprite[nSprite];
  2406. if ( pSprite->extra > 0 )
  2407. {
  2408. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  2409. if (pXSprite->respawn == kRespawnPermanent)
  2410. return TRUE;
  2411. // if (sprite respawn is forced OR (sprite has optional respawning set
  2412. // AND (sprite is a dude AND global dude respawning is set)
  2413. // OR (sprite is a thing AND global thing respawning is set)))
  2414. if (pXSprite->respawn == kRespawnAlways || (pXSprite->respawn == kRespawnOptional
  2415. && (pSprite->type >= kDudeBase && pSprite->type < kDudeMax && gRespawnEnemies)
  2416. || ((pSprite->type < kDudeBase || pSprite->type > kDudeMax) && gRespawnItems)))
  2417. {
  2418. if (pXSprite->respawnTime > 0)
  2419. {
  2420. dprintf("Respawn statnum: %d\n",pSprite->statnum);
  2421. pSprite->owner = pSprite->statnum; // store the sprite's status list for respawning
  2422. actPostSprite( nSprite, kStatRespawn );
  2423. pSprite->cstat &= ~kSpriteBlocking & ~kSpriteHitscan;
  2424. pSprite->cstat |= kSpriteInvisible;
  2425. evPost(nSprite, SS_SPRITE, pXSprite->respawnTime * kTimerRate / 10, kCommandRespawn);
  2426. return TRUE;
  2427. }
  2428. }
  2429. }
  2430. return FALSE; // indicate sprite will not respawn, and should be deleted, exploded, etc.
  2431. }
  2432. void actRespawnDude( int nSprite )
  2433. {
  2434. SPRITE *pSprite = &sprite[nSprite];
  2435. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  2436. // probably need more dude-specific initialization
  2437. pXSprite->moveState = 0;
  2438. pXSprite->aiState = 0;
  2439. pXSprite->health = 0;
  2440. pXSprite->target = 0;
  2441. pXSprite->targetX = 0;
  2442. pXSprite->targetY = 0;
  2443. pXSprite->targetZ = 0;
  2444. pXSprite->key = 0; // respawned dudes don't drop additional permanent keys
  2445. }
  2446. void actRespawnSprite( int nSprite )
  2447. {
  2448. SPRITE *pSprite = &sprite[nSprite];
  2449. actPostSprite( nSprite, pSprite->owner );
  2450. pSprite->owner = -1;
  2451. pSprite->cstat &= ~kSpriteInvisible;
  2452. if ( pSprite->extra > 0)
  2453. {
  2454. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  2455. pXSprite->isTriggered = 0;
  2456. if (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)
  2457. actRespawnDude( nSprite );
  2458. }
  2459. // spawn the respawn special effect
  2460. int nRespawn = actSpawnSprite( pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, kStatDefault, TRUE );
  2461. seqSpawn(kSeqRespawn, SS_SPRITE, sprite[nRespawn].extra);
  2462. }
  2463. void actFireVector( int nActor, int z, int dx, int dy, int dz, VECTOR_TYPE vectorType )
  2464. {
  2465. SPRITE *pActor = &sprite[nActor];
  2466. HITINFO hitInfo;
  2467. dassert(vectorType >= 0 && vectorType < kVectorMax);
  2468. VECTORDATA *pVectorData = &gVectorData[vectorType];
  2469. int maxDist = pVectorData->maxDist;
  2470. int hitCode = VectorScan( pActor, z, dx, dy, dz, &hitInfo );
  2471. // determine a point just a bit back from the intersection to place the ricochet
  2472. int rx = hitInfo.hitx - mulscale(dx, 1 << 4, 14);
  2473. int ry = hitInfo.hity - mulscale(dy, 1 << 4, 14);
  2474. int rz = hitInfo.hitz - mulscale(dz, 1 << 4, 14);
  2475. BYTE nSurf = kSurfNone;
  2476. if ( maxDist == 0 || qdist(hitInfo.hitx - pActor->x, hitInfo.hity - pActor->y) < maxDist )
  2477. {
  2478. switch ( hitCode )
  2479. {
  2480. case SS_CEILING:
  2481. if ( sector[hitInfo.hitsect].ceilingstat & kSectorParallax )
  2482. nSurf = kSurfNone;
  2483. else
  2484. nSurf = surfType[sector[hitInfo.hitsect].ceilingpicnum];
  2485. break;
  2486. case SS_FLOOR:
  2487. if ( sector[hitInfo.hitsect].floorstat & kSectorParallax )
  2488. nSurf = kSurfNone;
  2489. else
  2490. nSurf = surfType[sector[hitInfo.hitsect].floorpicnum];
  2491. break;
  2492. case SS_WALL:
  2493. {
  2494. int nWall = hitInfo.hitwall;
  2495. dassert( nWall >= 0 && nWall < kMaxWalls );
  2496. nSurf = surfType[wall[nWall].picnum];
  2497. WALL *pWall = &wall[nWall];
  2498. int nXWall = wall[nWall].extra;
  2499. if ( nXWall > 0 )
  2500. {
  2501. XWALL *pXWall = &xwall[nXWall];
  2502. if ( pXWall->triggerImpact )
  2503. trTriggerWall(nWall, pXWall, kCommandWallImpact);
  2504. }
  2505. break;
  2506. }
  2507. case SS_MASKED:
  2508. {
  2509. int nWall = hitInfo.hitwall;
  2510. dassert( nWall >= 0 && nWall < kMaxWalls );
  2511. nSurf = surfType[wall[nWall].overpicnum];
  2512. WALL *pWall = &wall[nWall];
  2513. int nXWall = wall[nWall].extra;
  2514. if ( nXWall > 0 )
  2515. {
  2516. XWALL *pXWall = &xwall[nXWall];
  2517. if ( pXWall->triggerImpact )
  2518. trTriggerWall(nWall, pXWall, kCommandWallImpact);
  2519. }
  2520. break;
  2521. }
  2522. case SS_SPRITE:
  2523. {
  2524. int nSprite = hitInfo.hitsprite;
  2525. nSurf = surfType[sprite[nSprite].picnum];
  2526. dassert( nSprite >= 0 && nSprite < kMaxSprites);
  2527. SPRITE *pSprite = &sprite[nSprite];
  2528. // back off ricochet (squibs) even more
  2529. rx -= mulscale(dx, 7 << 4, 14);
  2530. ry -= mulscale(dy, 7 << 4, 14);
  2531. rz -= mulscale(dz, 7 << 4, 14);
  2532. actDamageSprite(nActor, nSprite, pVectorData->damageType,
  2533. pVectorData->damageValue << 4);
  2534. int nXSprite = pSprite->extra;
  2535. if ( nXSprite > 0 )
  2536. {
  2537. XSPRITE *pXSprite = &xsprite[nXSprite];
  2538. if ( pXSprite->triggerImpact )
  2539. trTriggerSprite(nSprite, pXSprite, kCommandSpriteImpact);
  2540. }
  2541. break;
  2542. }
  2543. }
  2544. }
  2545. if ( pVectorData->impact[nSurf].nEffect >= 0 )
  2546. actSpawnEffect(hitInfo.hitsect, rx, ry, rz, pVectorData->impact[nSurf].nEffect);
  2547. if ( pVectorData->impact[nSurf].nSoundId >= 0 )
  2548. sfxCreate3DSound(rx, ry, rz, pVectorData->impact[nSurf].nSoundId);
  2549. }
  2550. static void FireballCallback( int /* type */, int nXIndex )
  2551. {
  2552. XSPRITE *pXSprite = &xsprite[nXIndex];
  2553. int nSprite = pXSprite->reference;
  2554. SPRITE *pSprite = &sprite[nSprite];
  2555. SPRITE *pSmoke = actSpawnEffect( pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, ET_SmokeTrail );
  2556. if (gDetail < kDetailLevelMax)
  2557. pSmoke->cstat |= kSpriteInvisible;
  2558. }
  2559. //static void FlareCallback( int /* type */, int nXIndex )
  2560. //{
  2561. // XSPRITE *pXSprite = &xsprite[nXIndex];
  2562. // int nSprite = pXSprite->reference;
  2563. // SPRITE *pSprite = &sprite[nSprite];
  2564. //
  2565. // actSpawnEffect( pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, ET_SmokeTrail );
  2566. //}
  2567. struct POSTPONE
  2568. {
  2569. short nSprite;
  2570. short nStatus;
  2571. };
  2572. int gPostCount = 0;
  2573. POSTPONE gPost[ kMaxSprites ];
  2574. /***********************************************************************
  2575. * actPostSprite()
  2576. *
  2577. * Postpones deletion or status list change for a sprite.
  2578. * An nStatus value of kStatFree passed to this function will
  2579. * postpone deletion of the sprite until the gPostpone list is
  2580. * next processed.
  2581. **********************************************************************/
  2582. void actPostSprite( int nSprite, int nStatus )
  2583. {
  2584. dassert( gPostCount < kMaxSprites );
  2585. dassert( nSprite < kMaxSprites && sprite[nSprite].statnum < kMaxStatus );
  2586. dassert( nStatus >= 0 && nStatus <= kStatFree );
  2587. // see if it is already in the list (we may want to semaphore with an attr bit for speed)
  2588. for (int n = 0; n < gPostCount; n++)
  2589. if ( gPost[n].nSprite == nSprite )
  2590. break;
  2591. gPost[n].nSprite = (short)nSprite;
  2592. gPost[n].nStatus = (short)nStatus;
  2593. if ( n == gPostCount )
  2594. gPostCount++;
  2595. }
  2596. /***********************************************************************
  2597. * actPostProcess()
  2598. *
  2599. * Processes postponed sprite events to ensure that sprite list
  2600. * processing functions normally when sprites are deleted or change
  2601. * status.
  2602. *
  2603. **********************************************************************/
  2604. void actPostProcess( void )
  2605. {
  2606. if (gPostCount)
  2607. {
  2608. for ( int i = 0; i < gPostCount; i++ )
  2609. {
  2610. POSTPONE *pPost = &gPost[i];
  2611. if ( pPost->nStatus == kStatFree )
  2612. deletesprite( pPost->nSprite );
  2613. else
  2614. changespritestat( pPost->nSprite, pPost->nStatus );
  2615. }
  2616. gPostCount = 0;
  2617. }
  2618. }
  2619. static void MakeSplash( SPRITE *pSprite, XSPRITE *pXSprite )
  2620. {
  2621. int nXSprite = pSprite->extra;
  2622. int nSprite = pXSprite->reference;
  2623. pSprite->flags &= ~kAttrGravity; // no bouncing...
  2624. pSprite->z -= 4 << 8; // up one pixel
  2625. viewBackupSpriteLoc(nSprite, pSprite); // prevent interpolation
  2626. int nSurfType = tileGetSurfType(gSpriteHit[nXSprite].floorHit);
  2627. switch ( pSprite->type )
  2628. {
  2629. case kThingWaterDrip:
  2630. switch (nSurfType)
  2631. {
  2632. case kSurfWater:
  2633. seqSpawn(kSeqSplash1, SS_SPRITE, nXSprite);
  2634. sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z,
  2635. kSfxDrip3, 0x2000);
  2636. // add a check for depth that uses either kSfxDrip2 (deep) or kSfxDrip3 (not deep)
  2637. break;
  2638. default:
  2639. seqSpawn(kSeqSplash2, SS_SPRITE, nXSprite);
  2640. sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z,
  2641. kSfxDrip1, 0x2000);
  2642. break;
  2643. }
  2644. break;
  2645. case kThingBloodDrip:
  2646. seqSpawn(kSeqSplash3, SS_SPRITE, nXSprite);
  2647. sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z,
  2648. kSfxDrip1, 0x2000);
  2649. break;
  2650. }
  2651. }