person.cpp 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // person.cpp
  19. // Project: Postal
  20. //
  21. // This module implements the CPerson class which is mostly a test object
  22. // the the most basic functionality of the enemy guys derrived from CDoofus.
  23. //
  24. // History:
  25. //
  26. // 04/28/97 BRH Started this person to be the generic Enemy/Victim
  27. // that will use the structures set up in
  28. // Personatorium to determine the abilities and
  29. // desired logic.
  30. //
  31. // 04/30/97 BRH Fixed up the EditModify dialog box to select any type
  32. // of personality and any type of weapon. Modified the
  33. // Update to shoot any weapon.
  34. //
  35. // 05/11/97 BRH Imported the Update function from CDoofus. CDoofus will
  36. // most likely make its Update funciton pure virtual so that
  37. // it is up to the derived classes to move from state to
  38. // state.
  39. //
  40. // 05/12/97 BRH Added the crawling special case for the Cop and Gunner in
  41. // Logic_Writhing. Added the logic for the circle fight
  42. // and retreat in CDoofus.
  43. //
  44. // 05/19/97 JMI Added ms_u16IdLogAI and EditModify() code to check and
  45. // change it.
  46. //
  47. // 05/19/97 JMI Added m_szLogicFile, m_sShowState, and Render() override.
  48. // Can change m_szLogicFile and m_sShowState in EditModify().
  49. //
  50. // 05/19/97 BRH Saved the m_sShowState variable so that it works during
  51. // play mode. Changed the name of the logic file to an
  52. // RString and added the RString load and save to the
  53. // CPerson load and save functions.
  54. //
  55. // 05/20/97 BRH Making the high level actions more concrete by adding
  56. // Actions as a higher level concept than the states. Each
  57. // action may consist of several pre-programmed state
  58. // sequences. At good evaluation points in each action,
  59. // it will check the suggested logic action and change states
  60. // to perform that action.
  61. //
  62. // 05/21/97 BRH Added Resource management for ShootRun animation.
  63. //
  64. // 05/22/97 JMI FreeResources() was releasing m_pLogicTable in g_resmgrGame
  65. // instead of g_resmgrRes (which is where it was
  66. // rspGetResource'ed from).
  67. //
  68. // 05/23/97 JMI Added NULLs for new pszEventName parameter to
  69. // CAnim3D::Get()s indicating to load no events.
  70. //
  71. // 05/25/97 BRH Added Release calls for the new animations.
  72. //
  73. // 05/25/97 JMI Changed "Personality.GUI" to "Person.GUI".
  74. //
  75. // 05/26/97 BRH Calls CDoofus::OnDead rather than the CCharacter version.
  76. //
  77. // 06/02/97 BRH Added case for State_HuntHold.
  78. //
  79. // 06/04/97 BRH Fixed Writing crawl to use the m_AnimRot so that it faces
  80. // the correct direction.
  81. //
  82. // 06/05/97 JMI Changed m_sHitPoints to m_stockpile.m_sHitPoints to
  83. // accommodate new m_stockpile in base class, CThing3d (which
  84. // used to contain the m_sHitPoints).
  85. //
  86. // 06/10/97 BRH Sends Death certificate to CDemon.
  87. //
  88. // 06/10/97 BRH Added Search and Crouch animations to Get and Free Resources
  89. //
  90. // 06/13/97 JMI Now GetResources() loads events for animations that need
  91. // them.
  92. //
  93. // 06/15/97 BRH Adjusted the time and comment count so people don't
  94. // speak as often.
  95. //
  96. // 06/16/97 BRH Tried Aborting any shot sounds if it wasn't done playing.
  97. // If it doesn sound good, then we will just verify that
  98. // the previous sample is done before playing the next one.
  99. // We were thinking that it may sound cool if he interrupted
  100. // "My leg" before saying "Ug".
  101. //
  102. // 06/16/97 BRH Switched to IsSamplePlaying rather than aborting, because
  103. // the phrases were rarely finished before aborting so you
  104. // never got to hear them if you kept shooting.
  105. //
  106. // 06/17/97 BRH Took out IsSamplePlaying because it screws up the network
  107. // mode because the Sample can play for different intervals
  108. // on different systems.
  109. //
  110. // 06/18/97 BRH Enabled the Shooting sounds.
  111. //
  112. // 06/18/97 JMI Changed PlaySoundWrithing() to return the duration of the
  113. // played sample.
  114. //
  115. // 06/18/97 BRH Changed to using GetRandom();
  116. //
  117. // 06/18/97 JMI Now uses the sample duration returned from PlaySample()
  118. // instead of getting it from the RSnd.
  119. //
  120. // 06/25/97 JMI Now calls PrepareShadow() in Init() which loads and sets up
  121. // a shadow sprite.
  122. //
  123. // 06/27/97 JMI Now shows weapon type when in edit mode via EditRender().
  124. //
  125. // 06/30/97 BRH Changed the random type sounds to play and then purge to
  126. // save memory. Cached the other sound effects during the
  127. // load for each different person type loaded so that their
  128. // sounds won't pause the game when they are first shot,
  129. // set on fire, etc.
  130. //
  131. // 07/03/97 JMI Converted calls to rspOpen/SaveBox() to new parm
  132. // conventions.
  133. //
  134. // 07/04/97 BRH Changed run and shoot prefix from run45rt to 45rt to
  135. // match the exported names. Also added a substitution of
  136. // the run animation if there is no onfire animation since
  137. // the victims don't yet have an onfire animaiton.
  138. //
  139. // 07/06/97 BRH Added new victim states to the Update function.
  140. //
  141. // 07/08/97 BRH Changed run backwards animation name to runbackwr since
  142. // some of the filenames were too long for the delicate
  143. // MacOS.
  144. //
  145. // 07/17/97 BRH Added delay shoot case in update.
  146. //
  147. // 07/17/97 JMI Changed RSnd*'s to SampleMaster::SoundInstances.
  148. // Now uses new SampleMaster interface for volume and play
  149. // instance reference.
  150. //
  151. // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
  152. // Now there is one PlaySample() function. Also, you now
  153. // MUST specify a category and you don't have to specify a
  154. // SoundInstance ptr to specify a volume.
  155. //
  156. // 07/21/97 JMI Now Update() calls CCharacter version (note that this is
  157. // skipping CDoofus::Update() ).
  158. //
  159. // 07/23/97 BRH Checks for a live dude before making a random comment so
  160. // that they don't say stupid things after the CDude is dead.
  161. //
  162. // 07/26/97 BRH Changed the initial setting of hit points from the CThing3D
  163. // default value to using the new value in the personatorium.
  164. //
  165. // 08/01/97 BRH Enemies now upgrade their weapons if the game is set
  166. // on difficulty 11. Guns are upgraded to Assault Weapons
  167. // and rockets are upgraded to heatseekers. Also added
  168. // case for State_AvoidFire and State_DangerNear.
  169. //
  170. // 08/06/97 JMI Now loads execution target points for writhing mode.
  171. // Also, now uses CDoofus's PositionSmash() for positioning
  172. // the main smash.
  173. //
  174. // 08/07/97 JMI Now loads new resname gotten from Personatorium for the
  175. // linkpoint/rigid-body for the person's hand.
  176. // Now calls CDoofus' GetResources()/ReleaseResources() to
  177. // get and release resources for weapons.
  178. //
  179. // 08/08/97 JMI Now does not display the mines in the EditModify().
  180. //
  181. // 08/08/97 JMI Upgraded to use all the new weapons.
  182. // Now does the weapon upgrade for difficulty 11 in only
  183. // when editing flag is set to false in the realm so it does
  184. // not occur in the editor.
  185. //
  186. // 08/09/97 BRH Added TRACE message for invalid state type - so if it
  187. // it happens sgain where a state is not accounted for in
  188. // the Update switch statement, it will print the number
  189. // and them attempt to print the description of the state
  190. // for debugging purposes.
  191. //
  192. // 08/10/97 BRH Fixed problem with executions when people yelled
  193. // things like ah my leg when they were being executed.
  194. // Changed this to a generic grunt that should work
  195. // for all people.
  196. //
  197. // 08/11/97 JMI Now sets backup weapon type based on personatorium.
  198. // Also, added case for State_WalkNext to Update()'s logic
  199. // switch.
  200. //
  201. // 08/12/97 JMI Now loads main event for all animations.
  202. //
  203. // 08/12/97 BRH Added missing case statement for Hide and HideBegin.
  204. // Also upped the number of random comments for the victims
  205. // (the ones in panic mode so that they will scream and
  206. // yell more often when in panic mode). Also added
  207. // special case for shot sound effects where the first
  208. // shot sound will be the comment, and the other 3 just
  209. // noises. Once the comment is played (randomly chosen)
  210. // the m_bHitComment will be set so it doesn't get played
  211. // again.
  212. //
  213. // 08/14/97 JMI Switched references to g_GameSettings.m_sDifficulty to
  214. // m_pRealm->m_flags.sDifficulty.
  215. //
  216. // 08/17/97 BRH Slowed writhing crawl velocity from 5 to 2.5
  217. //
  218. // 08/20/97 BRH Changed the sound categories from voice to voice and
  219. // the new pain and suffering categories.
  220. //
  221. // 08/24/97 JMI Also, now the gunner type of motion (PushBack) also dies
  222. // when it hits something.
  223. // Now checks a point that should be the person's furthest
  224. // extremity when he's writhing and if that point goes into
  225. // anything he acts the same as if his main attrib check area
  226. // hit it except he ignores the height (that is, he treats it
  227. // all as no walk)
  228. //
  229. // 08/24/97 BRH The PlaySound functions now set the new doofus m_siPlaying
  230. // sound instance so that it can be aborted when the guy is
  231. // killed so he doesn't keep making noises, especially after
  232. // being executed.
  233. //
  234. // 08/25/97 JMI When I added the last change on checking their heads'
  235. // while writhing, I inadvertently took out the check to kill
  236. // them if they're feet hit something. Since there moving
  237. // in the direction of their head, this shouldn't've been a
  238. // problem, but it's worth fixing. Fixed.
  239. //
  240. // 08/26/97 BRH Added special case for the people who have a description
  241. // starting with "Kid". The Kids smash bits are set to zero
  242. // so that they cannot be hit by weapons for the final
  243. // scene.
  244. //
  245. // 08/28/97 BRH Fixed the push back code in Logic_Writhing
  246. //
  247. // 08/29/97 BRH Added static variable for the logic table to use to set
  248. // group motions.
  249. //
  250. // 09/03/97 JMI Civilians now use Civilian Smash bit instead of Bad.
  251. //
  252. // 10/24/97 JMI Added Mac specific code to make sure browsed-for logic
  253. // files are relative paths.
  254. //
  255. // 01/14/98 JMI Added more descriptive alert (than the ASSERT(0) ) for
  256. // unexpected states in the main switch() based on the TRACEs
  257. // Bill had.
  258. //
  259. // 10/03/99 JMI Now launches TexEdit when Edit Textures... chosen.
  260. //
  261. // 10/06/99 JMI Now only adds the sTextureScheme if it is non-negative.
  262. // Now passes the hood lights to the texture editor.
  263. //
  264. ////////////////////////////////////////////////////////////////////////////////
  265. #define PERSON_CPP
  266. #include "RSPiX.h"
  267. #include <math.h>
  268. #include "person.h"
  269. #include "TexEdit.h"
  270. ////////////////////////////////////////////////////////////////////////////////
  271. // Macros/types/etc.
  272. ////////////////////////////////////////////////////////////////////////////////
  273. #define NEAR_DEATH_HITPOINTS 20
  274. #define MS_BETWEEN_SAMPLES 100
  275. #define PERSONALITY_ITEM_ID_BASE 200
  276. ////////////////////////////////////////////////////////////////////////////////
  277. // Variables/data
  278. ////////////////////////////////////////////////////////////////////////////////
  279. // These are default values -- actually values are set using the editor!
  280. double CPerson::ms_dLongRange = 500*500; // Squared distance (500 pixels away)
  281. double CPerson::ms_dInRangeLow = 190*190; // Squared distance to be in range with weapon
  282. double CPerson::ms_dInRangeHigh = 230*230; // Squared distance to be in range with weapon
  283. double CPerson::ms_dThrowHorizVel = 200; // Throw out at this velocity
  284. double CPerson::ms_dMaxCrawlVel = 2.5; // Speed at which cop crawls
  285. long CPerson::ms_lMinCommentTime = 10000; // Amount of time before making a comment
  286. long CPerson::ms_lCommentTimeVariance = 35000;// Random amount added on.
  287. long CPerson::ms_lRandomAvoidTime = 200; // Time to wander before looking again
  288. long CPerson::ms_lReseekTime = 1000; // Do a 'find' again
  289. long CPerson::ms_lWatchWaitTime = 5000; // Time to watch shot go
  290. long CPerson::ms_lReselectDudeTime = 3000; // Time to go without finding a dude
  291. // before calling SelectDude() to find
  292. // possibly a closer one.
  293. short CPerson::ms_sLogTabUserGlobal = 0; // Logic table variable for group effects
  294. // Let this auto-init to 0
  295. short CPerson::ms_sFileCount;
  296. // This is the one CPerson that can log its AI table transitions or
  297. // CIdBank::IdNil.
  298. U16 CPerson::ms_u16IdLogAI = CIdBank::IdNil;
  299. // The max amount a guy and step up while writhing.
  300. #define WRITHING_VERTICAL_TOLERANCE (MaxStepUpThreshold / 2)
  301. #define ID_GUI_EDIT_TEXTURES 900
  302. //#ifdef MOBILE
  303. extern bool demoCompat;
  304. //#endif
  305. ////////////////////////////////////////////////////////////////////////////////
  306. // Load object (should call base class version!)
  307. ////////////////////////////////////////////////////////////////////////////////
  308. short CPerson::Load( // Returns 0 if successfull, non-zero otherwise
  309. RFile* pFile, // In: File to load from
  310. bool bEditMode, // In: True for edit mode, false otherwise
  311. short sFileCount, // In: File count (unique per file, never 0)
  312. ULONG ulFileVersion) // In: Version of file format to load.
  313. {
  314. short sResult = 0;
  315. sResult = CDoofus::Load(pFile, bEditMode, sFileCount, ulFileVersion);
  316. if (sResult == 0)
  317. {
  318. // Load common data just once per file (not with each object)
  319. if (ms_sFileCount != sFileCount)
  320. {
  321. ms_sFileCount = sFileCount;
  322. // Load static data
  323. switch (ulFileVersion)
  324. {
  325. default:
  326. case 1:
  327. pFile->Read(&ms_dLongRange);
  328. pFile->Read(&ms_dInRangeLow);
  329. pFile->Read(&ms_dInRangeHigh);
  330. pFile->Read(&ms_lRandomAvoidTime);
  331. pFile->Read(&ms_lReseekTime);
  332. pFile->Read(&ms_lWatchWaitTime);
  333. pFile->Read(&ms_lReselectDudeTime);
  334. break;
  335. }
  336. }
  337. UCHAR uc;
  338. // Load data specific to CPerson (if any)
  339. switch (ulFileVersion)
  340. {
  341. default:
  342. case 14:
  343. pFile->Read(&uc);
  344. m_ePersonType = (Personatorium::Index) uc;
  345. pFile->Read(&m_sShowState);
  346. m_rstrLogicFile.Load(pFile);
  347. break;
  348. case 1:
  349. case 2:
  350. case 3:
  351. case 4:
  352. case 5:
  353. case 6:
  354. case 7:
  355. case 8:
  356. case 9:
  357. case 10:
  358. case 11:
  359. case 12:
  360. case 13:
  361. {
  362. pFile->Read(&uc);
  363. m_ePersonType = (Personatorium::Index) uc;
  364. break;
  365. }
  366. }
  367. // Cache the samples that this type of person uses
  368. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidSuffering1));
  369. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidSuffering2));
  370. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidSuffering3));
  371. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidSuffering4));
  372. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShot1));
  373. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShot2));
  374. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShot3));
  375. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShot4));
  376. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidBlownup1));
  377. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidBlownup2));
  378. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidBurning1));
  379. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidBurning2));
  380. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidDying1));
  381. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidDying2));
  382. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShooting1));
  383. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShooting2));
  384. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShooting3));
  385. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidShooting4));
  386. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidRandom1));
  387. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidRandom2));
  388. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidRandom3));
  389. CacheSample(*(g_apersons[m_ePersonType].Sample.psmidRandom4));
  390. m_bCivilian = (g_apersons[m_ePersonType].eLifestyle == Personatorium::Civilian);
  391. // Make sure there were no file errors or format errors . . .
  392. if (!pFile->Error() && sResult == 0)
  393. {
  394. // Get resources
  395. sResult = GetResources();
  396. }
  397. else
  398. {
  399. sResult = -1;
  400. TRACE("CPerson::Load(): Error reading from file!\n");
  401. }
  402. }
  403. else
  404. {
  405. TRACE("CPerson::Load(): CDoofus::Load() failed.\n");
  406. }
  407. return sResult;
  408. }
  409. ////////////////////////////////////////////////////////////////////////////////
  410. // Save object (should call base class version!)
  411. ////////////////////////////////////////////////////////////////////////////////
  412. short CPerson::Save( // Returns 0 if successfull, non-zero otherwise
  413. RFile* pFile, // In: File to save to
  414. short sFileCount) // In: File count (unique per file, never 0)
  415. {
  416. short sResult = SUCCESS;
  417. // Call the base class save to save the u16InstanceID
  418. CDoofus::Save(pFile, sFileCount);
  419. // Save common data just once per file (not with each object)
  420. if (ms_sFileCount != sFileCount)
  421. {
  422. ms_sFileCount = sFileCount;
  423. // Save static data
  424. pFile->Write(&ms_dLongRange);
  425. pFile->Write(&ms_dInRangeLow);
  426. pFile->Write(&ms_dInRangeHigh);
  427. pFile->Write(&ms_lRandomAvoidTime);
  428. pFile->Write(&ms_lReseekTime);
  429. pFile->Write(&ms_lWatchWaitTime);
  430. pFile->Write(&ms_lReselectDudeTime);
  431. }
  432. // Save imbecile specific data if any
  433. pFile->Write((UCHAR*) &m_ePersonType);
  434. pFile->Write(&m_sShowState);
  435. m_rstrLogicFile.Save(pFile);
  436. if (!pFile->Error())
  437. {
  438. sResult = SUCCESS;
  439. }
  440. else
  441. {
  442. TRACE("CPerson::Save() - Error writing to file\n");
  443. sResult = -1;
  444. }
  445. return sResult;
  446. }
  447. ////////////////////////////////////////////////////////////////////////////////
  448. // Startup object
  449. ////////////////////////////////////////////////////////////////////////////////
  450. short CPerson::Startup(void) // Returns 0 if successfull, non-zero otherwise
  451. {
  452. short sResult = 0;
  453. // Set the current height, previous time, and Nav Net
  454. CDoofus::Startup();
  455. // Init other stuff
  456. Init();
  457. return sResult;
  458. }
  459. ////////////////////////////////////////////////////////////////////////////////
  460. // Init - Call this after the resources are in place
  461. ////////////////////////////////////////////////////////////////////////////////
  462. short CPerson::Init(void)
  463. {
  464. short sResult = 0;
  465. // Prepare shadow (get resources and setup sprite).
  466. sResult = PrepareShadow();
  467. // Clear the hit comment
  468. m_bHitComment = false;
  469. // Init other stuff
  470. m_dVel = 0.0;
  471. m_dRot = 0.0;
  472. // Set to different starting state based on the design of the animation, but
  473. // for now, ok. Then also set his current animation.
  474. m_state = CCharacter::State_Guard;
  475. m_eCurrentAction = m_eSuggestedAction = CDoofus::Action_Guard;
  476. m_dAcc = ms_dAccUser;
  477. m_panimCur = &m_animStand;
  478. m_lTimer = m_pRealm->m_time.GetGameTime() + 500;
  479. // Stock up.
  480. m_stockpile.Copy(&CStockPile::ms_stockpileMax);
  481. m_stockpile.m_sHitPoints = g_apersons[m_ePersonType].sInitialHitPoints;
  482. // Get back up weapon type.
  483. m_eFallbackWeaponType = g_apersons[m_ePersonType].Weapon.idWeapon1;
  484. // If not civilian . . .
  485. if (g_apersons[m_ePersonType].eLifestyle != Personatorium::Civilian)
  486. {
  487. // Bad guy.
  488. m_smash.m_bits = CSmash::Bad | CSmash::Character;
  489. }
  490. else
  491. {
  492. // Civilian.
  493. m_smash.m_bits = CSmash::Civilian | CSmash::Character;
  494. }
  495. m_smash.m_pThing = this;
  496. // Special case for the kids who cannot be hit.
  497. if (strncmp(g_apersons[m_ePersonType].pszDescription, "Kid", 3) == 0)
  498. m_smash.m_bits = 0;
  499. m_sBrightness = 0; // Default Brightness level
  500. m_lCommentTimer = m_pRealm->m_time.GetGameTime() + ms_lMinCommentTime + GetRandom() % ms_lCommentTimeVariance;
  501. // Override the Doofus set timeout defaults by replacing the values with the
  502. // personatorium values.
  503. m_lGuardTimeout = g_apersons[m_ePersonType].lGuardTimeout;
  504. m_lRunShootInterval = g_apersons[m_ePersonType].lRunShootInterval;
  505. m_lShotReactionTimeout = g_apersons[m_ePersonType].lShotTimeout;
  506. // If the difficulty is set up to its highest level, then upgrade
  507. // guns to spray cannons and missiles to heatseekers.
  508. // Note we only do this if not in edit mode.
  509. if (m_pRealm->m_flags.sDifficulty == 11 && m_pRealm->m_flags.bEditing == false)
  510. {
  511. switch (m_eWeaponType)
  512. {
  513. case CUziID:
  514. case CAutoRifleID:
  515. case CSmallPistolID:
  516. case CPistolID:
  517. case CMachineGunID:
  518. case CShotGunID:
  519. m_eWeaponType = CAssaultWeaponID;
  520. break;
  521. case CRocketID:
  522. m_eWeaponType = CHeatseekerID;
  523. break;
  524. }
  525. }
  526. // Set initial group state to zero. If you use dispensers then initalizing
  527. // this value here would be bad, but this is a special case for the last
  528. // demo level with the kids and there aren't any dispensers on that level.
  529. ms_sLogTabUserGlobal = 0;
  530. return sResult;
  531. }
  532. ////////////////////////////////////////////////////////////////////////////////
  533. // Update object
  534. ////////////////////////////////////////////////////////////////////////////////
  535. void CPerson::Update(void)
  536. {
  537. CThing* pDemon = NULL;
  538. if (!m_sSuspend)
  539. {
  540. long lThisTime = m_pRealm->m_time.GetGameTime();
  541. // See if its time to reevaluate the states
  542. if (lThisTime > m_lEvalTimer)
  543. {
  544. m_lEvalTimer = lThisTime + 500 + (GetRandom() % 500);
  545. m_pLogicTable->Evaluate(this, ms_u16IdLogAI == GetInstanceID());
  546. }
  547. // Check for new messages that may change the state
  548. ProcessMessages();
  549. // See if its time to make a random comment yet
  550. if (lThisTime > m_lCommentTimer)
  551. {
  552. m_lCommentTimer = lThisTime + ms_lMinCommentTime + GetRandom() % ms_lCommentTimeVariance;
  553. PlaySoundRandom();
  554. }
  555. // See if there are any pylons nearby that he wants to use.
  556. // if (m_state == State_Idle ||
  557. // m_state == State_Wait ||
  558. // m_state == State_Hunt)
  559. // Logic_PylonDetect();
  560. switch (m_state)
  561. {
  562. case State_Guard:
  563. Logic_Guard();
  564. break;
  565. case State_PopBegin:
  566. Logic_PopBegin();
  567. break;
  568. case State_PopWait:
  569. Logic_PopWait();
  570. break;
  571. case State_Popout:
  572. Logic_Popout();
  573. break;
  574. case State_RunShootBegin:
  575. Logic_RunShootBegin();
  576. break;
  577. case State_RunShoot:
  578. Logic_RunShoot();
  579. break;
  580. case State_RunShootWait:
  581. Logic_RunShootWait();
  582. break;
  583. case State_Shoot:
  584. Logic_Shoot();
  585. break;
  586. case State_ShootRun:
  587. Logic_ShootRun();
  588. break;
  589. case State_Hunt:
  590. Logic_Hunt();
  591. break;
  592. case State_HuntNext:
  593. case State_MoveNext:
  594. case State_MarchNext:
  595. case State_WalkNext:
  596. Logic_MoveNext();
  597. break;
  598. case State_HuntHold:
  599. Logic_HuntHold();
  600. break;
  601. case State_Shot:
  602. Logic_Shot();
  603. break;
  604. case State_BlownUp:
  605. Logic_BlownUp();
  606. break;
  607. case State_Burning:
  608. Logic_Burning();
  609. break;
  610. case State_Die:
  611. Logic_Die();
  612. break;
  613. case State_Writhing:
  614. Logic_Writhing();
  615. break;
  616. case State_Engage:
  617. Logic_Engage();
  618. break;
  619. case State_PositionSet:
  620. Logic_PositionSet();
  621. break;
  622. case State_PositionMove:
  623. Logic_PositionMove();
  624. break;
  625. case State_Retreat:
  626. Logic_Retreat();
  627. break;
  628. case State_Dead:
  629. if ((m_ePersonType == Personatorium::Nude1) || (m_ePersonType == Personatorium::Nude2))
  630. UnlockAchievement(ACHIEVEMENT_KILL_A_NAKED_PERSON);
  631. GameMessage msg;
  632. msg.msg_Death.eType = typeDeath;
  633. msg.msg_Death.sPriority = 0;
  634. pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
  635. if (pDemon)
  636. SendThingMessage(&msg, pDemon);
  637. CDoofus::OnDead();
  638. delete this;
  639. return;
  640. break;
  641. case State_PanicBegin:
  642. Logic_PanicBegin();
  643. break;
  644. case State_PanicContinue:
  645. Logic_PanicContinue();
  646. // Call this a few times to make it happen more often, since
  647. // it normally happens only every 10th time.
  648. PlaySoundRandom();
  649. PlaySoundRandom();
  650. PlaySoundRandom();
  651. PlaySoundRandom();
  652. break;
  653. case State_WalkBegin:
  654. Logic_WalkBegin();
  655. break;
  656. case State_WalkContinue:
  657. Logic_WalkContinue();
  658. break;
  659. case State_DelayShoot:
  660. Logic_DelayShoot();
  661. break;
  662. case State_AvoidFire:
  663. Logic_AvoidFire();
  664. break;
  665. case State_Helping:
  666. Logic_Helping();
  667. break;
  668. case State_March:
  669. Logic_MarchBegin();
  670. break;
  671. case State_HideBegin:
  672. Logic_HideBegin();
  673. break;
  674. case State_Hide:
  675. Logic_Hide();
  676. break;
  677. default:
  678. // If it ever gets to this case, then it has entered an unknown
  679. // state which may perhaps be out of range. Please note the
  680. // value of the state to check to see if it is in the valid range
  681. // of states, and also note the m_ePreviousState to see if we can
  682. // detect where the error occurred.
  683. #if 1
  684. TRACE("Current state is %d - description is on next line if possible\n", m_state);
  685. if (m_state < NumThing3dStates)
  686. TRACE("Current state is %s\n", ms_apszStateNames[m_state]);
  687. ASSERT(0);
  688. ASSERT(m_state > 0);
  689. if (m_state == m_ePreviousState)
  690. TRACE("STATE-ALERT Probably an uninitialized previous state\n");
  691. #else
  692. if (rspMsgBox(
  693. RSP_MB_ICN_EXCLAIM | RSP_MB_BUT_YESNO,
  694. g_pszAppName,
  695. "Person.cpp encountered an unexpected state.\n"
  696. "Displaying the state's description may cause a crash.\n"
  697. "Would you like to see the state's description?\n"
  698. "%s",
  699. (m_state < 0) ? "The state is negative!!" : "") == RSP_MB_RET_YES)
  700. {
  701. rspMsgBox(
  702. RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
  703. g_pszAppName,
  704. "The state is \"%s\" (%ld).\n"
  705. "%s",
  706. ms_apszStateNames[m_state],
  707. m_state,
  708. (m_state == m_ePreviousState) ? "STATE-ALERT Probably an uninitialized previous state!" : "");
  709. }
  710. #endif
  711. break;
  712. }
  713. // Update the avoidance smash
  714. m_smashAvoid.m_sphere.sphere.X = m_dX + (rspCos(m_dRot) * ms_lAvoidRadius);
  715. m_smashAvoid.m_sphere.sphere.Y = m_dY;
  716. m_smashAvoid.m_sphere.sphere.Z = m_dZ - (rspSin(m_dRot) * ms_lAvoidRadius);
  717. // Determine appropriate position for main smash.
  718. PositionSmash();
  719. // Update the smash.
  720. m_pRealm->m_smashatorium.Update(&m_smash);
  721. m_lPrevTime = lThisTime;
  722. // Call base class //////////////////////////////////////////////////////
  723. CCharacter::Update();
  724. }
  725. }
  726. ////////////////////////////////////////////////////////////////////////////////
  727. // Render object.
  728. ////////////////////////////////////////////////////////////////////////////////
  729. void CPerson::Render(void)
  730. {
  731. if (m_sShowState != FALSE)
  732. {
  733. m_rstrLogicName = ms_apszStateNames[m_state];
  734. m_rstrLogicName += "/";
  735. m_rstrLogicName += ms_apszActionNames[m_eCurrentAction];
  736. m_sprite.m_pszText = (char*) m_rstrLogicName;
  737. // m_sprite.m_pszText = ms_apszStateNames[m_state];
  738. }
  739. else
  740. m_sprite.m_pszText = NULL;
  741. CDoofus::Render();
  742. }
  743. ////////////////////////////////////////////////////////////////////////////////
  744. // Called by editor to render object.
  745. ////////////////////////////////////////////////////////////////////////////////
  746. void CPerson::EditRender(void)
  747. {
  748. CDoofus::EditRender();
  749. if (m_sShowState != FALSE)
  750. {
  751. m_rstrLogicName += "/";
  752. WeaponDetails* pwd = GetWeaponDetails(m_eWeaponType);
  753. if (pwd)
  754. {
  755. m_rstrLogicName += pwd->pszName;
  756. }
  757. else
  758. {
  759. m_rstrLogicName += "Invalid weapon";
  760. }
  761. m_sprite.m_pszText = (char*) m_rstrLogicName;
  762. }
  763. else
  764. {
  765. WeaponDetails* pwd = GetWeaponDetails(m_eWeaponType);
  766. if (pwd)
  767. {
  768. m_sprite.m_pszText = pwd->pszName;
  769. }
  770. else
  771. {
  772. m_sprite.m_pszText = NULL;
  773. }
  774. }
  775. }
  776. ////////////////////////////////////////////////////////////////////////////////
  777. // Logic_Writhing - special case for the cop since he has to crawl
  778. ////////////////////////////////////////////////////////////////////////////////
  779. void CPerson::Logic_Writhing(void)
  780. {
  781. // m_dAnimRot = m_dRot;
  782. CDoofus::Logic_Writhing();
  783. // if (m_ePersonType == Personatorium::Cop || m_ePersonType == Personatorium::Gunner)
  784. if (g_apersons[m_ePersonType].eWrithingMotion != Personatorium::Still)
  785. {
  786. double dX = m_dX;
  787. double dZ = m_dZ;
  788. double dNewX;
  789. double dNewY;
  790. double dNewZ;
  791. double dSeconds = (m_pRealm->m_time.GetGameTime() - m_lPrevTime) / 1000.0;
  792. m_dAcc = ms_dAccUser;
  793. UpdateVelocities(dSeconds, ms_dMaxCrawlVel, ms_dMaxCrawlVel);
  794. GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
  795. if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, WRITHING_VERTICAL_TOLERANCE) == true)
  796. {
  797. // Update Values /////////////////////////////////////////////////////////
  798. m_dX = dNewX;
  799. m_dY = dNewY;
  800. m_dZ = dNewZ;
  801. UpdateFirePosition();
  802. }
  803. else
  804. {
  805. // Restore Values ////////////////////////////////////////////////////////
  806. m_dVel -= m_dDeltaVel;
  807. }
  808. #if 1
  809. // Get radius.
  810. short sRadius = m_sprite.m_sRadius;
  811. // Determine pseudo-head point.
  812. short sRot = rspMod360(m_dAnimRot);
  813. short sPseudoHeadX = m_dX + COSQ[sRot] * sRadius;
  814. short sPseudoHeadY = m_dZ - SINQ[sRot] * sRadius;
  815. // Check pseudo-head point.
  816. U16 u16Attrib = 0; // Safety.
  817. short sHeight = 0; // Safety.
  818. GetFloorAttributes(sPseudoHeadX, sPseudoHeadY, &u16Attrib, &sHeight);
  819. if ( (u16Attrib & REALM_ATTR_NOT_WALKABLE) || sHeight > m_dY + WRITHING_VERTICAL_TOLERANCE
  820. || (dX == m_dX && dZ == m_dZ) )
  821. {
  822. // Die real soon.
  823. m_stockpile.m_sHitPoints = 0;
  824. }
  825. else
  826. {
  827. if (g_apersons[m_ePersonType].eWrithingMotion == Personatorium::PushBack)
  828. {
  829. // If they are supposed to push themselves on their back, then the
  830. // animation angle and the direction angle need to be 180 degrees
  831. // apart.
  832. if (m_dRot != rspMod360(m_dAnimRot + 180))
  833. m_dRot = rspMod360(m_dAnimRot + 180);
  834. }
  835. }
  836. #else
  837. // if (m_ePersonType == Personatorium::Gunner)
  838. if (g_apersons[m_ePersonType].eWrithingMotion == Personatorium::PushBack)
  839. {
  840. #if 1
  841. // If he hits something, just make him die since his hotspot
  842. // is not in the correct place, he rotates around his feet
  843. // and it looks weird.
  844. m_stockpile.m_sHitPoints = 0;
  845. if (m_dRot != rspMod360(m_dAnimRot + 180))
  846. m_dRot = rspMod360(m_dAnimRot + 180);
  847. #else
  848. if (dX == m_dX && dZ == m_dZ)
  849. {
  850. // This is a sort of randomness that will make some turn left and
  851. // others turn right depending on if their rotation is even or odd.
  852. if (((short) m_dRot) & 0x01)
  853. m_dRot = rspMod360(m_dRot - 20);
  854. else
  855. m_dRot = rspMod360(m_dRot + 20);
  856. m_dAnimRot = rspMod360(m_dRot + 180);
  857. }
  858. #endif
  859. }
  860. else
  861. {
  862. // If he didn't move at all, then turn him so he will
  863. // avoid the wall
  864. if (dX == m_dX && dZ == m_dZ)
  865. {
  866. #if 1
  867. // If he hits something, just make him die since his hotspot
  868. // is not in the correct place, he rotates around his feet
  869. // and it looks weird.
  870. m_stockpile.m_sHitPoints = 0;
  871. #else
  872. // This is a sort of randomness that will make some turn left and
  873. // others turn right depending on if their rotation is even or odd.
  874. if (((short) m_dRot) & 0x01)
  875. m_dAnimRot = m_dShootAngle = m_dRot = rspMod360(m_dRot - 20);
  876. else
  877. m_dAnimRot = m_dShootAngle = m_dRot = rspMod360(m_dRot + 20);
  878. #endif
  879. }
  880. }
  881. #endif
  882. }
  883. }
  884. ////////////////////////////////////////////////////////////////////////////////
  885. // Shutdown object
  886. ////////////////////////////////////////////////////////////////////////////////
  887. short CPerson::Shutdown(void) // Returns 0 if successfull, non-zero otherwise
  888. {
  889. return 0;
  890. }
  891. ////////////////////////////////////////////////////////////////////////////////
  892. // Called by editor to init new object at specified position
  893. ////////////////////////////////////////////////////////////////////////////////
  894. short CPerson::EditNew( // Returns 0 if successfull, non-zero otherwise
  895. short sX, // In: New x coord
  896. short sY, // In: New y coord
  897. short sZ) // In: New z coord
  898. {
  899. short sResult = 0;
  900. sResult = CDoofus::EditNew(sX, sY, sZ);
  901. if (sResult == SUCCESS)
  902. {
  903. // Load resources
  904. sResult = GetResources();
  905. if (sResult == SUCCESS)
  906. {
  907. sResult = Init();
  908. }
  909. }
  910. else
  911. {
  912. sResult = -1;
  913. }
  914. return sResult;
  915. }
  916. ////////////////////////////////////////////////////////////////////////////////
  917. // Call back for the user-browse-for-logic-file button.
  918. ////////////////////////////////////////////////////////////////////////////////
  919. static void LogicUserBrowse( // Returns nothing
  920. RGuiItem* pgui) // In: GUI pressed.
  921. {
  922. RGuiItem* pguiLogicFileName = (RGuiItem*)pgui->m_ulUserInstance;
  923. ASSERT(pguiLogicFileName != NULL);
  924. // Get the logic file name . . .
  925. char szLogicFile[RSP_MAX_PATH];
  926. strcpy(szLogicFile, FullPathHD(pguiLogicFileName->m_szText));
  927. if (rspOpenBox(
  928. "Choose logic file",
  929. szLogicFile,
  930. szLogicFile,
  931. sizeof(szLogicFile),
  932. "lgk.") == 0)
  933. {
  934. char szHDPath[RSP_MAX_PATH];
  935. strcpy(szHDPath, FullPathHD(""));
  936. // Attempt to remove HD path . . .
  937. if (rspStrnicmp(szLogicFile, szHDPath, strlen(szHDPath) ) == 0)
  938. {
  939. // Determine amount of path to ignore.
  940. long lSubPathBegin = strlen(szHDPath);
  941. // Update the GUI that shows the filename.
  942. pguiLogicFileName->SetText("%s", rspPathFromSystem(szLogicFile + lSubPathBegin) );
  943. pguiLogicFileName->Compose();
  944. }
  945. }
  946. }
  947. ////////////////////////////////////////////////////////////////////////////////
  948. // Called by editor to modify object
  949. ////////////////////////////////////////////////////////////////////////////////
  950. short CPerson::EditModify(void)
  951. {
  952. short sResult = 0;
  953. Personatorium::Index eCurrentType = m_ePersonType;
  954. RGuiItem* pGuiItem = NULL;
  955. RGuiItem* pGui = RGuiItem::LoadInstantiate(FullPathVD("res/editor/person.gui"));
  956. if (pGui)
  957. {
  958. RListBox* pPersonalityList = (RListBox*) pGui->GetItemFromId(3);
  959. RListBox* pWeaponList = (RListBox*) pGui->GetItemFromId(4);
  960. RMultiBtn* pmbtnLogAI = (RMultiBtn*) pGui->GetItemFromId(102);
  961. RMultiBtn* pmbtnShowState = (RMultiBtn*) pGui->GetItemFromId(103);
  962. REdit* peditLogicFile = (REdit*) pGui->GetItemFromId(100);
  963. REdit* peditStartBouy = (REdit*) pGui->GetItemFromId(300);
  964. REdit* peditEndBouy = (REdit*) pGui->GetItemFromId(301);
  965. RBtn* pbtnLogicUserBrowse = (RBtn*) pGui->GetItemFromId(101);
  966. if ( pWeaponList && pPersonalityList && pmbtnLogAI
  967. && pmbtnShowState && peditLogicFile && pbtnLogicUserBrowse &&
  968. peditStartBouy && peditEndBouy)
  969. {
  970. // Verify these are the type we think they are before accessing type specific
  971. // members.
  972. ASSERT(pPersonalityList->m_type == RGuiItem::ListBox);
  973. ASSERT(pWeaponList->m_type == RGuiItem::ListBox);
  974. ASSERT(pmbtnLogAI->m_type == RGuiItem::MultiBtn);
  975. ASSERT(pmbtnShowState->m_type == RGuiItem::MultiBtn);
  976. ASSERT(peditLogicFile->m_type == RGuiItem::Edit);
  977. ASSERT(peditStartBouy->m_type == RGuiItem::Edit);
  978. ASSERT(peditEndBouy->m_type == RGuiItem::Edit);
  979. ASSERT(pbtnLogicUserBrowse->m_type == RGuiItem::Btn);
  980. // Fill in list box with current available personalities
  981. short i;
  982. for (i = 0; i < Personatorium::NumPersons; i++)
  983. {
  984. pGuiItem = pPersonalityList->AddString(g_apersons[i].pszDescription);
  985. if (pGuiItem != NULL)
  986. {
  987. pGuiItem->m_lId = PERSONALITY_ITEM_ID_BASE + i;
  988. pGuiItem->m_ulUserData = (ULONG) i;
  989. }
  990. }
  991. pPersonalityList->AdjustContents();
  992. // Show currently selected personality type
  993. pGuiItem = pGui->GetItemFromId(PERSONALITY_ITEM_ID_BASE + m_ePersonType);
  994. if (pGuiItem)
  995. {
  996. pPersonalityList->SetSel(pGuiItem);
  997. pPersonalityList->EnsureVisible(pGuiItem);
  998. }
  999. // Empty list box. We don't want to modify the .GUI resource just yet
  1000. // so we don't screw up people using the current .EXE on the server.
  1001. pWeaponList->RemoveAll();
  1002. // Fill in the list box with current available weapons.
  1003. for (i = 0; i < NumWeaponTypes; i++)
  1004. {
  1005. if ( (i != DeathWad || CStockPile::ms_sEnableDeathWad) &&
  1006. (i != DoubleBarrel || CStockPile::ms_sEnableDoubleBarrel) &&
  1007. (i != ProximityMine) &&
  1008. (i != TimedMine) &&
  1009. (i != RemoteControlMine) &&
  1010. (i != BouncingBettyMine) )
  1011. {
  1012. pGuiItem = pWeaponList->AddString(ms_awdWeapons[i].pszName);
  1013. if (pGuiItem != NULL)
  1014. {
  1015. // Store class ID so we can determine user selection
  1016. pGuiItem->m_lId = ms_awdWeapons[i].id;
  1017. }
  1018. }
  1019. }
  1020. pWeaponList->AdjustContents();
  1021. // Show which weapon is currently selected
  1022. pGuiItem = pGui->GetItemFromId(m_eWeaponType);
  1023. if (pGuiItem)
  1024. {
  1025. pWeaponList->SetSel(pGuiItem);
  1026. pWeaponList->EnsureVisible(pGuiItem);
  1027. }
  1028. // Set current state for AI log check box, if this is the guy being logged.
  1029. pmbtnLogAI->m_sState = (ms_u16IdLogAI == GetInstanceID()) ? 2 : 1;
  1030. // Reflect changes.
  1031. pmbtnLogAI->Compose();
  1032. // Set current state for show state check box.
  1033. pmbtnShowState->m_sState = (m_sShowState == FALSE) ? 1 : 2;
  1034. // Reflect changes.
  1035. pmbtnShowState->Compose();
  1036. // Set current logic file.
  1037. peditLogicFile->SetText("%s", (char*) m_rstrLogicFile);
  1038. // Reflect changes.
  1039. peditLogicFile->Compose();
  1040. // Set current start bouy
  1041. peditStartBouy->SetText("%d", m_ucSpecialBouy0ID);
  1042. peditStartBouy->Compose();
  1043. // Set current end bouy
  1044. peditEndBouy->SetText("%d", m_ucSpecialBouy1ID);
  1045. peditEndBouy->Compose();
  1046. // Set callback for logic browser button.
  1047. pbtnLogicUserBrowse->m_bcUser = LogicUserBrowse;
  1048. // Set instance data to GUI to query/update.
  1049. pbtnLogicUserBrowse->m_ulUserInstance = (ULONG)peditLogicFile;
  1050. SetGuiToNotify(pGui->GetItemFromId(ID_GUI_EDIT_TEXTURES) );
  1051. sResult = DoGui(pGui);
  1052. switch (sResult)
  1053. {
  1054. case ID_GUI_EDIT_TEXTURES: // Edit textures
  1055. case 1: // OK
  1056. {
  1057. RGuiItem* pSelection = pWeaponList->GetSel();
  1058. if (pSelection)
  1059. {
  1060. m_eWeaponType = pSelection->m_lId;
  1061. }
  1062. pSelection = pPersonalityList->GetSel();
  1063. if (pSelection)
  1064. {
  1065. m_ePersonType = (Personatorium::Index) pSelection->m_ulUserData;
  1066. if (m_ePersonType != eCurrentType)
  1067. {
  1068. // switch to new animation resources.
  1069. FreeResources();
  1070. GetResources();
  1071. m_bCivilian = (g_apersons[m_ePersonType].eLifestyle == Personatorium::Civilian);
  1072. }
  1073. }
  1074. // If the AI log checkbox is checked . . .
  1075. if (pmbtnLogAI->m_sState == 2)
  1076. {
  1077. // This is the guy who gets his AI logged.
  1078. ms_u16IdLogAI = GetInstanceID();
  1079. }
  1080. else
  1081. {
  1082. // If this was the guy who got his AI logged . . .
  1083. if (ms_u16IdLogAI == GetInstanceID() )
  1084. {
  1085. // No one is logging.
  1086. ms_u16IdLogAI = CIdBank::IdNil;
  1087. }
  1088. }
  1089. // Determine whether or not to display state on screen.
  1090. m_sShowState = (pmbtnShowState->m_sState == 2) ? TRUE : FALSE;
  1091. // Copy logic file to use.
  1092. m_rstrLogicFile.Grow(256);
  1093. peditLogicFile->GetText((char*) m_rstrLogicFile, 255);
  1094. m_rstrLogicFile.Update();
  1095. // Get the bouy settings
  1096. m_ucSpecialBouy0ID = peditStartBouy->GetVal();
  1097. m_ucSpecialBouy1ID = peditEndBouy->GetVal();
  1098. if (sResult == ID_GUI_EDIT_TEXTURES)
  1099. {
  1100. // Form save name.
  1101. RString strFile;
  1102. strFile = g_resmgrGame.GetBasePath();
  1103. strFile += g_apersons[m_ePersonType].Anim.pszBaseName;
  1104. if (g_apersons[m_ePersonType].Anim.sTextureScheme >= 0)
  1105. strFile += g_apersons[m_ePersonType].Anim.sTextureScheme;
  1106. strFile += ".tex";
  1107. CTexEdit te;
  1108. te.DoModal(&m_animStand, m_pRealm->m_phood->m_pltAmbient, m_pRealm->m_phood->m_pltSpot, strFile);
  1109. }
  1110. break;
  1111. }
  1112. }
  1113. }
  1114. }
  1115. delete pGui;
  1116. return 0;
  1117. }
  1118. ////////////////////////////////////////////////////////////////////////////////
  1119. // Called by editor to update object
  1120. ////////////////////////////////////////////////////////////////////////////////
  1121. void CPerson::EditUpdate(void)
  1122. {
  1123. }
  1124. ////////////////////////////////////////////////////////////////////////////////
  1125. // Get all required resources
  1126. ////////////////////////////////////////////////////////////////////////////////
  1127. short CPerson::GetResources(void) // Returns 0 if successfull, non-zero otherwise
  1128. {
  1129. short sResult = 0;
  1130. short sLoadResult = 0;
  1131. // Load Stand animation
  1132. sResult = m_animStand.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1133. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1134. "stand",
  1135. g_apersons[m_ePersonType].Anim.pszObjectName,
  1136. g_apersons[m_ePersonType].Anim.pszEventName,
  1137. g_apersons[m_ePersonType].Anim.pszHandName,
  1138. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1139. // Load Run animation, or load stand in its place if that fails
  1140. sLoadResult = m_animRun.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1141. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1142. "run",
  1143. g_apersons[m_ePersonType].Anim.pszObjectName,
  1144. g_apersons[m_ePersonType].Anim.pszEventName,
  1145. g_apersons[m_ePersonType].Anim.pszHandName,
  1146. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1147. if (sLoadResult != SUCCESS)
  1148. sResult |= m_animRun.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1149. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1150. "stand",
  1151. g_apersons[m_ePersonType].Anim.pszObjectName,
  1152. g_apersons[m_ePersonType].Anim.pszEventName,
  1153. g_apersons[m_ePersonType].Anim.pszHandName,
  1154. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1155. // Load Shoot animation or load stand in its place if that fails
  1156. sLoadResult = m_animShoot.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1157. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1158. "shoot",
  1159. g_apersons[m_ePersonType].Anim.pszObjectName,
  1160. g_apersons[m_ePersonType].Anim.pszEventName,
  1161. g_apersons[m_ePersonType].Anim.pszHandName,
  1162. 0);
  1163. if (sLoadResult != SUCCESS)
  1164. sResult |= m_animShoot.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1165. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1166. "stand",
  1167. g_apersons[m_ePersonType].Anim.pszObjectName,
  1168. g_apersons[m_ePersonType].Anim.pszEventName,
  1169. g_apersons[m_ePersonType].Anim.pszHandName,
  1170. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1171. // Load Shot animation or load stand in its place if that fails
  1172. sLoadResult = m_animShot.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1173. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1174. "shot",
  1175. g_apersons[m_ePersonType].Anim.pszObjectName,
  1176. g_apersons[m_ePersonType].Anim.pszEventName,
  1177. g_apersons[m_ePersonType].Anim.pszHandName,
  1178. 0);
  1179. if (sLoadResult != SUCCESS)
  1180. sResult |= m_animShot.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1181. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1182. "stand",
  1183. g_apersons[m_ePersonType].Anim.pszObjectName,
  1184. g_apersons[m_ePersonType].Anim.pszEventName,
  1185. g_apersons[m_ePersonType].Anim.pszHandName,
  1186. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1187. // Load Die animation or load stand in its place if that fails
  1188. sLoadResult = m_animDie.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1189. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1190. "die",
  1191. g_apersons[m_ePersonType].Anim.pszObjectName,
  1192. g_apersons[m_ePersonType].Anim.pszEventName,
  1193. g_apersons[m_ePersonType].Anim.pszHandName,
  1194. 0);
  1195. if (sLoadResult != SUCCESS)
  1196. sResult |= m_animDie.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1197. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1198. "stand",
  1199. g_apersons[m_ePersonType].Anim.pszObjectName,
  1200. g_apersons[m_ePersonType].Anim.pszEventName,
  1201. g_apersons[m_ePersonType].Anim.pszHandName,
  1202. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1203. // Load Writhing animation or load stand in its place if that fails
  1204. sLoadResult = m_animWrithing.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1205. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1206. "writhing",
  1207. g_apersons[m_ePersonType].Anim.pszObjectName,
  1208. g_apersons[m_ePersonType].Anim.pszEventName,
  1209. g_apersons[m_ePersonType].Anim.pszHandName,
  1210. RChannel_LoopAtEnd);
  1211. if (sLoadResult != SUCCESS)
  1212. sResult |= m_animWrithing.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1213. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1214. "stand",
  1215. g_apersons[m_ePersonType].Anim.pszObjectName,
  1216. g_apersons[m_ePersonType].Anim.pszEventName,
  1217. g_apersons[m_ePersonType].Anim.pszHandName,
  1218. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1219. // Load Executed animation or load stand in its place if that fails
  1220. sLoadResult = m_animExecuted.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1221. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1222. "executed",
  1223. g_apersons[m_ePersonType].Anim.pszObjectName,
  1224. g_apersons[m_ePersonType].Anim.pszEventName,
  1225. g_apersons[m_ePersonType].Anim.pszHandName,
  1226. 0);
  1227. if (sLoadResult != SUCCESS)
  1228. sResult |= m_animExecuted.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1229. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1230. "stand",
  1231. g_apersons[m_ePersonType].Anim.pszObjectName,
  1232. g_apersons[m_ePersonType].Anim.pszEventName,
  1233. g_apersons[m_ePersonType].Anim.pszHandName,
  1234. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1235. // Load Onfire animation animation or load stand in its place if that fails
  1236. sLoadResult = m_animOnfire.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1237. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1238. "onfire",
  1239. g_apersons[m_ePersonType].Anim.pszObjectName,
  1240. g_apersons[m_ePersonType].Anim.pszEventName,
  1241. g_apersons[m_ePersonType].Anim.pszHandName,
  1242. RChannel_LoopAtEnd);
  1243. if (sLoadResult != SUCCESS)
  1244. {
  1245. sResult |= m_animOnfire.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1246. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1247. "run",
  1248. g_apersons[m_ePersonType].Anim.pszObjectName,
  1249. g_apersons[m_ePersonType].Anim.pszEventName,
  1250. g_apersons[m_ePersonType].Anim.pszHandName,
  1251. RChannel_LoopAtEnd);
  1252. if (sLoadResult != SUCCESS)
  1253. sResult |= m_animOnfire.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1254. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1255. "stand",
  1256. g_apersons[m_ePersonType].Anim.pszObjectName,
  1257. g_apersons[m_ePersonType].Anim.pszEventName,
  1258. g_apersons[m_ePersonType].Anim.pszHandName,
  1259. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1260. }
  1261. // Load Walk animation animation or load stand in its place if that fails
  1262. sLoadResult = m_animWalk.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1263. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1264. "walk",
  1265. g_apersons[m_ePersonType].Anim.pszObjectName,
  1266. g_apersons[m_ePersonType].Anim.pszEventName,
  1267. g_apersons[m_ePersonType].Anim.pszHandName,
  1268. RChannel_LoopAtEnd);
  1269. if (sLoadResult != SUCCESS)
  1270. sResult |= m_animWalk.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1271. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1272. "stand",
  1273. g_apersons[m_ePersonType].Anim.pszObjectName,
  1274. g_apersons[m_ePersonType].Anim.pszEventName,
  1275. g_apersons[m_ePersonType].Anim.pszHandName,
  1276. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1277. if (sResult != SUCCESS)
  1278. TRACE("CPerson::GetResources - Error loading animation resources\n");
  1279. // Load ShootRun animation, or try Shoot if there isn't one, or stand as last option
  1280. sLoadResult = m_animShootRun.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1281. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1282. "runshoot",
  1283. g_apersons[m_ePersonType].Anim.pszObjectName,
  1284. g_apersons[m_ePersonType].Anim.pszEventName,
  1285. g_apersons[m_ePersonType].Anim.pszHandName,
  1286. 0);
  1287. if (sLoadResult != SUCCESS)
  1288. {
  1289. sLoadResult = m_animShootRun.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1290. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1291. "shoot",
  1292. g_apersons[m_ePersonType].Anim.pszObjectName,
  1293. g_apersons[m_ePersonType].Anim.pszEventName,
  1294. g_apersons[m_ePersonType].Anim.pszHandName,
  1295. 0);
  1296. if (sLoadResult != SUCCESS)
  1297. sResult |= m_animShootRun.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1298. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1299. "stand",
  1300. g_apersons[m_ePersonType].Anim.pszObjectName,
  1301. g_apersons[m_ePersonType].Anim.pszEventName,
  1302. g_apersons[m_ePersonType].Anim.pszHandName,
  1303. 0);
  1304. }
  1305. // Load ShootRunR0 animation, or try Shoot if there isn't one, or stand as last option
  1306. sLoadResult = m_animShootRunR0.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1307. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1308. "45rt",
  1309. g_apersons[m_ePersonType].Anim.pszObjectName,
  1310. g_apersons[m_ePersonType].Anim.pszEventName,
  1311. g_apersons[m_ePersonType].Anim.pszHandName,
  1312. 0);
  1313. if (sLoadResult != SUCCESS)
  1314. {
  1315. sLoadResult = m_animShootRunR0.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1316. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1317. "shoot",
  1318. g_apersons[m_ePersonType].Anim.pszObjectName,
  1319. g_apersons[m_ePersonType].Anim.pszEventName,
  1320. g_apersons[m_ePersonType].Anim.pszHandName,
  1321. 0);
  1322. if (sLoadResult != SUCCESS)
  1323. sResult |= m_animShootRunR0.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1324. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1325. "stand",
  1326. g_apersons[m_ePersonType].Anim.pszObjectName,
  1327. g_apersons[m_ePersonType].Anim.pszEventName,
  1328. g_apersons[m_ePersonType].Anim.pszHandName,
  1329. 0);
  1330. }
  1331. // Load ShootRunR1 animation, or try Shoot if there isn't one, or stand as last option
  1332. sLoadResult = m_animShootRunR1.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1333. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1334. "90rt",
  1335. g_apersons[m_ePersonType].Anim.pszObjectName,
  1336. g_apersons[m_ePersonType].Anim.pszEventName,
  1337. g_apersons[m_ePersonType].Anim.pszHandName,
  1338. 0);
  1339. if (sLoadResult != SUCCESS)
  1340. {
  1341. sLoadResult = m_animShootRunR1.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1342. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1343. "shoot",
  1344. g_apersons[m_ePersonType].Anim.pszObjectName,
  1345. g_apersons[m_ePersonType].Anim.pszEventName,
  1346. g_apersons[m_ePersonType].Anim.pszHandName,
  1347. 0);
  1348. if (sLoadResult != SUCCESS)
  1349. sResult |= m_animShootRunR1.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1350. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1351. "stand",
  1352. g_apersons[m_ePersonType].Anim.pszObjectName,
  1353. g_apersons[m_ePersonType].Anim.pszEventName,
  1354. g_apersons[m_ePersonType].Anim.pszHandName,
  1355. 0);
  1356. }
  1357. // Load ShootRunL0 animation, or try Shoot if there isn't one, or stand as last option
  1358. sLoadResult = m_animShootRunL0.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1359. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1360. "45lft",
  1361. g_apersons[m_ePersonType].Anim.pszObjectName,
  1362. g_apersons[m_ePersonType].Anim.pszEventName,
  1363. g_apersons[m_ePersonType].Anim.pszHandName,
  1364. 0);
  1365. if (sLoadResult != SUCCESS)
  1366. {
  1367. sLoadResult = m_animShootRunL0.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1368. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1369. "shoot",
  1370. g_apersons[m_ePersonType].Anim.pszObjectName,
  1371. g_apersons[m_ePersonType].Anim.pszEventName,
  1372. g_apersons[m_ePersonType].Anim.pszHandName,
  1373. 0);
  1374. if (sLoadResult != SUCCESS)
  1375. sResult |= m_animShootRunL0.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1376. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1377. "stand",
  1378. g_apersons[m_ePersonType].Anim.pszObjectName,
  1379. g_apersons[m_ePersonType].Anim.pszEventName,
  1380. g_apersons[m_ePersonType].Anim.pszHandName,
  1381. 0);
  1382. }
  1383. // Load ShootRunL1 animation, or try Shoot if there isn't one, or stand as last option
  1384. sLoadResult = m_animShootRunL1.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1385. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1386. "90lft",
  1387. g_apersons[m_ePersonType].Anim.pszObjectName,
  1388. g_apersons[m_ePersonType].Anim.pszEventName,
  1389. g_apersons[m_ePersonType].Anim.pszHandName,
  1390. 0);
  1391. if (sLoadResult != SUCCESS)
  1392. {
  1393. sLoadResult = m_animShootRunL1.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1394. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1395. "shoot",
  1396. g_apersons[m_ePersonType].Anim.pszObjectName,
  1397. g_apersons[m_ePersonType].Anim.pszEventName,
  1398. g_apersons[m_ePersonType].Anim.pszHandName,
  1399. 0);
  1400. if (sLoadResult != SUCCESS)
  1401. sResult |= m_animShootRunL1.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1402. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1403. "stand",
  1404. g_apersons[m_ePersonType].Anim.pszObjectName,
  1405. g_apersons[m_ePersonType].Anim.pszEventName,
  1406. g_apersons[m_ePersonType].Anim.pszHandName,
  1407. 0);
  1408. }
  1409. // Load ShootRunBack animation, or try Shoot if there isn't one, or stand as last option
  1410. sLoadResult = m_animShootRunBack.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1411. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1412. "runbackwr",
  1413. g_apersons[m_ePersonType].Anim.pszObjectName,
  1414. g_apersons[m_ePersonType].Anim.pszEventName,
  1415. g_apersons[m_ePersonType].Anim.pszHandName,
  1416. 0);
  1417. if (sLoadResult != SUCCESS)
  1418. {
  1419. sLoadResult = m_animShootRunBack.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1420. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1421. "shoot",
  1422. g_apersons[m_ePersonType].Anim.pszObjectName,
  1423. g_apersons[m_ePersonType].Anim.pszEventName,
  1424. g_apersons[m_ePersonType].Anim.pszHandName,
  1425. 0);
  1426. if (sLoadResult != SUCCESS)
  1427. sResult |= m_animShootRunBack.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1428. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1429. "stand",
  1430. g_apersons[m_ePersonType].Anim.pszObjectName,
  1431. g_apersons[m_ePersonType].Anim.pszEventName,
  1432. g_apersons[m_ePersonType].Anim.pszHandName,
  1433. 0);
  1434. }
  1435. // Load Crouch animation, or load stand in its place if that fails
  1436. sLoadResult = m_animCrouch.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1437. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1438. "crouch",
  1439. g_apersons[m_ePersonType].Anim.pszObjectName,
  1440. g_apersons[m_ePersonType].Anim.pszEventName,
  1441. g_apersons[m_ePersonType].Anim.pszHandName,
  1442. 0);
  1443. if (sLoadResult != SUCCESS)
  1444. sResult |= m_animCrouch.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1445. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1446. "stand",
  1447. g_apersons[m_ePersonType].Anim.pszObjectName,
  1448. g_apersons[m_ePersonType].Anim.pszEventName,
  1449. g_apersons[m_ePersonType].Anim.pszHandName,
  1450. 0);
  1451. // Load Search animation, or load stand in its place if that fails
  1452. sLoadResult = m_animSearch.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1453. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1454. "search",
  1455. g_apersons[m_ePersonType].Anim.pszObjectName,
  1456. g_apersons[m_ePersonType].Anim.pszEventName,
  1457. g_apersons[m_ePersonType].Anim.pszHandName,
  1458. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1459. if (sLoadResult != SUCCESS)
  1460. sResult |= m_animSearch.Get(g_apersons[m_ePersonType].Anim.pszBaseName,
  1461. g_apersons[m_ePersonType].Anim.sTextureScheme,
  1462. "stand",
  1463. g_apersons[m_ePersonType].Anim.pszObjectName,
  1464. g_apersons[m_ePersonType].Anim.pszEventName,
  1465. g_apersons[m_ePersonType].Anim.pszHandName,
  1466. RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1467. // Get execution target points -- NOT essential.
  1468. char szExeTargetResName[RSP_MAX_PATH];
  1469. sprintf(szExeTargetResName, "%s_writhing_exe.trans", g_apersons[m_ePersonType].Anim.pszBaseName);
  1470. sLoadResult = rspGetResource(&g_resmgrGame, szExeTargetResName, &m_ptransExecutionTarget);
  1471. if (sLoadResult == 0)
  1472. {
  1473. m_ptransExecutionTarget->SetLooping(RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1474. }
  1475. // Get Logic Table
  1476. sResult |= rspGetResource(&g_resmgrRes, (char*) m_rstrLogicFile, &m_pLogicTable);
  1477. // Get base class resources.
  1478. sResult |= CDoofus::GetResources();
  1479. return sResult;
  1480. }
  1481. ////////////////////////////////////////////////////////////////////////////////
  1482. // Free all resources
  1483. ////////////////////////////////////////////////////////////////////////////////
  1484. short CPerson::FreeResources(void) // Returns 0 if successfull, non-zero otherwise
  1485. {
  1486. m_animRun.Release();
  1487. m_animStand.Release();
  1488. m_animShoot.Release();
  1489. m_animShot.Release();
  1490. m_animDie.Release();
  1491. m_animWrithing.Release();
  1492. m_animExecuted.Release();
  1493. m_animOnfire.Release();
  1494. m_animWalk.Release();
  1495. m_animShootRun.Release();
  1496. m_animShootRunL0.Release();
  1497. m_animShootRunL1.Release();
  1498. m_animShootRunR0.Release();
  1499. m_animShootRunR1.Release();
  1500. m_animShootRunBack.Release();
  1501. m_animCrouch.Release();
  1502. m_animSearch.Release();
  1503. rspReleaseResource(&g_resmgrRes, &m_pLogicTable);
  1504. // If we have the execution target points . . .
  1505. if (m_ptransExecutionTarget)
  1506. rspReleaseResource(&g_resmgrGame, &m_ptransExecutionTarget);
  1507. // Release base class resources.
  1508. CDoofus::ReleaseResources();
  1509. return 0;
  1510. }
  1511. ////////////////////////////////////////////////////////////////////////////////
  1512. // PlaySoundWrithing - choose among the writhing sound effects
  1513. ////////////////////////////////////////////////////////////////////////////////
  1514. SampleMaster::SoundInstance CPerson::PlaySoundWrithing(
  1515. long* plDuration) // Out: Duration of sample, if not NULL.
  1516. {
  1517. m_siPlaying = 0;
  1518. SampleMasterID* psmid = &g_smidNil;
  1519. //#ifdef MOBILE //Reduce annoying comments when dying
  1520. if ((demoCompat) || (++m_usCommentCounter % 5 == 0) )
  1521. {
  1522. //#endif
  1523. switch (GetRandom() % 4)
  1524. {
  1525. case 0:
  1526. psmid = g_apersons[m_ePersonType].Sample.psmidSuffering1;
  1527. break;
  1528. case 1:
  1529. psmid = g_apersons[m_ePersonType].Sample.psmidSuffering2;
  1530. break;
  1531. case 2:
  1532. psmid = g_apersons[m_ePersonType].Sample.psmidSuffering3;
  1533. break;
  1534. case 3:
  1535. psmid = g_apersons[m_ePersonType].Sample.psmidSuffering4;
  1536. break;
  1537. }
  1538. PlaySample( // Returns nothing.
  1539. // Does not fail.
  1540. *psmid, // In: Identifier of sample you want played.
  1541. SampleMaster::Suffering, // In: Sound Volume Category for user adjustment
  1542. -1, // In: Initial Sound Volume (0 - 255)
  1543. // Negative indicates to use the distance to the ear.
  1544. &m_siPlaying, // Out: Handle for adjusting sound volume
  1545. plDuration); // Out: Sample duration in ms, if not NULL.
  1546. //#ifdef MOBILE
  1547. }
  1548. //#endif
  1549. return m_siPlaying;
  1550. }
  1551. ////////////////////////////////////////////////////////////////////////////////
  1552. // PlaySoundShot - choose among the shot sound effects
  1553. ////////////////////////////////////////////////////////////////////////////////
  1554. SampleMaster::SoundInstance CPerson::PlaySoundShot(void)
  1555. {
  1556. m_siPlaying = 0;
  1557. SampleMasterID* psmid = &g_smidNil;
  1558. long lThisTime = m_pRealm->m_time.GetGameTime();
  1559. long lSampleDuration = 0; // Safety.
  1560. if (lThisTime > m_lSampleTimeIsPlaying)
  1561. {
  1562. if (m_state == State_Writhing)
  1563. {
  1564. // Use the generic grunt when shot from writhing, so that they
  1565. // don't accidently say something stupid like Oh my leg when
  1566. // you execute them by shooting them in the head.
  1567. psmid = &g_smidRubinAh;
  1568. }
  1569. else
  1570. {
  1571. switch(GetRandom() % 4)
  1572. {
  1573. case 0:
  1574. if (m_bHitComment)
  1575. {
  1576. psmid = g_apersons[m_ePersonType].Sample.psmidShot2;
  1577. }
  1578. else
  1579. {
  1580. psmid = g_apersons[m_ePersonType].Sample.psmidShot1;
  1581. m_bHitComment = true;
  1582. }
  1583. break;
  1584. case 1:
  1585. psmid = g_apersons[m_ePersonType].Sample.psmidShot2;
  1586. break;
  1587. case 2:
  1588. psmid = g_apersons[m_ePersonType].Sample.psmidShot3;
  1589. break;
  1590. case 3:
  1591. psmid = g_apersons[m_ePersonType].Sample.psmidShot4;
  1592. break;
  1593. }
  1594. }
  1595. // We must get the sample duration from the PlaySample() function and NOT
  1596. // from the RSnd that it returns. The reason is that if we fail to play
  1597. // the sample (perhaps all the sound channels are in use), we still need
  1598. // the time reflected for the duration to be the same so the game will
  1599. // run consistently no matter the speed of sound playback. It could even
  1600. // be the case that there is no sound card in which case the only way to
  1601. // get it to run the same from machine to machine is to use the sample
  1602. // duration whether we succeed or fail to play the sample.
  1603. m_lSampleTimeIsPlaying = lThisTime + lSampleDuration;
  1604. }
  1605. PlaySample( // Returns nothing.
  1606. // Does not fail.
  1607. *psmid, // In: Identifier of sample you want played.
  1608. SampleMaster::Pain, // In: Sound Volume Category for user adjustment
  1609. -1, // In: Initial Sound Volume (0 - 255)
  1610. // Negative indicates to use the distance to the ear.
  1611. &m_siPlaying, // Out: Handle for adjusting sound volume
  1612. &lSampleDuration); // Out: Sample duration in ms, if not NULL.
  1613. return m_siPlaying;
  1614. }
  1615. ////////////////////////////////////////////////////////////////////////////////
  1616. // PlaySoundBlownup - choose among the blown up sound effects
  1617. ////////////////////////////////////////////////////////////////////////////////
  1618. SampleMaster::SoundInstance CPerson::PlaySoundBlownup(void)
  1619. {
  1620. m_siPlaying = 0;
  1621. SampleMasterID* psmid = &g_smidNil;
  1622. switch (GetRandom() % 2)
  1623. {
  1624. case 0:
  1625. psmid = g_apersons[m_ePersonType].Sample.psmidBlownup1;
  1626. break;
  1627. case 1:
  1628. psmid = g_apersons[m_ePersonType].Sample.psmidBlownup2;
  1629. break;
  1630. }
  1631. PlaySample( // Returns nothing.
  1632. // Does not fail.
  1633. *psmid, // In: Identifier of sample you want played.
  1634. SampleMaster::Pain, // In: Sound Volume Category for user adjustment
  1635. -1, // In: Initial Sound Volume (0 - 255)
  1636. // Negative indicates to use the distance to the ear.
  1637. &m_siPlaying); // Out: Handle for adjusting sound volume
  1638. return m_siPlaying;
  1639. }
  1640. ////////////////////////////////////////////////////////////////////////////////
  1641. // PlaySoundBurning - choose among burning yells
  1642. ////////////////////////////////////////////////////////////////////////////////
  1643. SampleMaster::SoundInstance CPerson::PlaySoundBurning(void)
  1644. {
  1645. m_siPlaying = 0;
  1646. SampleMasterID* psmid = &g_smidNil;
  1647. switch (GetRandom() % 2)
  1648. {
  1649. case 0:
  1650. psmid = g_apersons[m_ePersonType].Sample.psmidBurning1;
  1651. break;
  1652. case 1:
  1653. psmid = g_apersons[m_ePersonType].Sample.psmidBurning2;
  1654. break;
  1655. }
  1656. PlaySample( // Returns nothing.
  1657. // Does not fail.
  1658. *psmid, // In: Identifier of sample you want played.
  1659. SampleMaster::Pain, // In: Sound Volume Category for user adjustment
  1660. -1, // In: Initial Sound Volume (0 - 255)
  1661. // Negative indicates to use the distance to the ear.
  1662. &m_siPlaying); // Out: Handle for adjusting sound volume
  1663. return m_siPlaying;
  1664. }
  1665. ////////////////////////////////////////////////////////////////////////////////
  1666. // PlaySoundShooting - choose among comments to say before shooting
  1667. ////////////////////////////////////////////////////////////////////////////////
  1668. SampleMaster::SoundInstance CPerson::PlaySoundShooting(void)
  1669. {
  1670. m_siPlaying = 0;
  1671. SampleMasterID* psmid = &g_smidNil;
  1672. if (++m_usCommentCounter % 10 == 0 && m_idDude != CIdBank::IdNil)
  1673. {
  1674. switch (GetRandom() % 4)
  1675. {
  1676. case 0:
  1677. psmid = g_apersons[m_ePersonType].Sample.psmidShooting1;
  1678. break;
  1679. case 1:
  1680. psmid = g_apersons[m_ePersonType].Sample.psmidShooting2;
  1681. break;
  1682. case 2:
  1683. psmid = g_apersons[m_ePersonType].Sample.psmidShooting3;
  1684. break;
  1685. case 3:
  1686. psmid = g_apersons[m_ePersonType].Sample.psmidShooting4;
  1687. break;
  1688. }
  1689. }
  1690. PlaySample( // Returns nothing.
  1691. // Does not fail.
  1692. *psmid, // In: Identifier of sample you want played.
  1693. SampleMaster::Voices, // In: Sound Volume Category for user adjustment
  1694. -1, // In: Initial Sound Volume (0 - 255)
  1695. // Negative indicates to use the distance to the ear.
  1696. &m_siPlaying); // Out: Handle for adjusting sound volume
  1697. return m_siPlaying;
  1698. }
  1699. ////////////////////////////////////////////////////////////////////////////////
  1700. // PlaySoundDying - choose among dying sounds and comments
  1701. ////////////////////////////////////////////////////////////////////////////////
  1702. SampleMaster::SoundInstance CPerson::PlaySoundDying(void)
  1703. {
  1704. m_siPlaying = 0;
  1705. SampleMasterID* psmid = &g_smidNil;
  1706. if (++m_usCommentCounter % 4 == 0)
  1707. {
  1708. switch (GetRandom() % 2)
  1709. {
  1710. case 0:
  1711. psmid = g_apersons[m_ePersonType].Sample.psmidDying1;
  1712. break;
  1713. case 1:
  1714. psmid = g_apersons[m_ePersonType].Sample.psmidDying2;
  1715. break;
  1716. }
  1717. }
  1718. PlaySample( // Returns nothing.
  1719. // Does not fail.
  1720. *psmid, // In: Identifier of sample you want played.
  1721. SampleMaster::Suffering, // In: Sound Volume Category for user adjustment
  1722. -1, // In: Initial Sound Volume (0 - 255)
  1723. // Negative indicates to use the distance to the ear.
  1724. &m_siPlaying); // Out: Handle for adjusting sound volume
  1725. return m_siPlaying;
  1726. }
  1727. ////////////////////////////////////////////////////////////////////////////////
  1728. // PlaySoundRandom - choose among several random comments
  1729. ////////////////////////////////////////////////////////////////////////////////
  1730. SampleMaster::SoundInstance CPerson::PlaySoundRandom(void)
  1731. {
  1732. m_siPlaying = 0;
  1733. SampleMasterID* psmid = &g_smidNil;
  1734. //#ifdef MOBILE //reduce NPC random comments
  1735. int n;
  1736. if (demoCompat)
  1737. n = 10;
  1738. else
  1739. n = 20;
  1740. if (++m_usCommentCounter % n == 0 && m_idDude != CIdBank::IdNil)
  1741. //#else
  1742. //if (++m_usCommentCounter % 10 == 0 && m_idDude != CIdBank::IdNil)
  1743. //#endif
  1744. {
  1745. // Make sure the dude you are tracking is not dead before making any
  1746. // stupid comments about him, like "where did he go?", "Get that guy"
  1747. if (m_idDude != CIdBank::IdNil)
  1748. {
  1749. CDude* pdude;
  1750. if (m_pRealm->m_idbank.GetThingByID((CThing**) &pdude, m_idDude) == 0)
  1751. {
  1752. if (pdude && pdude->m_state != State_Dead)
  1753. {
  1754. switch (GetRandom() % 4)
  1755. {
  1756. case 0:
  1757. psmid = g_apersons[m_ePersonType].Sample.psmidRandom1;
  1758. break;
  1759. case 1:
  1760. psmid = g_apersons[m_ePersonType].Sample.psmidRandom2;
  1761. break;
  1762. case 2:
  1763. psmid = g_apersons[m_ePersonType].Sample.psmidRandom3;
  1764. break;
  1765. case 3:
  1766. psmid = g_apersons[m_ePersonType].Sample.psmidRandom4;
  1767. break;
  1768. }
  1769. PlaySample( // Returns nothing.
  1770. // Does not fail.
  1771. *psmid, // In: Identifier of sample you want played.
  1772. SampleMaster::Voices, // In: Sound Volume Category for user adjustment
  1773. -1, // In: Initial Sound Volume (0 - 255)
  1774. // Negative indicates to use the distance to the ear.
  1775. &m_siPlaying); // Out: Handle for adjusting sound volume
  1776. }
  1777. }
  1778. }
  1779. }
  1780. return m_siPlaying;
  1781. }
  1782. ////////////////////////////////////////////////////////////////////////////////
  1783. // EOF
  1784. ////////////////////////////////////////////////////////////////////////////////