1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2016 RWS Inc, All Rights Reserved
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of version 2 of the GNU General Public License as published by
- // the Free Software Foundation
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License along
- // with this program; if not, write to the Free Software Foundation, Inc.,
- // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // dude.cpp
- // Project: Postal
- //
- // This module implements the CDude class, which is the main, player-controlled
- // character in the game.
- //
- // History:
- // 01/12/97 MJR Started.
- //
- // 01/15/97 BRH Changed 3D to 2D render position to subtract the
- // Y rather than Add it.
- //
- // 01/23/97 JMI Now calls CRealm::GetLayerFromAttrib() in Render() to
- // get on the proper layer.
- //
- // 01/31/97 BRH Added the ability to throw Grenades.
- //
- // 01/29/97 JMI Now Load() and Save() call the base class versions.
- //
- // 02/04/97 JMI Changed LoadDib() call to Load() (which now supports
- // loading of DIBs).
- //
- // 02/07/97 BRH Changed to using the single frame 3D wire frame
- // instead of the 2D sprite.
- //
- // 02/07/97 JMI Added XRay flag to dude.
- //
- // 02/07/97 JMI GetResources() never closed its RFile. Fixed.
- //
- // 02/07/97 JMI Now CScene has its own pipeline, so we don't need ours
- // anymore. And we don't need to set any of that schtuff
- // up. Removed all the pipeline initialization stuff.
- //
- // 02/10/97 JMI Added the 3D animation for walking (or is it running?).
- //
- // 02/11/97 JMI Added the 3D animation for throwing and an associated
- // rigid body transform for a grenade.
- //
- // 02/12/97 JMI Forgot to set m_pGrenade->m_dRot again on release so the
- // grenade would have correct trajectory even if the dude
- // had rotated since the start of the throw. Fixed.
- //
- // 02/12/97 JMI Now animates backwards for running backwards.
- //
- // 02/13/97 JMI Changing RForm3d to RSop.
- //
- // 02/13/97 JMI Now the dude maps his textures to the palette on load.
- //
- // 02/14/97 JMI Removed Remap(). This'll now be done by a utility before
- // we even load the textures.
- // Also, changed the direction and rotation the guy does.
- // Currently, his position is hosed but I need to check it
- // in to get it at home.
- //
- // 02/17/97 JMI Now uses actual standing anim for standing state.
- // Changed resource filenames to not use two '.'s.
- // Now uses new m_pRealm->m_scene.TransformPtsToRealm() func
- // to get relative position of grenade on release.
- // For the mapping from 3D to 2D, now does not take radius
- // into account b/c the scene actually draws relative to the
- // origin.
- // Added UpdateRadius() function to get the current
- // m_sSphereRadius of the guy. But this is incorrect b/c
- // we should not be using m_sSphereRadius, but instead some-
- // thing like m_sCylinderR and m_sCylinderH to determine
- // the xray position, EditRect(), and EditHotSpot().
- //
- // 02/17/97 JMI Now changes the lighting if the lighting bit is set in the
- // checked attribute zone.
- //
- // 02/18/97 MJR Tuned guy turning and running speeds, added use of "shift"
- // key to run faster, switched all animations over to newly
- // existant main-guy versions.
- //
- // 02/18/97 JMI Added firing of bullets.
- // Also, removed #if 0, #elif 0, .... blocks.
- // Also, added dieing animation and die state.
- // Now goes into Die state when hit in response to several
- // messages.
- //
- // 02/19/97 JMI Now passes more masks to FireDeluxe() and uses Character
- // bit.
- // Also, does not subtract 90 before blitting.
- //
- // 02/19/97 JMI Slowed bullets to MAX_BULLETS_PER_SEC.
- //
- // 02/19/97 JMI Enhanced SetState(). Not it checks via its current state
- // if it's okay to change to the new state, and if it's okay,
- // cleans up the old state, sets the new state, and returns
- // true, if successful.
- //
- // 02/19/97 JMI Added shoot while still and while running.
- //
- // 02/19/97 JMI Changed main_rungun.* to main_run.* for running anim b/c
- // main_rungun looked too much like main_runshoot.
- // Also, now cannot rotate at user request when dead.
- // Now has a running and standing shooting anim.
- // Encapsulated release of grenade into ReleaseGrenade() so
- // it can be reused.
- // Fixed a bunch of little things in SetState().
- //
- // 02/19/97 JMI Brightness tuned slightly due to everything seeming to
- // change in brightness after tonight's assets fest.
- //
- // 02/19/97 JMI Added damage state.
- //
- // 02/20/97 MJR Added use of new input functions as part of enabling
- // multiplayer network mode.
- //
- // 02/20/97 JMI Changed bit masks to FireDeluxe so CDudes can shoot any
- // other characters.
- //
- // 02/20/97 JMI Now processes delete message.
- //
- // 02/20/97 JMI Added blood and now sets m_sprite flags only once (in
- // Init()).
- //
- // 02/21/97 JMI Had forgotten to release the 3d/main_shot.* resource.
- // Fixed.
- //
- // 02/21/97 JMI ThrowRelease was allowing any state change when it was the
- // current state.
- // Also, now if the dude changes animations during a throw,
- // the grenade just drops instead of exploding immediately.
- //
- // 02/21/97 JMI The grenade now rolls off randomly when dropped accidently.
- //
- // 02/23/97 JMI Now any state can jump out of damage state.
- //
- // 02/24/97 JMI Use 3D 'link'-like pt for bullet start position.
- //
- // 02/24/97 JMI Better blood splat and added blood pool.
- //
- // 02/24/97 JMI No longer sets the m_type member of the m_sprite b/c it
- // is set by m_sprite's constructor.
- //
- // 02/24/97 JMI Now State_Damage cannot interrupt State_Damage which looks
- // a lot better. It would look even better still, I think,
- // if the shot animation was a little shorter/faster.
- //
- // 02/24/97 JMI Now tweaks angle slightly before calling FireDeluxe() so
- // the gun does not aim perfectly.
- //
- // 02/24/97 JMI Added on-fire state.
- //
- // 02/24/97 JMI Tweaked on-fire state.
- //
- // 02/24/97 JMI Changed reference to CAnimThing's m_pthingSendMsg member to
- // m_u16IdSendMsg.
- //
- // 02/24/97 JMI No longer bleeds due to fire.
- //
- // 02/25/97 JMI Added new burning yell sound.
- //
- // 02/26/97 JMI Now <Control> fires weapon and <Alt> throws grenade.
- //
- // 03/03/97 JMI Added m_statePersistent.
- // Now sets m_statePersistent if State_Damage interrupts
- // State_Burning.
- //
- // 03/03/97 JMI Now passes CSmash::Dead as a bit that FireDeluxe() will not
- // hit.
- // Now sets m_smash.m_bits to include CSmash::Dead when we
- // reach State_Dead and removes it again when be leave
- // State_Dead.
- //
- // 03/03/97 JMI Added states for strafing and multiweapon logic.
- // Currently, loads run and shoot for strafe anims which
- // should do until the strafe equivalents are ready.
- //
- // 03/03/97 JMI Changed m_pGrenade to m_pWeapon (a CWeapon* instead of
- // a CGrenade*) so more weapons can be handled generically.
- //
- // 03/03/97 JMI Now CDude is based upon CCharacter.
- // Not much base class functionality utilized yet, though.
- //
- // 03/04/97 JMI Now utilizes more of the base class functionality.
- // All CCharacter::Edit*() functions are used.
- // Now uses real strafe animations.
- // Moved stuff I was incorrectly doing in Render() into
- // Update() so CDude now uses CCharacter::Render().
- // Update() now uses functions in CCharacter (i.e.,
- // UpdateVelocities(), GetNewPosition(), and
- // MakeValidPosition() ) to process acceleration,
- // velocities, and positions.
- //
- // 03/04/97 JMI Got rid of #if 0'd out code in Update().
- //
- // 03/04/97 JMI Now utilizes message overrides from CCharacter.
- //
- // 03/04/97 JMI Removed UpdateRadius().
- // Now calls CCharacter::UpdateFirePosition() to keep fire
- // position up to date.
- // Converted all rspMod360() calls to new calling convention.
- // Removed m_panimthing for fire (now uses base class fire).
- // Removed ProcessMessages() (now base class is fine).
- //
- // 03/05/97 JMI Was checking for fire gone incorrectly. Fixed.
- //
- // 03/05/97 JMI Now fires weapons (except SemiAutomatic) through base class.
- // Eventually, might move that to base class too??
- //
- // 03/05/97 JMI Removed ReleaseWeapon() now uses CCharacter::ShootWeapon().
- //
- // 03/05/97 JMI m_pWeapon no longer referenced.
- // Uses new multishot animation for when he's been shot.
- //
- // 03/05/97 JMI Removed ms_apt3dAttribCheck (these points are now stored
- // and checked in CCharacer).
- // Added Suicide.
- //
- // 03/06/97 JMI Drag no longer gets set to zero when velocity reaches zero
- // by this class (now handled by base class).
- // Added override to OnSuicideMsg().
- // Added a little fudge to BrainSplat location.
- //
- // 03/06/97 JMI No longer does hack to get ID from m_pWeapon since the base
- // class now stores the ID in m_u16IdWeapon (and does not
- // rely on m_pWeapon to reference the weapon).
- //
- // 03/06/97 JMI Now sets his velocity to 0.0 when committing suicide.
- //
- // 03/06/97 JMI Changed fudge factor delay for suicide brain splat to
- // 1400 ms (was 700 ms).
- //
- // 03/06/97 JMI User can no longer influence velocity when dude is being
- // shot.
- //
- // 03/13/97 JMI Added EditModify() member function.
- // Also, added m_sNumFireBombs/Missiles/Napalms.
- // Load now takes a version number.
- //
- // 03/13/97 JMI Added file format version 2 load stuff:
- // m_sNumFireBombs/Missiles/Napalms.
- // Now considers amount of particular weapon left before
- // firing it.
- //
- // 03/13/97 JMI Added DrawStatus() member function.
- // Now can run out of bullets.
- // BUG: Wierd glitchiness when firing empty gun and running
- // which is exaggerated by the distance between shots. Longer
- // times between empty shots seem to cause more noticable
- // glitches.
- //
- // 03/13/97 JMI Dude now takes additional burn damage while on fire.
- //
- // 03/14/97 JMI Changed the fire angle sway to 20 (was 10).
- //
- // 03/14/97 JMI Added very simple jump.
- //
- // 03/21/97 JMI Added launching animation.
- //
- // 03/21/97 JMI Now deletes launched weapon when launch is interrupted.
- // Also, added a minimum time to the got shot animation.
- //
- // 03/24/97 JMI Now utilize new input rotation embedded in UINPUT value.
- //
- // 03/25/97 JMI Now uses main_runnogun*.* for run animation.
- //
- // 03/26/97 JMI Changed STATUS_FONT_SIZE from 30 to 24.
- //
- // 03/26/97 JMI When I added the rotation value built into the UINPUT,
- // and then ignored the rotation value when dying, the net
- // effect was the guy would snap to rotation 0, when dying.
- // Fixed.
- // Also, when I switched to having the guy get damaged
- // more than just once by the same fire, it caused the dude
- // to react to fire even if we was previously dead. Fixed.
- //
- // 03/27/97 JMI Added many animations.
- //
- // 03/27/97 JMI Timing for blown up animation was being done through the
- // rigid body transform for some unknown reason. Fixed.
- //
- // 03/27/97 JMI Can no longer move forward when ducking, exploding,
- // or getting up from explosion.
- //
- // 03/28/97 JMI Now dude will enter the blown up animation, even if he is
- // dead (returning to the dead anim).
- // Also, now damage anim will loop.
- //
- // 03/31/97 JMI Took out INPUT_* macro definitions since input.h now
- // defines them correctly.
- //
- // 04/01/97 JMI UINPUT now stores the delta rotation in the first 10 bits
- // as 0..720 representing delta values between -360 and 360.
- //
- // 04/02/97 JMI Changed all resource animation names to use the
- // CREATERESNAMES macro that some were already using.
- //
- // 04/02/97 JMI OnExplosionMsg() now beefs up his vertical velocity due to
- // the explosion, if a successful state change occurs.
- //
- // 04/03/97 JMI Added additional link point for shooting from nealing pos.
- //
- // 04/03/97 JMI Changed font color to RGB. The index is gotten on Init().
- //
- // 04/03/97 JMI Hard coded ms_u8FontBackIndex to RSP_BLACK_INDEX.
- //
- // 04/03/97 JMI Now that PrepareWeapon() returns the pointer to the new
- // weapon or NULL. The return value should not be compared to
- // 0 for success (now that indicates failure).
- //
- // 04/03/97 JMI Now, if the rise state is entered before the ducking anim
- // was finished, he jumps into the rise anim at the inverse of
- // his relative position in the duck anim so he appears to
- // rise back starting at the position he was in during the
- // duck. It looks suprisingly good thanks to the consistency
- // of the art.
- // Also, if shoot is requested while ducking, the dude auto-
- // magically switches to rising state first. Firing cannot
- // override rising, so it is not entered until the rise is
- // complete.
- //
- // 04/07/97 JMI Added jumps, landings, and fall components.
- //
- // 04/08/97 JMI He was not responding to State_Delete. Now he deletes self
- // at the end of Update().
- //
- // 04/14/97 BRH Added CSmash::Item to the type of things that bullets could
- // hit, so he can shoot barrels.
- //
- // 04/14/97 JMI Now DrawStatus() will only display <= 100% health.
- //
- // 04/18/97 JMI Changed EXPLOSION_VERTICAL_VEL_MULTIPLIER from 1.5 to 1.0
- // which should basically make is vertical explosion velocity
- // the same as all the other characters.
- //
- // 04/21/97 JMI Changed EXPLOSION_VERTICAL_VEL_MULTIPLIER from 1.0 to 1.3.
- //
- // 04/21/97 JMI Incorporated Mike's new crawler thinger for smooth rubbin'
- // and slidin' up against schtuff.
- // The nubs can be heavily tuned.
- //
- // 04/21/97 JMI Added override of WhileBlownUp().
- //
- // 04/22/97 BRH In the burning state, he used to check to see when the
- // fire object was dead. Now since the fire changes to smoke,
- // he was running around on smoke. So I added a call to
- // IsBurning so that he knows when he can resume normal
- // control.
- //
- // 04/22/97 JMI Moved the setup of the font stuff to startup when the
- // palette for the hood should already have been set. This
- // way we get the correct colors for the DrawStatus().
- //
- // 04/22/97 JMI Fixed my use of shadow even though currently that code does
- // not get used.
- // Also, changed STATUS_FONT_SIZE from 24 to 26 which is a
- // currently cached scale for the g_fontBig.
- // Also, disabled jump for current demo for GT.
- //
- // 04/22/97 JMI Dude can no longer get up after dying.
- //
- // 04/23/97 JMI Now just uses a test version of IsPathClear().
- //
- // 04/23/97 JMI Now our bullets can hit Characters, Miscs, Mines,
- // Barrels, and Fire.
- //
- // 04/23/97 JMI Disabled IsPathClear() test.
- //
- // 04/24/97 JMI Added shotgun weapon components.
- //
- // 04/25/97 JMI ShootWeapon() now decrements m_sNumShells.
- // Also, previously when the guy was reacting to being shot,
- // he couldn't die.
- //
- // 04/25/97 JMI Added a state for executing dudes.
- //
- // 04/25/97 JMI Can no longer move forward or back or turn while executing.
- //
- // 04/25/97 JMI Added flame thrower weapon support. Required fuel ammo
- // info and special case on release of flamage.
- //
- // 04/25/97 JMI Removed input for flame thrower for temp even though it will
- // soon rock.
- //
- // 04/27/97 JMI Changed link point for execute and re-enabled flame thrower.
- // Also, execute now checks amount of bullets.
- //
- // 04/28/97 JMI Removed PrepareWeapon() override since the base class
- // version now handles bullet oriented weapons.
- // Also, moved FireBullets() to base class, CCharacter.
- //
- // 04/29/97 JMI Changed CAnim3D::Get()'s over to new version that does not
- // require an array of char pointers.
- // Added m_animPickPut for picking up and putting things down.
- // Also, added mine weapon. You cannot choose the type now,
- // though (it's the default which is proximity).
- //
- // 04/29/97 JMI I was unnecessarily making the dude go into State_Rise
- // after the State_PutDown animation finished. But, as it
- // turns out, the m_animPickPut already contains a rise
- // which makes things a bit easier.
- //
- // 04/29/97 JMI Flame thrower would only work while not moving. Fixed.
- //
- // 04/30/97 JMI Changed Mine enum value to ProximityMine, TimedMine,
- // RemoteMine, and BouncingBettyMine.
- //
- // 04/30/97 JMI Changed m_animPickPut to use 'hand' instead of 'guntip'.
- //
- // 05/01/97 JMI Now his animation speed for his run is in ratio to
- // RUN_ANIM_VELOCITY and he enters the stand state when his
- // speed falls below MIN_RUN_VEL and there's no user
- // acceleration.
- // Also, fixed some transition bugs involving
- // strafing/standing/shooting to strafing/running/shooting and
- // everything in between.
- //
- // 05/02/97 JMI Now plays sample g_smidExecute1 or g_smidExecute2, if
- // he actually hits someone during execute.
- //
- // 05/02/97 JMI Uses new inputs where weapons are a value stored in 4 bits.
- //
- // 05/08/97 JMI Now shows status change even if the weapon pressed is
- // already the current weapon.
- // Added the NoWeapon weapon.
- //
- // 05/09/97 JMI Changed MAX_BULLETS_PER_SEC from 10 to 6.
- // Added flame thrower noises.
- //
- // 05/12/97 JRD Added a call to SpewTriggers on dude move to alert Pylons
- //
- // 05/13/97 JMI Changed INPUT_WALK (was INPUT_RUN) from functioning as a
- // 'fast' key to a 'slow' key.
- // Also, I made the slow key affect the rate the dude turns
- // by dividing the input rotation delta by SLOW_TURN_DIVISOR.
- // Also, added ability to fire the heatseeker.
- //
- // 05/14/97 JMI Dude can now pick up and cash in on power ups.
- // Also, added Message() which allows you to add messages
- // to the dude's status display.
- //
- // 05/22/97 JMI Added CDudeAnim3D so we could use Get() but have it not
- // load textures (they are loaded separately so the dude
- // color can be changed by the user).
- //
- // 05/23/97 JMI Update() was nearly a thousand lines and that was just
- // too damned much. So I broke it up a bit.
- // Also, changed FireCurrentWeapon() to ArmWeapon() which
- // takes as a parameter the weapon to fire.
- //
- // 05/23/97 JMI Changed all the CAnim3D::Get()s to take the new
- // pszEventName parameter.
- //
- // 05/23/97 JMI Changed names of loaded textures to "main_color%02d" (was
- // "main_%d".
- //
- // 05/23/97 JMI Now loads the "main_missile" event data and uses it to
- // show and release the missile.
- // Consequently, most of the time the missile seems to be in
- // the wrong spot and kills us almost immediately... .
- //
- // 05/25/97 JMI Restored main_missile anim to NOT using events b/c those
- // events happend so much earlier than the old FUDGE method,
- // the dude kills himself with the missiles.
- //
- // 05/26/97 JMI Now will only repeat shot state every
- // MIN_CANNOT_BE_SHOT_DURATION ms (will groan and get bloody
- // though).
- // Also, will only yell due to being shot or blown up every
- // MIN_BETWEEN_YELLS ms.
- //
- // 05/26/97 JMI Added m_sOrigHitPoints so dude can show percentage based
- // on initial hitpoints.
- //
- // 05/27/97 JMI Changed 'beers' to 'health'.
- //
- // 05/29/97 JMI Made it so the dude can go from blownup state to blownup
- // state repeatedly (not sure why I limited it before).
- // Attempted to make it so the dude does not cry out in
- // pain while blowing up.
- // Added a Revive() function which is the best way to revive
- // a dude that has died.
- // Added a timer for changing weapons that use the same input.
- //
- // 05/29/97 JMI Now the INPUT_JUMP doubles as a revive (when he is dead).
- //
- // 05/29/97 JMI Fixed comparison on mine delay timer that caused mines to
- // be unselectable.
- //
- // 05/30/97 JMI Added SprayCannon weapon.
- //
- // 05/30/97 JMI Changed SHELLS_PER_SPRAY_CANNON_FIRE to 4 (was 2) and
- // disabled the flame thrower.
- //
- // 05/30/97 JMI Fixed Spray Cannon so it won't fire if there's less than
- // SHELLS_PER_SPRAY_CANNON_FIRE shells.
- //
- // 06/02/97 JMI Added climb state.
- //
- // 06/02/97 JMI Removed climb state.
- //
- // 06/03/97 JMI Changed EXPLOSION_VERTICAL_VEL_MULTIPLIER from 1.3 to 1.0.
- //
- // 06/03/97 JMI Got rid of 2d brain splat anim and replaced with CChunk
- // pieces.
- // Also, changed weapon used to shotgun.
- //
- // 06/03/97 JMI Changed event name from 'mainmissile' to 'mainevent' and
- // changed the suicide to use the event for when to fire the
- // gun (and splat is brains). Also, now uses the 'head'
- // transform for the location of the source of the brain
- // splat.
- //
- // 06/05/97 JMI Removed m_sHitPoints and m_sNum*. Now uses CThing3d's
- // m_stockpile instead.
- // Changed EditModify() to bring up the user settings for
- // m_stockpile when the 'StockPile...' button is pressed.
- //
- // 06/05/97 JMI Now rotates at a reduced rate when standing still.
- // Also, fixed bug with divisors when input for rotation
- // is nullified.
- //
- // 06/06/97 JMI Now utilizes CPowerUps' new CStockPile and GetDescription().
- // Also, reduced status font size so we can see moreat 640x480
- // (from 26 to 15).
- //
- // 06/07/97 JMI Now Revive() will try to use a CWarp.
- //
- // 06/08/97 BRH Added targeting sprite to the dude and using it
- // when calling IlluminateTarget() to display which enemy
- // or item is being targeted. Temporarily disabled the
- // targeting aid. Still need to add a key to toggle
- // m_bTargetingHelpEnabled and the position of the target
- // sprite needs to be adjusted.
- //
- // 06/09/97 BRH Adjusted the target position on the child and enabled
- // the targeting help.
- //
- // 06/09/97 JMI Now Revive() empties the message queue b/c we don't want
- // him responding to things that happened in his old location
- // (i.e., his location before he warped in).
- // Removed m_inputLast and m_lLastWeaponChangeTime which are
- // no longer necessary now that we can use the auto-repeat
- // feature with the new event driven rspGetKeyStatusArray()
- // used by input.cpp.
- // Added idle animation components.
- //
- // 06/09/97 BRH Hid the target when the option is disabled. Set the
- // default state to disabled.
- //
- // 06/09/97 JMI Disabled the SprayCannon.
- //
- // 06/09/97 JMI Changed INPUT_WALK to INPUT_RUN.
- //
- // 06/10/97 BRH Sends WeaponSelect and WeaponFire messages to CDemon
- // so that comments can be made about these actions.
- //
- // 06/09/97 JMI Added weapon selection feedback specific to whether weapons
- // are loaded or empty.
- //
- // 06/10/97 JMI Changed SLOW_TURN_DIVISOR from 1.5 to 1.25.
- //
- // 06/10/97 JMI Got rid of the SLOW_TURN_DIVISOR and added a second rate
- // inside of input to vary the rate.
- //
- // 06/10/97 JMI Now notifies demon of suicides.
- //
- // 06/11/97 JMI Commented out code that starts idle animation.
- // Also, made suicide zero your hitpoints.
- //
- // 06/11/97 JMI Revive() now drops a powerup before warping dude.
- //
- // 06/12/97 JMI Dude now checks to make sure he has the proper weapon to
- // fire the requested ammo.
- // Added handy functions, SetWeapon(), NextWeapon(), and
- // PrevWeapon().
- //
- // 06/12/97 JMI Added powerup responses to inputs 10 to 14.
- //
- // 06/12/97 JMI Adjusted some of the cheat powerups that were silly, silly
- // amounts.
- //
- // 06/12/97 JMI Made launch and throw anims use the events to show and
- // release weapons.
- // Now registers suicide death with Score module (but will
- // probably have to add m_pRealm as a parm once that accepts
- // it).
- // Now napalm launches from the missile launcher.
- // Also, re-enabled idle animation.
- //
- // 06/12/97 JMI Added ms_apszAmmoNames to differentiate between weapons
- // and ammo strings.
- //
- // 06/12/97 JMI Now DrawStatus() only draws once per StatusChange() call.
- //
- // 06/13/97 JMI Now State_ThrowRelease, State_LaunchRelease, and
- // State_PutDown all use WhileHoldingWeapon() to unhide and
- // release the weapon at the appropriate event driven times.
- //
- // 06/13/97 JMI Now correctly uses columns and word wrap with its m_print.
- //
- // 06/14/97 JMI Now picks up powerups when you run over them.
- //
- // 06/15/97 JMI Now minimizes total stockpile after adding in powerups.
- // Now initializes stockpiles since CStockPile no longer has
- // a constructor (I wanted it to be aggregatable).
- //
- // 06/16/97 JMI Now plays a sound when his torso hits the ground when dying.
- //
- // 06/16/97 JMI The target now alpha blits.
- //
- // 06/16/97 JMI Added MessageChange() and m_lMsgUpdateDoneTime.
- //
- // 06/16/97 JMI Plays audible feedback via powerup when powerups picked up.
- // Up, up, up, up.
- //
- // 06/16/97 JMI Added parms to make ShootWeapon() comply with virtual
- // base class version.
- // Also, fixed bug where, when out of bullets, we went ahead
- // and fired anyways.
- //
- // 06/16/97 JMI Now applies resets shot timer when a shot kills us.
- //
- // MJR Changed strafe speed.
- //
- // JMI Now registers death when he enters the State_Dead.
- //
- // 06/17/97 JMI Changed the hit the ground noise event val to 2 (was 1).
- //
- // JMI Added PlayStep() which is commented out b/c of sound probs.
- // Added m_u8LastEvent and OnExecute().
- //
- // JMI Added NULL in call to PlaySample() corresponding to new
- // param.
- //
- // 06/17/97 JMI Converted all occurrences of rand() to GetRand() and
- // srand() to SeedRand().
- //
- // 06/24/97 JMI Now notifies the demon of suicide in SetState() (used to
- // be in OnSuicideMsg() which is not the only way a suicide
- // can be initiated).
- // Also, now SetWeapon() only sends a message to the demon
- // if the new weapon has ammo.
- //
- // 06/25/97 JMI Added FindExecutee() which is called to find an executee
- // before entering the execute state. If none is found, we
- // do not enter the state. If we do enter the state, while
- // he is leading up to the shooting portion of the animation,
- // he turns toward the executee. When he fires at the
- // executee, it does not use FireBullets() but instead merely
- // creates a muzzle flare and sound for feedback and sends a
- // message to the executee telling him he's been shot.
- //
- // 06/25/97 JMI Now calls PrepareShadow() in Init() which loads and sets up
- // a shadow sprite.
- // Also, now prints 'you are dead' when you are out of
- // hitpoints.
- //
- // 06/25/97 JMI Replaced m_lStatusUpdateDoneTime with
- // m_lNextStatusUpdateTime and removed m_bUpdateStatus.
- // Also, changed SHELLS_PER_SPRAY_CANNON_FIRE from 4 to 1.
- // ms_apszAmmoNames[] now contain the sprintf format
- // specifiers to provide greater to control to each type over
- // whether to display a number and/or where to display it.
- // The machine gun no longer uses up bullets. So, once you
- // have bullets, you never run out.
- // Now hitting the rocket key while the rocket is selected
- // switches to heatseekers and vice-versa.
- // Now switches to the machine gun when you run out of
- // a particular weapon.
- //
- // 06/26/97 JMI The 'You are dead' message now flashes.
- // Target now goes away when you are dead.
- // Also, changed 'You are dead' to something else to get
- // Steve inspired enough to think of a cool one.
- //
- // 06/26/97 JMI Now handles throw weapons the same way launch weapons are
- // handled when leaving the animation early. That is, they
- // no longer drop, but, instead, just get deleted via a
- // message.
- //
- // 06/26/97 JMI Re-activated foot step sound.
- //
- // 06/27/97 JMI If the dude cannot move (i.e., MakeValidPos() fails), he
- // resets his velocity, acceleration, and drag to zero.
- // The only possible problem that I know of with this is that,
- // if there's an external force that's causing him to push up
- // against terrain, even if he is fighting the force by run-
- // ning against it, he won't be able to accelerate until the
- // force dissipates. Currently, though, all external forces
- // have drag.
- //
- // 06/28/97 JMI Now scales the Dude's Z through the realm before calling
- // SpewTriggers().
- //
- // 06/29/97 JMI Now uses the new name for the function that scales the Z
- // through the realm (MapZ3DtoY2D (was ScaleZ) ).
- //
- // 06/30/97 BRH Cached sound effects during the load so they will be
- // ready for their first use.
- //
- // 07/01/97 JMI Changed name of animation file for strafe from 'sidestep'
- // to 'strafe' and strafe and shoot from 'sideshoot' to
- // 'strafe'.
- // Added new rigid bodies to CDudeAnim3D and moved its
- // function defs into dude.cpp.
- // Also, added m_idFlagItem.
- //
- // 07/01/97 JMI Strafing was not playing anim backwards for left strafe
- // when shooting.
- // Also, a bug caused the strafe to not go backwards for
- // the regular (non-shooting) strafe if m_dRot was less than
- // 90.
- //
- // 07/02/97 BRH Changed the flamethrower to use CFirestreamID rather than
- // CFireballID.
- //
- // 07/03/97 JMI Now uses SetGuiToNotify() to make a button able to end a
- // DoGui() session.
- //
- // 07/04/97 BRH Made the Dude drop the flag if he gets blownup, burned or
- // he dies, also it tries to use the current animation's
- // rigid body transform for the release point but if it doesn't
- // have one it will just use the guy's position.
- //
- // 07/07/97 JMI DrawStatus() now returns true if it drew to the provide
- // image.
- //
- // 07/08/97 BRH Changed some of the animation names that were too long
- // for the delicate MacOS. Also changed hand transform
- // and backpack animation names.
- //
- // 07/09/97 JMI Changed MAX_STEPUP_THRESHOLD to use CThing3d's macro enum
- // MaxStepUpThreshold.
- //
- // 07/09/97 JMI Now uses m_pRealm->Make2dResPath() to get the fullpath
- // for 2D image components.
- //
- // 07/10/97 JMI Now uses "lfhand" for main rigid body for pick put anim.
- //
- // 07/10/97 JMI Changed names of loaded textures from "main_color%02d" to
- // "main_%d". Also, now it's zero based instead of 1 based.
- //
- // 07/12/97 JMI Now m_pRealm->m_bMultiplayer must be true in order to
- // Revive() a CDude.
- //
- // 07/13/97 JMI Set ms_dAccUser and ms_dAccDrag to 1000.0 each so the Dude
- // will start and stop nearly immediately.
- // Attempt to adjust the RUN_ANIM_VELOCITY but got nowhere.
- // Somebody who's better at judging distances should do that.
- //
- // 07/14/97 JMI Now applies damange to dude in OnBurnMsg() after doing all
- // other processing. The problem was that, when he was being
- // damaged before other processing, he would die if the damage
- // was great enough and then the other processing would not
- // be done.
- // Also, only destroys his fire when exiting the burning state
- // to go to other than the die state.
- //
- // 07/14/97 JMI Was subtracting from fuel for flamethrower in both
- // ArmWeapon() and ShootWeapon().
- //
- // 07/15/97 JMI Moved CDude() and ~CDude() from dude.h to dude.cpp.
- // Also, ShootWeapon() no longer checks for out of fuel con-
- // dition as this is done in ArmWeapon().
- //
- // 07/15/97 JMI Now dude will leave portions of powerups that he doesn't
- // need.
- //
- // 07/15/97 JMI Added TakePowerup().
- //
- // 07/16/97 JMI Made DropPowerUp() return the newly created powerup.
- // Added CreateCheat() which trims the amount the dude cannot
- // use from the stockpile and passes that to DropPowerUp().
- //
- // 07/16/97 JMI Changed the order of the weapons.
- //
- // 07/17/97 JMI Changed m_psnd to m_siLastPlayInstance.
- // Now uses new SampleMaster interface for volume and play
- // instance reference.
- //
- // 07/18/97 JMI Now uses StopLoopingSample() to stop looping the flame-
- // thrower sound (instead of GetInstanceChannel() ).
- //
- // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
- // Now there is one PlaySample() function. Also, you now
- // MUST specify a category and you don't have to specify a
- // SoundInstance ptr to specify a volume.
- //
- // 07/18/97 JMI Now updates font colors based on hood background's palette
- // rather than the RSPiX system palette.
- //
- // 07/19/97 JMI In previous fix, forgot to change the increment value for
- // the palette red, green, & blue arrays.
- // Also, now we pass our GUI to the stockpile editor.
- // Also, now Revive() allows revival in single player mode if
- // the dude has health greater than 0.
- // Also, the 'give health' cheat can now be activated while
- // dead.
- //
- // 07/20/97 BRH Added a few more sample caches for weapon selection and
- // powerup pickups.
- //
- // 07/20/97 JMI Now, if there's nothing the dude needs out of a powerup,
- // he plays a feedback sample and throws the powerup anyways.
- //
- // 07/20/97 JMI Spray cannon is now governed by MAX_SPRAYS_PER_SEC (10).
- //
- // 07/21/97 JMI Now TakePowerUp() returns the powerup if it persisted.
- // CreateCheat() now immediately hands the created powerup
- // to TakePowerUp() so there's no chance we'll miss it.
- // Also, TakePowerUp() will use the max stockpile for
- // backpacks not only if the dude has a backpack but, also,
- // if the dude will have a backpack (i.e., if there's one in
- // the powerup).
- // Also, added ms_apszWeaponStatusFormats[].
- // Now, if you have ammo but no weapon, it reports that you
- // have ammo but no weapon. Ingenious.
- //
- // 07/21/97 JMI Added OnWeaponDestroyed() override of CCharacter version.
- // Also, Update() now calls CCharacter version.
- // Also, ShootWeapon() now decrements ammo supplies (not
- // ArmWeapon() ).
- // Also, added m_weaponShooting.
- // Removed SHELLS_PER_SPRAY_CANNON_FIRE.
- //
- // 07/22/97 JMI Now can never run out of machine gun bullets again.
- //
- // 07/23/97 JMI Changed MIN_CANNOT_BE_SHOT_DURATION to 3000 (was 1500) ms.
- //
- // 07/23/97 JMI Added DefHasNapalmLauncher enum and added strings to in-
- // corporate new napalm launcher (used to be launched by the
- // missile launcher).
- //
- // 07/25/97 JMI Removed PickUp input.
- // Added option to Revive() to allow him to revive in-place
- // (rather than warping in).
- // Added m_bDead and IsDead() which are true when the dude
- // is dead.
- // Now uses m_bDead in most cases that m_state == State_Dead
- // and m_smash.m_bits & CSmash::Dead were used.
- //
- // 07/25/97 JMI Added StartAnim() which starts a CAnimThing.
- // Added visual feedback (bullet CChunks that fly off) when
- // wearing the kevlar layers.
- //
- // 07/27/97 JMI Now, like the chunks, ricochets appear on the appropriate
- // part of the dude's torso (based on the angle of the bullet).
- // It might make sense to eventually put the height of the shot
- // in the shot message so we can place the splat at the
- // appropriate height giving more feedback as to what's/who's
- // shooting us. It'd also be neat to adjust the damage based on
- // the vertical position.
- // Also, now StartAnim() does not call CRealm::Make2dResPath()
- // on passed in paths since CAnimThing does this
- // automatically.
- //
- // 07/28/97 JMI Now checks m_bDead (instead of m_stockpile.m_sHitPoints) to
- // determine if dude is dead in DrawStatus().
- // Also, only bobbles powerups when alive.
- //
- // 07/28/97 JMI Fixed resurection w/o powerup that would occur sometimes.
- // There are only two ways to leave the Die state, BlowUp and
- // Dead. Sometimes he would get blown up while dying skipping
- // ever getting his m_bDead flag set. Now the Die state sets
- // this flag as well since we know we want him to die if he
- // enters the die state.
- // Since, once his dead flag is set, he can accept the
- // resurection cheat, there's some misleading feedback in the
- // Die state if that cheat is entered.
- // To avoid this problem we could not set the flag and instead
- // set the persistent state to State_Dead so that when he's
- // done blowing up he'll go to the dead state, but setting the
- // flag seems much more likely to make sure he dies.
- //
- // 07/29/97 JMI Added GetCurrentWeapon().
- //
- // 07/30/97 JMI Added DeathWad components.
- // Now displays a random message from g_apszDeathMessages[]
- // when dead.
- //
- // 07/30/97 JMI Now the death wad cheat enables the death wad option in the
- // editor.
- //
- // 08/01/97 BRH CreateCheat() now sends a message to the CDemon to let
- // it know that a cheat code was entered so the Demon can
- // mock the player. Also added it in the revive case.
- // Also took out loading of .hot files since they aren't used
- // and will soon be deleted from the directories.
- // Changed fire damage to be based on difficulty setting.
- //
- // 08/04/97 JMI Now Damage() function will set m_bDead even if
- // SetState(State_Die) fails. This way, he'll die when he
- // comes out of the explosion state (he cannot go to die from
- // explode (unless explode is done) b/c that would look really
- // wrong).
- //
- // 08/04/97 JMI Added array of weapon anims, m_aanimWeapons[], and
- // a sprite for showing the current weapon, m_spriteWeapon.
- // Now changes weapons visually based on current weapon type.
- //
- // 08/04/97 JMI Now uses Jeff's rspDegDelta() to better determine which
- // direction to turn when executing.
- //
- // 08/05/97 JMI Changed reference of m_pRealm->m_bMultiplayer to
- // m_pRealm->m_flags.bMultiplayer.
- // Changed "rthand" to "gun" for right hand rigid body trans-
- // form.
- //
- // 08/05/97 JMI Added an ID to Message(). The idea being that, when the
- // same message ID is specified w/i a certain amount of time,
- // the more recent message is ignored.
- //
- // 08/06/97 JMI Now OnExecute(), TrackExecutee(), and FindExecutee() can
- // work with any CThing that defines GetX/Y/Z() (not just
- // CThing3d's).
- //
- // 08/07/97 JMI Added DoubleBarrel components.
- //
- // 08/07/97 JMI Forgot a break in switch in GetWeaponInfo().
- //
- // 08/07/97 JMI Added m_animBackpack and m_spriteBackpack for his backpack
- // when he has it.
- //
- // 08/07/97 JMI Removed commented out hot channel stuff from CDudeAnim3D.
- // Added release of backpack anim in FreeResources().
- //
- // 08/08/97 JMI Now that CCharacter handles flamer noise, this class now
- // longer has to (and doesn't).
- //
- // 08/08/97 JMI Added TossPowerUp().
- // Also, changed TakePowerup() to TakePowerUp().
- // Now, when he enters the dead state in multiplayer mode,
- // he drops his schtuff.
- //
- // 08/08/97 JMI Majorly condensed code segments for detaching flag by
- // calling DetachChild() which does most of what we were doing
- // here. Also, removed some conditions that were checking to
- // make sure m_panimCur and m_panimCur->m_ptransRigid were
- // valid but they were not very useful since if m_panimCur were
- // NULL we'd be fucked AND m_ptransRigid was not the
- // rigid body transforms being used for the flag anyways (we're
- // using m_ptransLeft).
- //
- // 08/09/97 JMI Draws dead frame into background just before reviving.
- //
- // 08/10/97 JMI Added StrafeLeft and StrafeRight inputs.
- // Also, changed Jump to Revive and INPUT_JUMP to INPUT_REVIVE.
- //
- // 08/10/97 JMI Changed doubles dDistX and Z to shorts sDistX and Z. The
- // compiler seemed to lock up when inlining was enabled and we
- // passed these two doubles to rspATan. With a different
- // function it worked fine and with one of the vars as a short
- // it worked fine. /shrug Looking for a VC patch.
- //
- // 08/10/97 JMI Added m_dLastCrawledToPosX, Z which are the last position
- // successfully crawled to by the crawler (except on the
- // first iteration where they are simply set to the dude's
- // starting point). In TRACENASSERT mode, an ASSERT is
- // generated if the position gets modified by other than the
- // crawler. In release mode, it sets him back to the last
- // successful crawled position.
- // Added a function to set m_dX, Y, & Z, SetPosition().
- //
- // 08/12/97 BRH Added CSmash::Ducking bits to the smash when he is
- // ducking down. When he is ducking, he won't get hit
- // by the missiles.
- //
- // 08/12/97 JMI Removed unused anims: m_animJump, JumpForward, Land,
- // LandForward, Fall.
- //
- // 08/13/97 JMI Temporarily shows particle effects regardless of user
- // setting in multiplayer mode.
- //
- // 08/14/97 JMI Switched references to g_GameSettings.m_sDifficulty to
- // m_pRealm->m_flags.sDifficulty.
- //
- // 08/14/97 BRH Added static collision bits to be passed as the default
- // bits for weapons that the dude shoots. The default
- // arguments in the ShootWeapon are unreliable and may
- // get set to the bits of the base class default args.
- // Also changed call of WhileHoldingWeapon to include
- // these default collision bits.
- //
- // 08/15/97 BRH Set the XrayAll flag when the Dude is dead, so if he
- // dies behind opaque, you will be able to see that he is
- // dead.
- //
- // 08/17/97 JMI Changed to only find writhers as executees and will
- // definitely hit the executee.
- //
- // 08/17/97 JMI Removed all occurrences of the SetXRayAll() call as this
- // would not be a good place to do that since this dude is
- // not necessarily the local dude. Soon we will change Play
- // to do it since it knows that.
- //
- // 08/17/97 JMI Got rid of m_szMessages and all message related functions
- // and variables from CDude since we are now using the toolbar
- // for dude status feedback to the user. This includes:
- // MsgTypeInfo, m_lNextStatusUpdateTime, m_lMsgUpdateDoneTime,
- // m_print, m_bClearedStatus, m_szMessages[], m_sDeadMsgNum,
- // ms_amtfMessages[], ms_u8FontForeIndex, ms_u8FontBackIndex,
- // ms_u8FontShadowIndex, DrawStatus(), StatusChange(),
- // MessageChange(), Message(), UpdateFontColors(),
- // CPowerUp::ms_apszPowerUpTypeNames[],
- // CPowerUp::GetDescription(), and some strings and a string
- // array in localize.*.
- //
- // 08/18/97 JMI Now applies no randomization to CChunks and instead allows
- // CChunk::Setup() to apply its own randomization based on
- // sway values passed to it. Also, CChunk::Construct() will
- // now fail if particles are disabled so we don't need to
- // check for that anymore.
- //
- // 08/18/97 JMI Moved StartAnim() from CDude to CThing3d so more things
- // could use it.
- //
- // 08/18/97 JMI Added m_bInvincible which gets set via cheat.
- // Added many cheats and revamped originals. There is one
- // left.
- //
- // 08/18/97 JMI Added cheat code for sales people.
- //
- // 08/18/97 JMI Changed Revive() to call DeadRender3D() (which used to be
- // known/called as just another Render() overload).
- //
- // 08/19/97 JMI No longer shoots CSmash::Misc items.
- //
- // 08/24/97 BRH Forwards the burn message to the child flag so that it
- // can react. Before he was dropping the flag when blown up
- // or burned, but only telling the flag when it was blown up,
- // so if you got burned while holding the flag, the flag was
- // in the wrong state and never looked for anyone to pick it
- // up again. So the flag would be stuck in place and you could
- // not grab it again.
- //
- // 08/24/97 JMI Now instead of setting his brightness to zero in the dead
- // state, he clears it in Revive(). This way he stays charred
- // even when laying there dead or being blown up but cannot
- // come back to life charred.
- //
- // 08/24/97 JMI Now INPUT_WEAPON_0 is no weapon and INPUT_WEAPON_10 is
- // mines.
- //
- // 08/28/97 BRH Moved the caching of samples to Init() now that the
- // Load function is not being called now that the warps
- // create a dude. Also added OnPutMeDowmMsg handler function
- // that the flag sends when it wants to be set down (on the
- // flagbase).
- //
- // 08/30/97 JMI Removed m_idFlagItem (now uses the sprite list and, for
- // flag child sprites, updates them all).
- //
- // 09/01/97 JMI Now ArmWeapon() sets m_weaponShooting to NoWeapon if it
- // fails to arm a weapon (either b/c of no ammo or the shoot
- // state is not attainable).
- //
- // 09/01/97 JMI Previous changed was hosing the shotgun so I made it a
- // little less strict.
- //
- // 09/02/97 JMI Now targets CSmash::Sentry in ms_u32CollideBitsInclude.
- //
- // 09/07/97 MJR Fixed bug in DropAllFlags() that didn't read the message
- // properly.
- //
- // 09/08/97 JMI Added Kevlar type for pieces of kevlar vest that
- // splatter off of dudes with vest.
- //
- // 11/21/97 JMI Now varies whether CSmash::Good is a desirable target to
- // our weapons based on the realm's multiplayer cooperative
- // flag.
- // Removed version of ShootWeapon() that took 3 default
- // parameters and replaced it with a version that takes no
- // parameters so we could control the defaults from within the
- // CPP.
- // Also, now sets CWeapons' detection bits explicitly via
- // SetDetectionBits() to NOT seek other players in Cooperative
- // multiplayer mode.
- //
- // 12/08/97 JMI Added an option for DropPowerUp() to only drop the
- // currently selected weapon.
- // Also, now sets m_sHitPoints to zero before calling
- // SetState(State_Dead) which was previously generating a
- // health powerup if m_sHitPoints was greater than zero which
- // was the case for suicide.
- //
- // 12/09/97 JMI Now drops all weapons when reviving in single player mode.
- // In general, drops all weapons when reviving at location of
- // death and drops only the current weapon when reviving via
- // a warp (the warp gives you additional stuff).
- //
- ////////////////////////////////////////////////////////////////////////////////
- #define DUDE_CPP
- #include "RSPiX.h"
- #include <math.h>
- #include "dude.h"
- #include "grenade.h"
- #include "game.h"
- #include "SampleMaster.h"
- #include "input.h"
- #include "AnimThing.h"
- #include "reality.h"
- #include "fire.h"
- #include "TriggerRegions.h"
- #include "PowerUp.h"
- #include "chunk.h"
- #include "warp.h"
- #include "score.h"
- #include "CompileOptions.h" // For sales cheat.
- #include "play.h"
- //#ifdef MOBILE
- bool demoCompat = false; //Set in Play.cpp
- //#endif
- #if defined(ALLOW_TWINSTICK)
- void GetDudeVelocity(double* d_Velocity, double* d_Angle);
- extern bool GetDudeFireAngle(double* d_Angle);
- #endif
- ////////////////////////////////////////////////////////////////////////////////
- // Macros/types/etc.
- ////////////////////////////////////////////////////////////////////////////////
- // Determines the number of elements in the passed array at compile time.
- #define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0]) )
- // Tunable bullet parameters.
- #define MAX_BULLETS_PER_SEC 6
- #define MS_BETWEEN_BULLETS (1000 / MAX_BULLETS_PER_SEC)
- #define MAX_SPRAYS_PER_SEC 10
- #define MS_BETWEEN_SPRAYS (1000 / MAX_SPRAYS_PER_SEC)
- #define MAX_FLAMES_PER_SEC 1000
- #define MS_BETWEEN_FLAMETHROWS (1000 / MAX_FLAMES_PER_SEC)
- #define MODIFY_GUI_FILE "res/editor/EditDude.gui"
- // Random amount the fire angle can adjust.
- #define FIRE_ANGLE_Y_SWAY 15
- #define FIRE_ANGLE_Z_SWAY 10
- // Maximum the guy can tweak your angle while you're on fire.
- #define ON_FIRE_ROT_TWEAKAGE 22
- #define ON_FIRE_VEL_TWEAKAGE ((short)ms_dMaxVelForeFast)
- // Amount per damage pt that translate to velocity.
- #define VEL_PER_DAMAGE 0.5
- // Gets a random between -range / 2 and range / 2.
- #define RAND_SWAY(sway) ((GetRand() % sway) - sway / 2)
- // Velocity for strafing.
- #define STRAFE_VEL 60.0
- #define EXPLOSION_VERTICAL_VEL_MULTIPLIER 1.0
- // Amount of time to suffer from shot.
- #define MIN_SHOT_DURATION 500
- // Amount of time before we can suffer another shot.
- #define MIN_CANNOT_BE_SHOT_DURATION 3000
- // Minimum duration between yells (for blown up and shot).
- #define MIN_BETWEEN_YELLS 750 // Current yell ('groan_male1.wav') is 640 ms.
- // IDs for GUIs.
- #define GUI_ID_STOCKPILE 3
- // The color range that is the same on all hoods.
- #define CONSTANT_COLOR_START_INDEX 95
- #define NUM_CONSTANT_COLOR_INDICES (256 - CONSTANT_COLOR_START_INDEX)
- // Size of font used for status updates.
- #define STATUS_FONT_SIZE 15
- // 0 for any of these colors is transparent.
- #define STATUS_FONT_FORE_RED 128
- #define STATUS_FONT_FORE_GREEN 0
- #define STATUS_FONT_FORE_BLUE 0
- #define STATUS_FONT_BACK_RED 0
- #define STATUS_FONT_BACK_GREEN 0
- #define STATUS_FONT_BACK_BLUE 0
- #define STATUS_FONT_SHADOW_RED 127
- #define STATUS_FONT_SHADOW_GREEN 127
- #define STATUS_FONT_SHADOW_BLUE 127
- #define STATUS_PRINT_X 0
- #define STATUS_PRINT_Y 0
- #define STATUS_UPDATE_DURATION 5000 // In ms.
- #define MESSAGE_UPDATE_DURATION 3000 // In ms.
- #define SHADOW_DEPTH_X 1
- #define SHADOW_DEPTH_Y 1
- // Rate at which run animation was made to travel in pixels per second.
- // This is used to compute a ratio to the current speed. The resulting
- // ratio is used to tune the animation rate dynamically.
- #define RUN_ANIM_VELOCITY 85.0 // Pix/Sec.
- // When below this speed, the dude will not be in his running anim.
- #define MIN_RUN_VEL 40.0 // Pix/Sec.
- // Maximum springiness for crawler.
- #define MAX_CRAWLER_PUSH_X 1.5
- #define MAX_CRAWLER_PUSH_Z 1.5
- // Time between cycling weapons that are chosen using the same input.
- #define WEAPON_CYCLE_TIME 250
- // Ladder tolerance.
- #define LADDER_DIR_TOLERANCE 20 // +/- this amount in degrees.
- #define BRAIN_SPLAT_NUM_CHUNKS 200
- #define BRAIN_SPLAT_SWAY 30
- // Reduced rate for standing still rotation.
- #define STILL_TURN_DIVISOR 2.0
- // Handy macro to define char* array with one 'base' name.
- #define CREATERESNAMES(var, base, rigid) \
- static char* var[] = \
- { \
- "3d/main_" #base ".sop", \
- "3d/main_" #base ".mesh", \
- "3d/main_" #base ".tex", \
- "3d/main_" #base ".hot", \
- "3d/main_" #base ".bounds", \
- "3d/main_" #base ".floor", \
- "3d/main_" #base "_" #rigid ".trans", \
- NULL, /* Safety */ \
- };
- #define TARGETING_FILE "target.img"
- // IDLE_ANIM_TIMEOUT is NOT evaluated every frame.
- #define IDLE_ANIM_TIMEOUT (5000 + (GetRand() % 5000) )
- #define IDLE_ANIM_LOOPS 1
- // This is multiplied our current number of kevlar layers and the
- // result is divided into the bullet damage to produce the damage
- // the dude receives.
- #define KEVLAR_PROTECTION_MULTIPLIER 3
- // Alpha level used when blit'ing the target crosshairs.
- #define TARGET_ALPHA_LEVEL 100
- // Max distance to writher when executing.
- #define EXECUTE_RADIUS 50
- // Time between constant status updates in milliseconds.
- #define STATUS_UPDATE_DELAY 500 // In ms.
- // Max lag time between a known status change and the next update.
- #define MAX_STATUS_LAG 250 // In ms.
- // These may not be correct for now, but just to get them up and running:
- // These are the names of the rigid body transforms that are loaded for
- // every dude animation.
- #define LEFT_HAND_RIGID_ANIM_NAME "lfhand"
- #define RIGHT_HAND_RIGID_ANIM_NAME "gun"
- #define BACK_RIGID_ANIM_NAME "backpack"
- // This value indicates no strafe motion and must be a totally invalid
- // strafe angle value.
- #define INVALID_STRAFE_ANGLE 0x7fff
- #define VEST_HIT_SWAY 10
- #define VEST_HIT_RES_NAME "Ricochet.aan"
- // This is the distance in realm units from the dude's center
- // to the outside of his jacket. This is used to adjust things
- // like ricochets off of his kevlar vest around the outside of
- // his torso.
- #define TORSO_RADIUS 5
- // The minimum square distance the dude wants to be back from
- // his target point when executing.
- #define MIN_SQR_DISTANCE_TO_EXECUTEE 250.0
- // The backpack animation basename.
- #define BACKPACK_RES_NAME "3d/backpack"
- #define COLLISION_BITS_INCLUDE (ms_u32CollideBitsInclude)
- #define COLLISION_BITS_DONTCARE (ms_u32CollideBitsDontcare | (m_pRealm->m_flags.bCoopMode ? 0 : CSmash::Good) )
- #define COLLISION_BITS_EXCLUDE (ms_u32CollideBitsExclude | (m_pRealm->m_flags.bCoopMode ? CSmash::Good : 0) )
- ////////////////////////////////////////////////////////////////////////////////
- // Variables/data
- ////////////////////////////////////////////////////////////////////////////////
- // These are default values -- actually values are set using the editor!
- double CDude::ms_dAccUser = 1000.0; //150.0; // Acceleration due to user
- double CDude::ms_dAccDrag = 1000.0; //110.0; // Acceleration due to drag
- double CDude::ms_dMaxVelFore = 85.0; // Maximum forward velocity
- double CDude::ms_dMaxVelBack = -60.0; // Maximum backward velocity
- double CDude::ms_dMaxVelForeFast = 120.0; // Maximum forward velocity
- double CDude::ms_dMaxVelBackFast = -90.0; // Maximum backward velocity
- double CDude::ms_dDegPerSec = 240.0; // Degrees of rotation per second
- double CDude::ms_dVertVelJump = 100.0; // Velocity of jump.
- U32 CDude::ms_u32CollideBitsInclude = CSmash::Character | CSmash::Barrel | CSmash::SpecialBarrel | CSmash::Sentry;
- U32 CDude::ms_u32CollideBitsDontcare = CSmash::Bad;
- U32 CDude::ms_u32CollideBitsExclude = 0;
- // Let this auto-init to 0
- short CDude::ms_sFileCount;
- // Weapon details database.
- CDude::WeaponDetails CDude::ms_awdWeapons[NumWeaponTypes] =
- {
- // NoWeapon.
- {
- "No Weapon", // Weapon name.
- "bare hands", // Ammo name.
- " No Weapon", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
-
- // SemiAutomatic.
- {
- "Machine Gun", // Weapon name.
- "Bullets", // Ammo name.
- " Machine Gun", // Status format.
- "3d/machinegun", // Weapon resource name.
- 1, // Min ammo required.
- },
-
- // ShotGun.
- {
- "Shotgun", // Weapon name.
- "Shells", // Ammo name.
- " Shotgun -- %d Shells", // Status format.
- "3d/shotgun", // Weapon resource name.
- 1, // Min ammo required.
- },
-
- // SprayCannon.
- {
- "Spray Cannon", // Weapon name.
- "Shells", // Ammo name.
- " Spray Cannon -- %d Shells", // Status format.
- "3d/spraygun", // Weapon resource name.
- 1, // Min ammo required.
- },
-
- // Grenade.
- {
- "Grenades", // Weapon name.
- "Grenades", // Ammo name.
- " %d Grenades", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
-
- // Rocket.
- {
- "Missile Launcher", // Weapon name.
- "Missiles", // Ammo name.
- " Missile Launcher -- %d Missiles", // Status format.
- "3d/launcher", // Weapon resource name.
- 1, // Min ammo required.
- },
- // Heatseeker.
- {
- "Missile Launcher", // Weapon name.
- "Heatseekers", // Ammo name.
- " Missile Launcher -- %d Heatseekers", // Status format.
- "3d/launcher", // Weapon resource name.
- 1, // Min ammo required.
- },
- // FireBomb.
- {
- "Cocktails", // Weapon name.
- "Cocktails", // Ammo name.
- " %d Cocktails", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
- // Napalm.
- {
- "Napalm Launcher", // Weapon name.
- "Napalm Canisters", // Ammo name.
- " Napalm Launcher -- %d Canisters", // Status format.
- "3d/napalmer", // Weapon resource name.
- 1, // Min ammo required.
- },
- // Fuel.
- {
- "Flame Thrower", // Weapon name.
- "Fuel Canisters", // Ammo name.
- " Flamer -- %d Fuel Canisters", // Status format.
- "3d/flmthrower", // Weapon resource name.
- 1, // Min ammo required.
- },
- // ProximityMine.
- {
- "Proximity Mines", // Weapon name.
- "Proximity Mines", // Ammo name.
- " %d Proximity Mines", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
- // TimedMine.
- {
- "Timed Mines", // Weapon name.
- "Timed Mines", // Ammo name.
- " %d Timed Mines", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
- // RemoteMine.
- {
- "Remote Mines", // Weapon name.
- "Remote Mines", // Ammo name.
- " %d Remote Mines", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
- // BouncingBettyMine.
- {
- "Bouncing Bettys", // Weapon name.
- "Bouncing Bettys", // Ammo name.
- " %d Bouncing Bettys", // Status format.
- NULL, // Weapon resource name.
- 1, // Min ammo required.
- },
- // DeathWad.
- {
- "Wad Launcher", // Weapon name.
- "Wads", // Ammo name.
- " Wad -- %d missiles, %d napalm canisters, %d fuel canisters, %d grenades", // Status format.
- "3d/napalmer", // Weapon resource name.
- 1, // Min ammo required.
- },
- // DoubleBarrel.
- {
- "Double Barrel", // Weapon name.
- "Shells", // Ammo name.
- " Double Barrel -- %d Shells", // Status format.
- "3d/shotgun", // Weapon resource name.
- 2, // Min ammo required.
- },
- };
- // Dude's default stockpile.
- CStockPile CDude::ms_stockpileDefault =
- {
- DefHitPoints, // m_sHitPoints
-
- DefNumGrenades, // m_sNumGrenades
- DefNumFireBombs, // m_sNumFireBombs
- DefNumMissiles, // m_sNumMissiles
- DefNumNapalms, // m_sNumNapalms
- DefNumBullets, // m_sNumBullets
- DefNumShells, // m_sNumShells
- DefNumFuel, // m_sNumFuel
- DefNumMines, // m_sNumMines
- DefNumHeatseekers, // m_sNumHeatseekers
-
- DefHasMachineGun, // m_sMachineGun
- DefHasLauncher, // m_sMissileLauncher
- DefHasShotgun, // m_sShotGun
- DefHasSprayCannon, // m_sSprayCannon
- DefHasFlamer, // m_sFlameThrower
- DefHasNapalmLauncher, // m_sNapalmLauncher.
- DefHasDeathWadLauncher, // m_sDeathWadLauncher.
- DefHasDoubleBarrel, // m_sDoubleBarrel.
-
- DefKevlarLayers, // m_sKevlarLayers
-
- DefHasBackpack, // m_sBackpack
- };
- // Nubs (a CCrawler tool). These are the realtive points on the X/Z plane that
- // define the hard and soft 'springs' that deflect the dude from terrain
- // obstacles.
- static CCrawler::Nub ms_anubs[] =
- {
- // Hard nubs
- { 8, 0, 1, 180, 1.0 },
- { 6, -6, 1, 225, 1.0 },
- { 0, -8, 1, 270, 1.0 },
- { -6, -6, 1, 315, 1.0 },
- { -8, 0, 1, 0, 1.0 },
- { -6, 6, 1, 45, 1.0 },
- { 0, 8, 1, 90, 1.0 },
- { 6, 6, 1, 135, 1.0 },
- // Soft nubs
- { 12, 0, 0, 180, 1.0 },
- { 9, -9, 0, 225, 1.0 },
- { 0, -12, 0, 270, 1.0 },
- { -9, -9, 0, 315, 1.0 },
- { -12, 0, 0, 0, 1.0 },
- { -9, 9, 0, 45, 1.0 },
- { 0, 12, 0, 90, 1.0 },
- { 9, 9, 0, 135, 1.0 }
- };
- ////////////////////////////////////////////////////////////////////////////////
- // Get the various components of this animation from the resource names
- // specified in the provided array of pointers to strings.
- ////////////////////////////////////////////////////////////////////////////////
- // virtual // Overridden here.
- short CDude::CDudeAnim3D::Get( // Returns 0 on success.
- char* pszBaseFileName, // In: Base string for resource filenames.
- char* pszRigidName, // In: String to add for rigid transform channel
- // or NULL for none.
- char* pszEventName, // In: String to add for event states channel
- // or NULL for none.
- short sLoopFlags) // In: Looping flags to apply to all channels
- // in this anim.
- {
- short sRes;
- char szResName[RSP_MAX_PATH];
- sprintf(szResName, "%s.sop", pszBaseFileName);
- sRes = rspGetResource(&g_resmgrGame, szResName, &m_psops);
- sprintf(szResName, "%s.mesh", pszBaseFileName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_pmeshes);
- sprintf(szResName, "%s.bounds", pszBaseFileName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_pbounds);
- if (pszRigidName != NULL)
- {
- sprintf(szResName, "%s_%s.trans", pszBaseFileName, pszRigidName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_ptransRigid);
- }
- if (pszEventName != NULL)
- {
- sprintf(szResName, "%s_%s.event", pszBaseFileName, pszEventName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_pevent);
- }
- // We always load these transforms.
- sprintf(szResName, "%s_" LEFT_HAND_RIGID_ANIM_NAME ".trans", pszBaseFileName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_ptransLeft);
- sprintf(szResName, "%s_" RIGHT_HAND_RIGID_ANIM_NAME ".trans", pszBaseFileName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_ptransRight);
- sprintf(szResName, "%s_" BACK_RIGID_ANIM_NAME ".trans", pszBaseFileName);
- sRes |= rspGetResource(&g_resmgrGame, szResName, &m_ptransBack);
- // If successful . . .
- if (sRes == 0)
- {
- m_psops->SetLooping(sLoopFlags);
- m_pmeshes->SetLooping(sLoopFlags);
- m_pbounds->SetLooping(sLoopFlags);
- if (m_ptransRigid != NULL)
- m_ptransRigid->SetLooping(sLoopFlags);
- if (m_pevent != NULL)
- m_pevent->SetLooping(sLoopFlags);
- m_ptransLeft->SetLooping(sLoopFlags);
- m_ptransRight->SetLooping(sLoopFlags);
- m_ptransBack->SetLooping(sLoopFlags);
- }
- return sRes;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Release all resources.
- ////////////////////////////////////////////////////////////////////////////////
- // virtual // Overridden here.
- void CDude::CDudeAnim3D::Release(void) // Returns nothing.
- {
- rspReleaseResource(&g_resmgrGame, &m_psops);
- rspReleaseResource(&g_resmgrGame, &m_pmeshes);
- rspReleaseResource(&g_resmgrGame, &m_pbounds);
- if (m_ptransRigid != NULL)
- rspReleaseResource(&g_resmgrGame, &m_ptransRigid);
- if (m_pevent != NULL)
- rspReleaseResource(&g_resmgrGame, &m_pevent);
- rspReleaseResource(&g_resmgrGame, &m_ptransLeft);
- rspReleaseResource(&g_resmgrGame, &m_ptransRight);
- rspReleaseResource(&g_resmgrGame, &m_ptransBack);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Constructor.
- ////////////////////////////////////////////////////////////////////////////////
- CDude::CDude(CRealm* pRealm)
- : CCharacter(pRealm, CDudeID)
- {
- m_statePersistent = State_Stand;
- // Set default stockpile.
- m_stockpile.Copy(&ms_stockpileDefault);
- m_weapontypeCur = SemiAutomatic;
- m_weaponShooting = NoWeapon;
- m_lLastShotTime = 0;
- m_lLastYellTime = 0;
- m_u16IdChild = CIdBank::IdNil;
- m_sTextureIndex = 0;
- m_u8LastEvent = 0;
- m_idVictim = CIdBank::IdNil;
- m_bDead = false;
- m_bInvincible = false;
- // Base the dude number of the number of dude's in the realm. Note that
- // this number already includes this dude, so we subtract 1 from so the
- // assigned dude numbers will start at 0.
- ASSERT(m_pRealm->m_asClassNumThings[CDudeID] > 0);
- m_sDudeNum = m_pRealm->m_asClassNumThings[CDudeID] - 1;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Destructor
- ////////////////////////////////////////////////////////////////////////////////
- CDude::~CDude()
- {
- // Kill dude
- Kill();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Load object (should call base class version!)
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::Load( // Returns 0 if successfull, non-zero otherwise
- RFile* pFile, // In: File to load from
- bool bEditMode, // In: True for edit mode, false otherwise
- short sFileCount, // In: File count (unique per file, never 0)
- ULONG ulFileVersion) // In: File version being loaded.
- {
- short sResult = 0;
- // In most cases, the base class Load() should be called.
- sResult = CCharacter::Load(pFile, bEditMode, sFileCount, ulFileVersion);
- if (sResult == 0)
- {
- // Load common data just once per file (not with each object)
- if (ms_sFileCount != sFileCount)
- {
- ms_sFileCount = sFileCount;
- switch (ulFileVersion)
- {
- default: // Newer versions where this format has not changed.
- case 1:
- // Load static data
- pFile->Read(&ms_dAccUser);
- pFile->Read(&ms_dAccDrag);
- pFile->Read(&ms_dMaxVelFore);
- pFile->Read(&ms_dMaxVelBack);
- pFile->Read(&ms_dMaxVelForeFast);
- pFile->Read(&ms_dMaxVelBackFast);
- pFile->Read(&ms_dDegPerSec);
- break;
- }
- }
- switch (ulFileVersion)
- {
- default: // Newer versions where this format has not changed.
- case 16:
- // Nothing to load here.
- break;
- case 15:
- case 14:
- case 13:
- pFile->Read(&m_stockpile.m_sNumHeatseekers);
- pFile->Read(&m_stockpile.m_sNumMines);
- case 12:
- case 11:
- case 10:
- pFile->Read(&m_stockpile.m_sNumFuel);
- case 9:
- pFile->Read(&m_stockpile.m_sNumShells);
- case 8:
- case 7:
- case 6:
- case 5:
- case 4:
- case 3:
- case 2:
- pFile->Read(&m_stockpile.m_sNumBullets);
- pFile->Read(&m_stockpile.m_sNumFireBombs);
- pFile->Read(&m_stockpile.m_sNumMissiles);
- pFile->Read(&m_stockpile.m_sNumNapalms);
- case 1:
- {
- pFile->Read(&m_stockpile.m_sNumGrenades);
- U32 u32Temp;
- pFile->Read(&u32Temp);
- m_state = (CCharacter::State)u32Temp;
- break;
- }
- }
- // Make sure there were no file errors or format errors . . .
- if (!pFile->Error() && sResult == 0)
- {
- // Init dude
- sResult = Init();
- }
- else
- {
- sResult = -1;
- TRACE("CDude::Load(): Error reading from file!\n");
- }
- }
- else
- {
- TRACE("CDude::Load(): CCharacter::Load() failed.\n");
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Save object (should call base class version!)
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::Save( // Returns 0 if successfull, non-zero otherwise
- RFile* pFile, // In: File to save to
- short sFileCount) // In: File count (unique per file, never 0)
- {
- short sResult = 0;
- // In most cases, the base class Save() should be called.
- sResult = CCharacter::Save(pFile, sFileCount);
- if (sResult == 0)
- {
- // Save common data just once per file (not with each object)
- if (ms_sFileCount != sFileCount)
- {
- ms_sFileCount = sFileCount;
- // Save static data.
- pFile->Write(&ms_dAccUser);
- pFile->Write(&ms_dAccDrag);
- pFile->Write(&ms_dMaxVelFore);
- pFile->Write(&ms_dMaxVelBack);
- pFile->Write(&ms_dMaxVelForeFast);
- pFile->Write(&ms_dMaxVelBackFast);
- pFile->Write(&ms_dDegPerSec);
- }
- // Save object data.
- sResult = pFile->Error();
- }
- else
- {
- TRACE("CDude::Save(): CCharacter::Save() failed.\n");
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Startup object
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::Startup(void) // Returns 0 if successfull, non-zero otherwise
- {
- short sResult = CCharacter::Startup();
-
- // Init other stuff
- m_lNextBulletTime = m_pRealm->m_time.GetGameTime() + MS_BETWEEN_BULLETS;
- // Set start position for crawler verification.
- m_dLastCrawledToPosX = m_dX;
- m_dLastCrawledToPosZ = m_dZ;
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Shutdown object
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::Shutdown(void) // Returns 0 if successfull, non-zero otherwise
- {
- short sResult = CCharacter::Shutdown();
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Suspend object
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Suspend(void)
- {
- if (m_sSuspend == 0)
- {
- // Store current delta so we can restore it.
- long lCurTime = m_pRealm->m_time.GetGameTime();
- m_lNextBulletTime = lCurTime - m_lNextBulletTime;
- }
- CCharacter::Suspend();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Resume object
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Resume(void)
- {
- CCharacter::Resume();
- if (m_sSuspend == 0)
- {
- long lCurTime = m_pRealm->m_time.GetGameTime();
- m_lNextBulletTime = lCurTime - m_lNextBulletTime;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Update object
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Update(void)
- {
- if (!m_sSuspend)
- {
- // Get new time
- long lThisTime = m_pRealm->m_time.GetGameTime();
- // Advance the animation timer.
- long lDifTime = lThisTime - m_lAnimPrevUpdateTime;
- m_lAnimTime += lDifTime;
- // Update prev time.
- m_lAnimPrevUpdateTime = lThisTime;
- // Process Input ////////////////////////////////////////////////////////
- double dMaxForeVel;
- double dMaxBackVel;
- short sStrafeAngle = INVALID_STRAFE_ANGLE; // Angle of motion from strafing.
- ProcessInput(
- &dMaxForeVel,
- &dMaxBackVel,
- &sStrafeAngle
- );
- // Process Forces ///////////////////////////////////////////////////////
- switch (m_state)
- {
- case State_BlownUp:
- break;
- default:
- ProcessForces(
- lThisTime,
- dMaxForeVel,
- dMaxBackVel,
- sStrafeAngle);
- break;
- }
-
- // Specific transitions by state dependent on motion ////////////////////
- switch (m_state)
- {
- default: // Catch all. Go to idle if NYI state.
- case State_Idle:
- break;
- case State_Dead:
- case State_Strafe:
- case State_StrafeAndShoot:
- case State_Stand:
- case State_Shooting:
- // If there's any movement . . .
- if (m_dAcc != 0.0)
- {
- // Move to running.
- switch (m_state)
- {
- case State_Stand:
- case State_Strafe:
- SetState(State_Run);
- break;
- case State_StrafeAndShoot:
- case State_Shooting:
- SetState(State_RunAndShoot);
- break;
- }
- }
- else
- {
- // If there's strafe motion . . .
- if (sStrafeAngle != INVALID_STRAFE_ANGLE)
- {
- switch (m_state)
- {
- case State_Stand:
- SetState(State_Strafe);
- break;
- case State_Shooting:
- SetState(State_StrafeAndShoot);
- break;
- case State_Strafe:
- case State_StrafeAndShoot:
- break;
- }
- }
- else
- {
- switch (m_state)
- {
- case State_Stand:
- case State_Shooting:
- break;
- case State_Strafe:
- SetState(State_Stand);
- break;
- case State_StrafeAndShoot:
- SetState(State_Shooting);
- break;
- }
- }
- }
- break;
- case State_Burning:
- {
- // Tweak out.
- m_dRot = rspMod360(m_dRot + RAND_SWAY(ON_FIRE_ROT_TWEAKAGE) );
- m_dVel += RAND_SWAY(ON_FIRE_VEL_TWEAKAGE) + ON_FIRE_VEL_TWEAKAGE / 4; // **FUDGE**
- }
- // Intentional fall through.
- case State_Run:
- case State_RunAndShoot:
- // If there's little movement . . .
- if ((m_dVel < MIN_RUN_VEL && m_dVel > -MIN_RUN_VEL && m_dAcc == 0.0))
- {
- // If not strafing . . .
- if (sStrafeAngle == INVALID_STRAFE_ANGLE)
- {
- // Move to standing.
- switch (m_state)
- {
- case State_Run:
- SetState(State_Stand);
- break;
- case State_RunAndShoot:
- SetState(State_Shooting);
- break;
- case State_Burning:
- break;
- }
- }
- else // We are strafing in some way.
- {
- // Move to standing.
- switch (m_state)
- {
- case State_Run:
- SetState(State_Strafe);
- break;
- case State_RunAndShoot:
- SetState(State_StrafeAndShoot);
- break;
- case State_Burning:
- break;
- }
- }
- }
- else
- {
- if (GetInput(m_sDudeNum) & INPUT_RUN)
- {
- if (StatsAreAllowed)
- {
- Stat_TimeRunning += lDifTime;
- if (Stat_TimeRunning >= (60 * 5 * 1000))
- UnlockAchievement(ACHIEVEMENT_RUN_5_MINUTES);
- }
- }
- }
- break;
- case State_Throw:
- case State_ThrowRelease:
- case State_ThrowDone:
- case State_ThrowFinish:
- case State_Launch:
- case State_LaunchRelease:
- case State_LaunchDone:
- case State_LaunchFinish:
- // Let's just say you can't move while throwing/launching.
- m_dVel = 0.0;
- m_dAcc = 0.0;
- m_dDrag = 0.0;
- break;
- }
- // Service message queue ////////////////////////////////////////////////
- ProcessMessages();
- // Switch on state.
- switch (m_state)
- {
- case State_Stand:
- {
- #if 1 // No idle anim currently.
- // If we've been idle for a while . . .
- if (m_lAnimTime > m_lNextIdleTime)
- {
- // Toggle anim.
- if (m_panimCur == &m_animStand)
- {
- // Switch to idle.
- m_panimCur = &m_animIdle;
- // Set next timeout.
- m_lNextIdleTime = m_animIdle.m_psops->TotalTime() * IDLE_ANIM_LOOPS;
- }
- else
- {
- // Switch to stand.
- m_panimCur = &m_animStand;
- // Set next timeout.
- m_lNextIdleTime = IDLE_ANIM_TIMEOUT;
- }
- // Reset anim timer.
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = lThisTime;
- }
- #endif
- break;
- }
- case State_Throw:
- {
- #if 1
- U8 u8Event = *( (U8*)(m_panimCur->m_pevent->GetAtTime(m_lAnimTime) ) );
- // Check for release point in animation . . .
- if (u8Event > 0)
- {
- CWeapon* pweapon;
- if (m_pRealm->m_idbank.GetThingByID((CThing**)&pweapon, m_u16IdWeapon) == 0)
- {
- if (pweapon->m_eState == CWeapon::State_Hide)
- {
- // Unhide grenade.
- pweapon->m_eState = CWeapon::State_Idle;
- }
- else if (u8Event > 1)
- {
- // Release projectile.
- // Go to State_ThrowRelease which is purely transitional to State_ThrowFinish.
- SetState(State_ThrowRelease);
- }
- }
- else
- {
- if (u8Event > 1)
- {
- // Release projectile.
- // Go to State_ThrowRelease which is purely transitional to State_ThrowFinish.
- SetState(State_ThrowRelease);
- }
- }
- }
- #else
- if (WhileHoldingWeapon(
- COLLISION_BITS_INCLUDE,
- COLLISION_BITS_DONTCARE,
- COLLISION_BITS_EXCLUDE) == true)
- {
- // Go to State_ThrowFinish.
- SetState(State_ThrowFinish);
- }
- #endif
- break;
- }
- case State_ThrowRelease:
- {
- ShootWeapon();
- // Finish animation.
- SetState(State_ThrowFinish);
- break;
- }
- case State_ThrowDone:
- case State_LaunchDone:
- // Move on.
- SetState(State_Persistent);
- break;
- case State_LaunchRelease:
- {
- ShootWeapon();
- // Finish animation.
- SetState(State_LaunchFinish);
- break;
- }
- case State_ThrowFinish:
- // Check for end of throw animation.
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // This will let us know to be done with throwing on the next Update.
- SetState(State_ThrowDone);
- }
- break;
- case State_Run:
- {
- // Remove adjustment made above.
- m_lAnimTime -= lDifTime;
- // Tune the time. Note that this is automathematically negative when
- // velocity is negative.
- long lDifAnimTime = lDifTime * (m_dVel / RUN_ANIM_VELOCITY);
- m_lAnimTime += lDifAnimTime;
- // Play step noise if event has changed.
- PlayStep();
- break;
- }
- case State_RunAndShoot:
- {
- // Remove adjustment made above.
- m_lAnimTime -= lDifTime;
- // Tune the time. Note that this is automathematically negative when
- // velocity is negative.
- long lDifAnimTime = lDifTime * (m_dVel / RUN_ANIM_VELOCITY);
- m_lAnimTime += lDifAnimTime;
- // Play step noise if event has changed.
- PlayStep();
- if (lThisTime >= m_lNextBulletTime)
- {
- // Shoot.
- ShootWeapon();
- }
- break;
- }
- case State_Shooting:
- // If out of bullets . . .
- if (m_stockpile.m_sNumBullets <= 0)
- {
- // Don't animate.
- m_lAnimTime -= lDifTime;
- }
- if (lThisTime >= m_lNextBulletTime)
- {
- // Shoot.
- ShootWeapon();
- }
- break;
- case State_StrafeAndShoot:
- // If going left of forwards . . .
- if (m_dRot - sStrafeAngle < 0)
- {
- // Subtract twice the time to make up for fact that it was already added once above
- m_lAnimTime -= lDifTime * 2;
- }
- // Play step noise if event has changed.
- PlayStep();
- if (lThisTime >= m_lNextBulletTime)
- {
- // Shoot.
- ShootWeapon();
- }
- break;
- case State_Strafe:
- // If going left of forwards . . .
- if (m_dRot - sStrafeAngle < 0)
- {
- // Subtract twice the time to make up for fact that it was already added once above
- m_lAnimTime -= lDifTime * 2;
- }
- // Play step noise if event has changed.
- PlayStep();
- break;
- case State_Shot:
- // Check for end of damage animation . . .
- // if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- // Instead check for minimum duration since last shot time . . .
- if (lThisTime > m_lLastShotTime + MIN_SHOT_DURATION)
- {
- // Stand.
- SetState(State_Persistent);
- }
- break;
- case State_BlownUp:
- // Check for end . . .
- if (WhileBlownUp() == false)
- {
- SetState(State_GetUp);
- }
- break;
- case State_Suicide:
- // Check for moment of firing weapon . . .
- if (*((U8*)(m_panimCur->m_pevent->GetAtTime(m_lAnimTime))) > 0
- && m_bBrainSplatted == false) // ***FUDGE***
- {
- // Play shot fire.
- PlaySample(g_smidShotgun, SampleMaster::Weapon);
- // Play shot received.
- PlaySample(g_smidDyingYell, SampleMaster::Voices);
- // Start gore.
- StartBrainSplat();
- // Remember.
- m_bBrainSplatted = true;
- // Register the kill.
- ScoreRegisterKill(m_pRealm, GetInstanceID(), m_u16InstanceId);
- // Note that he's dead
- m_bDead = true;
- }
- // Intentional fall through to State_Die.
- case State_Die:
- // Check for end of die animation . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Make sure we're dead for reals. Do this before the SetState()
- // so we doesn't end up dropping any health.
- m_stockpile.m_sHitPoints = 0;
- // Go to dead.
- SetState(State_Dead);
- // If he is carying the flag item, then he should drop it.
- DropAllFlags(NULL);
- }
- else if (m_bGenericEvent1 == false)
- {
- U8 u8Event = *( (U8*)(m_panimCur->m_pevent->GetAtTime(m_lAnimTime) ) );
- if (u8Event > 1) // ***FUDGE***
- {
- PlaySample(g_smidBodyImpact2, SampleMaster::Unspecified);
- m_bGenericEvent1 = true;
- }
- }
- break;
- case State_Burning:
- {
- // Play step noise if event has changed.
- PlayStep();
- CThing* pthingFire;
- // If the fire's gone . . .
- if (m_pRealm->m_idbank.GetThingByID(&pthingFire, m_u16IdFire) == 0)
- {
- if (!((CFire*) (pthingFire))->IsBurning())
- // Stand.
- SetState(State_Stand);
- }
- else
- {
- // Stand.
- SetState(State_Stand);
- }
- break;
- }
- case State_Launch:
- #if 0
- {
- U8 u8Event = *( (U8*)(m_panimCur->m_pevent->GetAtTime(m_lAnimTime) ) );
- // Check for launch point in animation . . .
- if (u8Event > 0)
- {
- CWeapon* pweapon;
- if (m_pRealm->m_idbank.GetThingByID((CThing**)&pweapon, m_u16IdWeapon) == 0)
- {
- if (pweapon->m_eState == CWeapon::State_Hide)
- {
- // Unhide missile.
- pweapon->m_eState = CWeapon::State_Idle;
- }
- else if (u8Event > 1)
- {
- // Release missile.
- // Go to State_LaunchRelase which is purely transitional to State_LaunchFinish.
- SetState(State_LaunchRelease);
- }
- }
- else
- {
- if (u8Event > 1)
- {
- // Release missile.
- // Go to State_LaunchRelase which is purely transitional to State_LaunchFinish.
- SetState(State_LaunchRelease);
- }
- }
- }
- }
- #else
- if (WhileHoldingWeapon(
- COLLISION_BITS_INCLUDE,
- COLLISION_BITS_DONTCARE,
- COLLISION_BITS_EXCLUDE) == true)
- {
- // Go to State_LaunchFinish.
- SetState(State_LaunchFinish);
- }
- #endif
- break;
- case State_LaunchFinish:
- // Check for end of launch animation . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to State_LaunchDone which is purely transitional to State_Stand.
- SetState(State_LaunchDone);
- }
- break;
- case State_GetUp:
- // check for end of getup anim . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- }
- break;
- case State_Rise:
- // check for end of rise anim . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- }
- break;
- case State_Jump:
- case State_JumpForward:
- if (m_lAnimTime > 750 && m_bJumpVerticalTrigger == false)
- {
- // Go up.
- m_dExtVertVel = ms_dVertVelJump;
- m_bJumpVerticalTrigger = true;
- }
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to fall state.
- SetState(State_Fall);
- }
- else
- {
- break;
- }
- // Intentional fall through to State_Fall.
- case State_Fall:
- // If we've reached the ground . . .
- if (m_bAboveTerrain == false)
- {
- // Go to land state.
- SetState((m_dVel == 0.0) ? State_Land : State_LandForward);
- }
- break;
- case State_Land:
- case State_LandForward:
- // Return to last persistent state.
- SetState(State_Persistent);
- break;
- case State_Execute:
- // check for end of execute anim . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- UnlockAchievement(ACHIEVEMENT_PERFORM_FIRST_EXECUTION);
- if (StatsAreAllowed) Stat_Executions++;
- }
- // If before point of firing . . .
- else if (m_lAnimTime < 1350) // ***FUDGE***.
- {
- // Track executee. If we lost 'em . . .
- if (TrackExecutee(lDifTime / 1000.0) == false)
- {
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- }
- }
- // If in point of firing . . .
- else if (m_lAnimTime < 1950) // ***FUDGE***.
- {
- #if 1
- if (lThisTime >= m_lNextBulletTime)
- {
- OnExecute();
- }
- #else
- if (lThisTime >= m_lNextBulletTime)
- {
- ArmWeapon(SemiAutomatic);
- ShootWeapon();
- }
- #endif
- }
- break;
- case State_PutDown:
- #if 0
- // Check for end of anim . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- }
- else
- {
- U8 u8Event = *( (U8*)(m_panimCur->m_pevent->GetAtTime(m_lAnimTime) ) );
- // Check for show point in anim . . .
- if (u8Event > 0)
- {
- // Check for drop point in animation . . .
- if (u8Event > 1)
- {
- if (m_u16IdWeapon != CIdBank::IdNil)
- {
- ShootWeapon();
- }
- }
- }
- #else
- if (WhileHoldingWeapon(
- COLLISION_BITS_INCLUDE,
- COLLISION_BITS_DONTCARE,
- COLLISION_BITS_EXCLUDE) == true)
- {
- // Go to State_ObjectReleased.
- SetState(State_ObjectReleased);
- }
- break;
- case State_ObjectReleased:
- // Check for end of anim . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- }
- #endif
- break;
- case State_PickUp:
- {
- CPowerUp* ppowerup;
- // Check for end of anim . . .
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- // If we still have the picked up item . . .
- if (m_pRealm->m_idbank.GetThingByID((CThing**)&ppowerup, m_u16IdChild) == 0)
- {
- TakePowerUp(&ppowerup);
- m_u16IdChild = CIdBank::IdNil;
- }
- // Go to last persistent state. Usually stand.
- SetState(State_Persistent);
- }
- else if (m_lAnimTime > 500 && m_bGenericEvent1 == false)
- {
- // This should be QuickCheckClosest, when available . . .
- CSmash* psmash = NULL; // Safety.
- if (m_pRealm->m_smashatorium.QuickCheck( // Returns true if collision detected, false otherwise
- &m_smash, // In: CSmash to check
- CSmash::PowerUp, // In: Bits that must be 1 to collide with a given CSmash
- 0, // In: Bits that you don't care about
- 0, // In: Bits that must be 0 to collide with a given CSmash
- &psmash) == true) // Out: Thing being smashed into if any (unless 0)
- {
- ASSERT(psmash->m_pThing != NULL);
- // Make it blit as a child.
- ASSERT(psmash->m_pThing->GetClassID() == CPowerUpID);
- ppowerup = (CPowerUp*)psmash->m_pThing;
- if (ppowerup->Grab(&m_sprite) == 0)
- {
- // Store/Identify child.
- m_u16IdChild = ppowerup->GetInstanceID();
- }
- // Note we already did this.
- m_bGenericEvent1 = true;
- }
- }
- else if (m_pRealm->m_idbank.GetThingByID((CThing**)&ppowerup, m_u16IdChild) == 0)
- {
- // Position powerup.
- PositionChild(
- &(ppowerup->m_sprite), // In: Child sprite to detach.
- (RTransform*) m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime), // In: Transform specifying position.
- &(ppowerup->m_dX), // Out: New position of child.
- &(ppowerup->m_dY), // Out: New position of child.
- &(ppowerup->m_dZ) ); // Out: New position of child.
- }
- break;
- }
- }
- // Update sphere.
- m_smash.m_sphere.sphere.X = m_dX;
- // Fudge center of sphere as half way up the dude.
- // Doesn't work if dude's feet leave the origin.
- m_smash.m_sphere.sphere.Y = m_dY + m_sprite.m_sRadius;
- m_smash.m_sphere.sphere.Z = m_dZ;
- m_smash.m_sphere.sphere.lRadius = m_sprite.m_sRadius;
- // Update the smash.
- m_pRealm->m_smashatorium.Update(&m_smash);
- // Check for powerups.
- CSmash* psmash = NULL; // Safety.
- if (m_pRealm->m_smashatorium.QuickCheck( // Returns true if collision detected, false otherwise
- &m_smash, // In: CSmash to check
- CSmash::PowerUp, // In: Bits that must be 1 to collide with a given CSmash
- 0, // In: Bits that you don't care about
- 0, // In: Bits that must be 0 to collide with a given CSmash
- &psmash) == true) // Out: Thing being smashed into if any (unless 0)
- {
- ASSERT(psmash->m_pThing != NULL);
- ASSERT(psmash->m_pThing->GetClassID() == CPowerUpID);
- CPowerUp* ppowerup = (CPowerUp*)psmash->m_pThing;
- // If we're not dead or the powerup contains health . . .
- if (m_bDead == false || ppowerup->m_stockpile.m_sHitPoints > 0)
- {
- TakePowerUp(&ppowerup);
- }
- }
- // Save time for next time
- m_lPrevTime = lThisTime;
- // Call the targeting aid function
- ShowTarget();
- // Call base class //////////////////////////////////////////////////////
- CCharacter::Update();
- // If requested to delete self . . .
- if (m_state == State_Delete)
- {
- // Good bye.
- delete this;
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Attempts user motivated state transitions.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::ProcessInput( // Returns nothing.
- double* pdMaxForeVel, // Out: Maximum forward velocity.
- double* pdMaxBackVel, // Out: Maximum backward velocity.
- short* psStrafeAngle) // Out: Strafe angle.
- {
- UINPUT input = 0;
- // Get user input
- input = GetInput(m_sDudeNum);
- bool bCanMove = true; // Flags for twinstick input so they don't override death, etc. states
- bool bCanFire = true;
- switch (m_state)
- {
- case State_Dead:
- // Let's take jump as 'revive' . . .
- if (input & INPUT_REVIVE)
- {
- // It's alive; alive!
- Revive();
- }
- // Allow only one input (life cheat) . . .
- if ( (input & INPUT_WEAPONS_MASK) == INPUT_CHEAT_15)
- {
- input = INPUT_CHEAT_15;
- }
- else
- {
- // No other user control during these states.
- input = 0;
- bCanMove = false;
- bCanFire = false;
- }
- break;
- case State_Die:
- case State_Suicide:
- // No user control during these states.
- input = 0;
- bCanMove = false;
- bCanFire = false;
- break;
- case State_BlownUp:
- case State_Rise:
- case State_GetUp:
- case State_PutDown:
- case State_ObjectReleased:
- case State_PickUp:
- // No user control during these states other than to change weapon.
- input &= INPUT_WEAPONS_MASK;
- bCanMove = false;
- bCanFire = false;
- break;
- case State_Throw:
- case State_ThrowRelease:
- case State_ThrowDone:
- case State_ThrowFinish:
- case State_Launch:
- case State_LaunchRelease:
- case State_LaunchDone:
- case State_LaunchFinish:
- //case State_Shot:
- // No influence on velocity during these states.
- input &= ~(INPUT_FORWARD | INPUT_BACKWARD | INPUT_REVIVE | INPUT_DUCK | INPUT_MOVE_UP | INPUT_MOVE_DOWN | INPUT_MOVE_LEFT | INPUT_MOVE_RIGHT);
- bCanMove = false;
- bCanFire = false;
- break;
- case State_Execute:
- case State_Duck:
- // No rotation or jumping.
- input &= ~(INPUT_LEFT | INPUT_RIGHT | INPUT_REVIVE | INPUT_ROT_MASK | INPUT_FORWARD | INPUT_BACKWARD | INPUT_MOVE_UP | INPUT_MOVE_DOWN | INPUT_MOVE_LEFT | INPUT_MOVE_RIGHT);
- bCanMove = false;
- bCanFire = false;
- break;
- }
- // Change weapon . . .
- WeaponType wtNew = m_weapontypeCur;
- switch (input & INPUT_WEAPONS_MASK)
- {
- case INPUT_WEAPON_1:
- case INPUT_WEAPON_2:
- case INPUT_WEAPON_3:
- case INPUT_WEAPON_4:
- case INPUT_WEAPON_5:
- //#ifdef MOBILE //We want weapon 5 to toggle weapon
- if (!demoCompat)
- {
- if (((input & INPUT_WEAPONS_MASK) == INPUT_WEAPON_5)
- && (m_weapontypeCur == Rocket))
- {
- wtNew = Heatseeker;
- break;
- }
- }
- //#endif
- case INPUT_WEAPON_6:
- case INPUT_WEAPON_7:
- case INPUT_WEAPON_8:
- case INPUT_WEAPON_9:
- wtNew = (WeaponType)(NoWeapon + ( ( (input & INPUT_WEAPONS_MASK) - INPUT_WEAPON_0) >> INPUT_WEAPONS_BIT) );
- break;
- case INPUT_WEAPON_0:
- switch (m_weapontypeCur)
- {
- case NoWeapon:
- if (m_stockpile.m_sDeathWadLauncher)
- {
- wtNew = DeathWad;
- break;
- }
- case DeathWad:
- if (m_stockpile.m_sDoubleBarrel)
- {
- wtNew = DoubleBarrel;
- break;
- }
- case DoubleBarrel:
- default:
- wtNew = NoWeapon;
- break;
- }
- break;
- case INPUT_WEAPON_10:
- switch (m_weapontypeCur)
- {
- default:
- wtNew = ProximityMine;
- break;
- case ProximityMine:
- wtNew = TimedMine;
- break;
- case TimedMine:
- #if 0 // Remote mines are not very useful currently.
- wtNew = RemoteMine;
- break;
- case RemoteMine:
- #endif
- wtNew = BouncingBettyMine;
- break;
- }
- break;
-
- // 'Cheats' ////////////////////////////////////////////////////
-
- case INPUT_CHEAT_11: // Restore health.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sHitPoints = MAX(0, m_sOrigHitPoints - m_stockpile.m_sHitPoints);
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_12: // Full kevlar.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sKevlarLayers = CStockPile::ms_stockpileBackPackMax.m_sKevlarLayers;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_13: // Backpack.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sBackpack = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_14: // Full weaponry, full ammo, backpack, and full kevlar.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sHitPoints = MAX(0, m_sOrigHitPoints - m_stockpile.m_sHitPoints);
- stockpile.m_sNumGrenades = CStockPile::ms_stockpileBackPackMax.m_sNumGrenades;
- stockpile.m_sNumFireBombs = CStockPile::ms_stockpileBackPackMax.m_sNumFireBombs;
- stockpile.m_sNumMissiles = CStockPile::ms_stockpileBackPackMax.m_sNumMissiles;
- stockpile.m_sNumNapalms = CStockPile::ms_stockpileBackPackMax.m_sNumNapalms;
- stockpile.m_sNumBullets = CStockPile::ms_stockpileBackPackMax.m_sNumBullets;
- stockpile.m_sNumShells = CStockPile::ms_stockpileBackPackMax.m_sNumShells;
- stockpile.m_sNumMines = CStockPile::ms_stockpileBackPackMax.m_sNumMines;
- stockpile.m_sNumHeatseekers = CStockPile::ms_stockpileBackPackMax.m_sNumHeatseekers;
- stockpile.m_sNumFuel = CStockPile::ms_stockpileBackPackMax.m_sNumFuel;
- stockpile.m_sMachineGun = 1;
- stockpile.m_sMissileLauncher = 1;
- stockpile.m_sShotGun = 1;
- stockpile.m_sSprayCannon = 1;
- stockpile.m_sFlameThrower = 1;
- stockpile.m_sNapalmLauncher = 1;
- stockpile.m_sKevlarLayers = CStockPile::ms_stockpileMax.m_sKevlarLayers;
- stockpile.m_sBackpack = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_15: // Revive.
- {
- UnlockAchievement(ACHIEVEMENT_ENABLE_CHEATS);
- Flag_Achievements |= FLAG_USED_CHEATS;
- Revive(false);
- // Let the demon know they entered a cheat code
- GameMessage msg;
- msg.msg_Cheater.eType = typeCheater;
- msg.msg_Cheater.sPriority = 0;
- CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
- if (pDemon)
- SendThingMessage(&msg, pDemon);
- break;
- }
- case INPUT_CHEAT_16: // DeathWadLauncher and ammo.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumGrenades = CStockPile::ms_stockpileBackPackMax.m_sNumGrenades;
- stockpile.m_sNumMissiles = CStockPile::ms_stockpileBackPackMax.m_sNumMissiles;
- stockpile.m_sNumNapalms = CStockPile::ms_stockpileBackPackMax.m_sNumNapalms;
- stockpile.m_sNumFuel = CStockPile::ms_stockpileBackPackMax.m_sNumFuel;
- stockpile.m_sDeathWadLauncher = 1;
- CreateCheat(&stockpile);
- // Enable death wad launcher in editor as well.
- CStockPile::ms_sEnableDeathWad = TRUE;
- break;
- }
- case INPUT_CHEAT_17: // DoubleBarrel and shells.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumShells = CStockPile::ms_stockpileBackPackMax.m_sNumShells;
- stockpile.m_sDoubleBarrel = 1;
- CreateCheat(&stockpile);
- // Enable Double Barrel in editor as well.
- CStockPile::ms_sEnableDoubleBarrel = TRUE;
- break;
- }
- case INPUT_CHEAT_18: // Mighty Mouse mode.
- {
- UnlockAchievement(ACHIEVEMENT_ENABLE_CHEATS);
- Flag_Achievements |= FLAG_USED_CHEATS;
- // Modify hood's scale.
- m_pRealm->m_phood->m_dScale3d -= 0.10;
- // Let the hood setup the pipeline.
- m_pRealm->m_phood->SetupPipeline();
- break;
- }
- case INPUT_CHEAT_19: // Shell weapons and ammo.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumShells = CStockPile::ms_stockpileBackPackMax.m_sNumShells;
- stockpile.m_sShotGun = 1;
- stockpile.m_sSprayCannon = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_20: // Explosive weapons and ammo.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumGrenades = CStockPile::ms_stockpileBackPackMax.m_sNumGrenades;
- stockpile.m_sNumMissiles = CStockPile::ms_stockpileBackPackMax.m_sNumMissiles;
- stockpile.m_sNumHeatseekers = CStockPile::ms_stockpileBackPackMax.m_sNumHeatseekers;
- stockpile.m_sMissileLauncher = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_21: // Flame weapons and ammo.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumFireBombs = CStockPile::ms_stockpileBackPackMax.m_sNumFireBombs;
- stockpile.m_sNumNapalms = CStockPile::ms_stockpileBackPackMax.m_sNumNapalms;
- stockpile.m_sNumFuel = CStockPile::ms_stockpileBackPackMax.m_sNumFuel;
- stockpile.m_sNapalmLauncher = 1;
- stockpile.m_sFlameThrower = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_22: // Shotgun and shells.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumShells = CStockPile::ms_stockpileBackPackMax.m_sNumShells;
- stockpile.m_sShotGun = 1;
-
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_23: // Spray cannon and shells.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumShells = CStockPile::ms_stockpileBackPackMax.m_sNumShells;
- stockpile.m_sSprayCannon = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_24: // Grenades and cocktails.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumGrenades = CStockPile::ms_stockpileBackPackMax.m_sNumGrenades;
- stockpile.m_sNumFireBombs = CStockPile::ms_stockpileBackPackMax.m_sNumFireBombs;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_25: // Missile launcher and missiles (including heatseekers).
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumMissiles = CStockPile::ms_stockpileBackPackMax.m_sNumMissiles;
- stockpile.m_sNumHeatseekers = CStockPile::ms_stockpileBackPackMax.m_sNumHeatseekers;
- stockpile.m_sMissileLauncher = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_26: // Napalm launcher and napalm canisters.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumNapalms = CStockPile::ms_stockpileBackPackMax.m_sNumNapalms;
- stockpile.m_sNapalmLauncher = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_27: // Flame thrower and fuel canisters.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumFuel = CStockPile::ms_stockpileBackPackMax.m_sNumFuel;
- stockpile.m_sFlameThrower = 1;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_28: // Mines.
- {
- CStockPile stockpile = { 0, };
- stockpile.m_sNumMines = CStockPile::ms_stockpileBackPackMax.m_sNumMines;
- CreateCheat(&stockpile);
- break;
- }
- case INPUT_CHEAT_29: // Unused except for SALES demo.
- {
- #ifdef SALES_DEMO
- CStockPile stockpile = { 0, };
- stockpile.m_sHitPoints = MAX(0, m_sOrigHitPoints - m_stockpile.m_sHitPoints);
- stockpile.m_sNumGrenades = CStockPile::ms_stockpileBackPackMax.m_sNumGrenades;
- stockpile.m_sNumFireBombs = CStockPile::ms_stockpileBackPackMax.m_sNumFireBombs;
- stockpile.m_sNumMissiles = CStockPile::ms_stockpileBackPackMax.m_sNumMissiles;
- stockpile.m_sNumNapalms = CStockPile::ms_stockpileBackPackMax.m_sNumNapalms;
- stockpile.m_sNumBullets = CStockPile::ms_stockpileBackPackMax.m_sNumBullets;
- stockpile.m_sNumShells = CStockPile::ms_stockpileBackPackMax.m_sNumShells;
- stockpile.m_sNumMines = CStockPile::ms_stockpileBackPackMax.m_sNumMines;
- stockpile.m_sNumHeatseekers = CStockPile::ms_stockpileBackPackMax.m_sNumHeatseekers;
- stockpile.m_sNumFuel = CStockPile::ms_stockpileBackPackMax.m_sNumFuel;
- stockpile.m_sMachineGun = 1;
- stockpile.m_sMissileLauncher = 1;
- stockpile.m_sShotGun = 1;
- stockpile.m_sSprayCannon = 1;
- stockpile.m_sFlameThrower = 1;
- stockpile.m_sNapalmLauncher = 1;
- stockpile.m_sKevlarLayers = CStockPile::ms_stockpileMax.m_sKevlarLayers;
- stockpile.m_sBackpack = 1;
- CreateCheat(&stockpile);
- // Also, make invincible.
- m_bInvincible = true;
- // Also, allow level advance.
- g_bEnableLevelAdvanceWithoutGoal = true;
- #endif
- break;
- }
- case INPUT_CHEAT_30: // Toggle invincibility.
- {
- UnlockAchievement(ACHIEVEMENT_ENABLE_CHEATS);
- Flag_Achievements |= FLAG_USED_CHEATS;
- m_bInvincible = !m_bInvincible;
- break;
- }
- }
- // "Twinstick" style inputs.
- if (!demoCompat)
- {
- if ((input & INPUT_MOVE_UP) || (input & INPUT_MOVE_DOWN) || (input & INPUT_MOVE_LEFT) || (input & INPUT_MOVE_RIGHT)
- || (input & INPUT_FIRE_UP) || (input & INPUT_FIRE_DOWN) || (input & INPUT_FIRE_LEFT) || (input & INPUT_FIRE_RIGHT))
- {
- // Say we're using twinstick mode
- m_bUseRotTS = true;
- // Turn off the normal movement inputs if present
- input &= ~(INPUT_FORWARD | INPUT_BACKWARD | INPUT_LEFT | INPUT_RIGHT);
- // Determine movement direction
- if (bCanMove)
- {
- if ((input & INPUT_MOVE_UP) || (input & INPUT_MOVE_DOWN) || (input & INPUT_MOVE_LEFT) || (input & INPUT_MOVE_RIGHT))
- {
- // Set up acceleration
- m_dAcc = ms_dAccUser;
- m_dDrag = 0;
- // Say which direction we want to go
- if (input & INPUT_MOVE_UP)
- m_dRotTS = 90 + (input & INPUT_MOVE_LEFT ? 45 : 0) + (input & INPUT_MOVE_RIGHT ? -45 : 0);
- else if (input & INPUT_MOVE_DOWN)
- m_dRotTS = -90 + (input & INPUT_MOVE_LEFT ? -45 : 0) + (input & INPUT_MOVE_RIGHT ? 45 : 0);
- else if (input & INPUT_MOVE_LEFT)
- m_dRotTS = 180;
- else if (input & INPUT_MOVE_RIGHT)
- m_dRotTS = 0;
- }
- else
- {
- m_dAcc = 0;
- if (m_dVel > 0)
- m_dDrag = ms_dAccDrag;
- else if (m_dVel < 0)
- m_dDrag = -ms_dAccDrag;
- }
- }
- // Determine fire direction
- if (bCanFire)
- {
- if ((input & INPUT_FIRE_UP) || (input & INPUT_FIRE_DOWN) || (input & INPUT_FIRE_LEFT) || (input & INPUT_FIRE_RIGHT))
- {
- // Say we're firing our weapon
- input |= INPUT_FIRE;
- // Then point in the correct direction
- if (input & INPUT_FIRE_UP)
- m_dRot = 90 + (input & INPUT_FIRE_LEFT ? 45 : 0) + (input & INPUT_FIRE_RIGHT ? -45 : 0);
- else if (input & INPUT_FIRE_DOWN)
- m_dRot = -90 + (input & INPUT_FIRE_LEFT ? -45 : 0) + (input & INPUT_FIRE_RIGHT ? 45 : 0);
- else if (input & INPUT_FIRE_LEFT)
- m_dRot = 180;
- else if (input & INPUT_FIRE_RIGHT)
- m_dRot = 0;
- }
- else
- // otherwise, point in the direction we're going
- m_dRot = m_dRotTS;
- }
- }
- //else
- //m_bUseRotTS = false;
- }
- #ifdef ALLOW_TWINSTICK
- if (!demoCompat)
- {
- GetDudeVelocity(&m_dJoyMoveVel, &m_dJoyMoveAngle);
- if (!bCanMove)
- m_dJoyMoveVel = 0;
- m_dJoyFireAngle = 0.f;
- m_bJoyFire = (bCanFire && GetDudeFireAngle(&m_dJoyFireAngle));
- if (m_dJoyMoveVel > 0 || m_bJoyFire)
- {
- // Setup movement
- if (m_dJoyMoveVel > 0)
- {
- // Say we're using twinstick mode
- m_bUseRotTS = true;
- // Turn off the normal movement inputs if present
- input &= ~(INPUT_FORWARD | INPUT_BACKWARD | INPUT_LEFT | INPUT_RIGHT);
- // Set up acceleration
- m_dAcc = ms_dAccUser;
- m_dDrag = 0;
- // Say which direction we want to go
- m_dRotTS = m_dJoyMoveAngle;
- }
- else
- {
- // Setup drag
- m_dAcc = 0;
- if (m_dVel > 0)
- m_dDrag = ms_dAccDrag;
- else if (m_dVel < 0)
- m_dDrag = -ms_dAccDrag;
- }
- // Setup firing
- if (m_bJoyFire)
- {
- // Say we're firing our weapon
- //input |= INPUT_FIRE;
- // Then point in the correct direction
- m_dRot = m_dJoyFireAngle;
- }
- else
- // otherwise, point in the direction we're going
- m_dRot = m_dJoyMoveAngle;
- }
- }
- #endif
- //TRACE("TSD Acc %f MA %f AA %f Fire %i\n", m_dAcc, m_dRotTS, m_dRot, m_bJoyFire);
- //TRACE("JoyVel %f JoyAngle %f Fire %i FireAngle %f\n", m_dJoyMoveVel, m_dJoyMoveAngle, m_bJoyFire, m_dJoyFireAngle);
- //#ifdef MOBILE
- if (!demoCompat)
- {
- //#endif // MOBILE
- if (input & INPUT_WEAPON_NEXT)
- {
- input &= ~(INPUT_FIRE);
- NextWeapon();
- }
- if (input & INPUT_WEAPON_PREV)
- {
- input &= ~(INPUT_FIRE);
- PrevWeapon();
- }
- //#ifdef MOBILE
- }
- //#endif // MOBILE
- // If a weapon key was pressed . . .
- if (input & INPUT_WEAPONS_MASK)
- {
- // If weapon was available . . .
- if (SetWeapon(wtNew) == true)
- {
- }
- }
- // See if the guy fires his weapon . . .
- // Check for general weapon fire . . .
- if (input & INPUT_FIRE)
- {
- // If not ducking . . .
- if (m_state != State_Duck)
- {
- ArmWeapon();
- }
- else
- {
- // We should get up first.
- SetState(State_Rise);
- }
-
- // Ducking is not a user option when rising for or firing.
- input &= ~INPUT_DUCK;
- }
- else
- {
- // If currently shooting . . .
- switch (m_state)
- {
- case State_Shooting:
- SetState(State_Stand);
- break;
- case State_RunAndShoot:
- SetState(State_Run);
- break;
- case State_StrafeAndShoot:
- SetState(State_Strafe);
- break;
- }
- }
- #ifdef MOBILE
- if (!demoCompat)
- {
- if (input & INPUT_STRAFE)
- {
- if (input & INPUT_LEFT)
- {
- *psStrafeAngle = m_dRot + 90;
- }
- else if (input & INPUT_RIGHT)
- {
- *psStrafeAngle = m_dRot - 90;
- }
- }
- {
- short sRotDelta = (short)(input & INPUT_ROT_MASK);
-
- if (sRotDelta != 0)
- sRotDelta -= 360;
- if (input & INPUT_ROT_IS_ABS)
- m_dRot = (double) sRotDelta;
- else
- m_dRot += (double) sRotDelta;
- // If there was any rotation while standing . . .
- if (sRotDelta != 0 && m_state == State_Stand)
- {
- // Reset stand state (to make sure idle anim doesn't kick (or gets turned
- // off if we're already in it) ).
- SetState(State_Stand);
- }
- }
- }
- else
- {
- #endif
- if (input & INPUT_STRAFE)
- {
- if (input & INPUT_LEFT)
- {
- *psStrafeAngle = m_dRot + 90;
- }
- else if (input & INPUT_RIGHT)
- {
- *psStrafeAngle = m_dRot - 90;
- }
- }
- else if (input & INPUT_STRAFE_LEFT)
- *psStrafeAngle = m_dRot + 90;
- else if (input & INPUT_STRAFE_RIGHT)
- *psStrafeAngle = m_dRot - 90;
- else
- {
- short sRotDelta = (short)(input & INPUT_ROT_MASK);
-
- if (sRotDelta != 0)
- sRotDelta -= 360;
- // Adjust by input delta.
- m_dRot += (double) sRotDelta;
- //printf("dRotDelta == (%f), m_dRot == (%f)\n", (float) dRotDelta, (float) m_dRot);
- // If there was any rotation while standing . . .
- if (sRotDelta != 0 && m_state == State_Stand)
- {
- // Reset stand state (to make sure idle anim doesn't kick (or gets turned
- // off if we're already in it) ).
- SetState(State_Stand);
- }
- }
- #ifdef MOBILE
- }
- #endif
- // Set acceleration based on user input (forward has precedance over reverse)
- if (input & INPUT_FORWARD)
- {
- m_dAcc = ms_dAccUser;
- m_dDrag = 0;
- m_bUseRotTS = false;
- }
- else if (input & INPUT_BACKWARD)
- {
- m_dAcc = -ms_dAccUser;
- m_dDrag = 0;
- m_bUseRotTS = false;
- }
- else if (!demoCompat && !((input & INPUT_MOVE_UP) || (input & INPUT_MOVE_DOWN) || (input & INPUT_MOVE_LEFT) || (input & INPUT_MOVE_RIGHT) || m_dJoyMoveVel > 0))
- {
- m_dAcc = 0;
- // If traveling forward . . .
- if (m_dVel > 0.0)
- {
- m_dDrag = -ms_dAccDrag;
- }
- else if (m_dVel < 0.0)
- {
- m_dDrag = ms_dAccDrag;
- }
- }
- // Limit to maximum velocity, which depends on whether "slow" key is being pressed
- if (input & INPUT_RUN)
- {
- *pdMaxForeVel = ms_dMaxVelForeFast;
- *pdMaxBackVel = ms_dMaxVelBackFast;
- }
- else
- {
- *pdMaxForeVel = ms_dMaxVelFore;
- *pdMaxBackVel = ms_dMaxVelBack;
- }
- // If jump specified . . .
- if ((input & INPUT_REVIVE) && 0) // ***TEMPORARILY DISABLED***
- {
- // If on the ground . . .
- if (m_bAboveTerrain == false)
- {
- // If moving forward of our own power. . .
- if (m_dVel > 0.0)
- {
- SetState(State_JumpForward);
- }
- else
- {
- SetState(State_Jump);
- }
- }
- }
- // If duck specified . . .
- if (input & INPUT_DUCK)
- {
- SetState(State_Duck);
- }
- else
- {
- if (m_state == State_Duck)
- {
- SetState(State_Rise);
- }
- }
- // If suicide specified . . .
- if (input & INPUT_SUICIDE)
- {
- // If we have the appropriate weapon . . .
- if (m_stockpile.m_sMachineGun)
- {
- SetState(State_Suicide);
- }
- else
- {
- // Audible user feedback.
- PlaySample(g_smidGeneralBeep, SampleMaster::UserFeedBack);
- }
- }
- // If execute specified . . .
- if (input & INPUT_EXECUTE)
- {
- // If not already executing . . .
- if (m_state != State_Execute)
- {
- // If we have the appropriate weapon . . .
- if (m_stockpile.m_sMachineGun)
- {
- // If there's someone close enough to execute . . .
- if (FindExecutee() == true)
- {
- // Do it.
- SetState(State_Execute);
- }
- }
- else
- {
- // Audible user feedback.
- PlaySample(g_smidGeneralBeep, SampleMaster::UserFeedBack);
- }
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Applies accelerations, velocities, reacts to terrain obstructions, etc.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::ProcessForces( // Returns nothing.
- long lCurTime, // In: Current game time.
- double dMaxForeVel, // Out: Maximum forward velocity.
- double dMaxBackVel, // Out: Maximum backward velocity.
- short sStrafeAngle) // Out: Strafe angle.
- {
- double dNewX, dNewY, dNewZ;
-
- // Calculate elapsed time in seconds.
- double dSeconds = (double)(lCurTime - m_lPrevTime) / 1000.0;
- #ifdef MOBILE
- if (!demoCompat)
- {
- TwinStickInfo analogInfo = AndroidGetMovment();
- if (analogInfo.velocity)
- {
- UpdateVelocities(dSeconds, dMaxForeVel * analogInfo.velocity, dMaxBackVel * analogInfo.velocity);
- GetNewPositionAngle(&dNewX, &dNewY, &dNewZ, dSeconds,analogInfo.movmentAngle);
- }
- else
- {
- // Update Velocities ////////////////////////////////////////////////////////
- UpdateVelocities(dSeconds, dMaxForeVel, dMaxBackVel);
- // Get New Position /////////////////////////////////////////////////////////
- GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
- //GetNewPositionAngle(&dNewX, &dNewY, &dNewZ, dSeconds,angle_for_postal);
- }
- }
- else
- {
- // Update Velocities ////////////////////////////////////////////////////////
- UpdateVelocities(dSeconds, dMaxForeVel, dMaxBackVel);
-
- // Get New Position /////////////////////////////////////////////////////////
- GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
- }
- #else
- // Update Velocities ////////////////////////////////////////////////////////
- #if defined(ALLOW_TWINSTICK)
- if (!demoCompat && m_dJoyMoveVel != 0)
- UpdateVelocities(dSeconds, dMaxForeVel * m_dJoyMoveVel, dMaxBackVel * m_dJoyMoveVel);
- else
- #endif // ALLOW_TWINSTICK
- UpdateVelocities(dSeconds, dMaxForeVel, dMaxBackVel);
-
- // Get New Position /////////////////////////////////////////////////////////
- if (!demoCompat && m_bUseRotTS)
- GetNewPositionAngle(&dNewX, &dNewY, &dNewZ, dSeconds, m_dRotTS);
- else
- GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
- #endif // MOBILE
- // If strafing . . .
- if (sStrafeAngle != INVALID_STRAFE_ANGLE)
- {
- // Add strafe.
- sStrafeAngle = rspMod360(sStrafeAngle);
- double dStrafeDistance = (STRAFE_VEL * dSeconds);
- dNewX += COSQ[sStrafeAngle] * dStrafeDistance;
- dNewZ -= SINQ[sStrafeAngle] * dStrafeDistance;
- }
- // Validate New Position ////////////////////////////////////////////////////
- if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, MaxStepUpThreshold) == true)
- {
- // Update Values /////////////////////////////////////////////////////////
- m_dX = dNewX;
- m_dY = dNewY;
- m_dZ = dNewZ;
- // Map through view angle which is the angle of the trigger plane.
- // (it is created by the user in the editor parallel with the
- // screen).
- double dTriggerY;
- m_pRealm->MapZ3DtoY2D(m_dZ, &dTriggerY);
- // Spew triggers.
- SpewTriggers(m_pRealm, GetInstanceID(), m_dX, dTriggerY);
- UpdateFirePosition();
- }
- else
- {
- // Restore Values ////////////////////////////////////////////////////////
-
- // Didn't actually move and, therefore, did not actually accelerate.
- // Restore velocities.
- // m_dVel -= m_dDeltaVel;
- // m_dExtHorzVel -= m_dExtHorzDeltaVel;
- m_dExtVertVel -= m_dExtVertDeltaVel;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Render object
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Render(void)
- {
- // Use user's chosen texture.
- m_panimCur->m_ptextures = m_aptextures[m_sTextureIndex];
- // Call base class.
- CCharacter::Render();
- // Update children, if any . . .
- CFlag* pflag = GetNextFlag(NULL);
- while (pflag)
- {
- PositionChild(
- pflag->GetSprite(),
- ((CDudeAnim3D*) m_panimCur)->m_ptransLeft->GetAtTime(m_lAnimTime), // In: Transform specifying position.
- NULL,
- NULL,
- NULL);
- // Update flag's position so it can correctly collision detect.
- pflag->m_dX = m_dX;
- pflag->m_dY = m_dY;
- pflag->m_dZ = m_dZ;
- // For asthetics, rotate it a bit.
- pflag->m_dRot = rspMod360(pflag->m_dRot + RAND_SWAY(10) );
- // Get next.
- pflag = GetNextFlag(pflag);
- }
- // Get anim . . .
- CAnim3D* panimWeapon = NULL; // Safety.
- switch (m_state)
- {
- case State_Suicide:
- case State_Execute:
- panimWeapon = &(m_aanimWeapons[SemiAutomatic]);
- break;
- default:
- panimWeapon = &(m_aanimWeapons[m_weapontypeCur]);
- break;
- }
- // If we have a visible weapon . . .
- if (panimWeapon->m_pmeshes)
- {
- // Show weapon sprite.
- m_spriteWeapon.m_sInFlags &= ~CSprite::InHidden;
- m_spriteWeapon.m_pmesh = panimWeapon->m_pmeshes->GetAtTime(m_lAnimTime);
- m_spriteWeapon.m_psop = panimWeapon->m_psops->GetAtTime(m_lAnimTime);
- m_spriteWeapon.m_ptex = panimWeapon->m_ptextures->GetAtTime(m_lAnimTime);
- m_spriteWeapon.m_psphere = panimWeapon->m_pbounds->GetAtTime(m_lAnimTime);
- m_spriteWeapon.m_ptrans = ((CDudeAnim3D*)m_panimCur)->m_ptransRight->GetAtTime(m_lAnimTime);
- }
- else
- {
- // Hide weapon sprite.
- m_spriteWeapon.m_sInFlags |= CSprite::InHidden;
- }
- // If we have a backpack . . .
- if (m_stockpile.m_sBackpack)
- {
- // Show backpack sprite.
- m_spriteBackpack.m_sInFlags &= ~CSprite::InHidden;
- ASSERT(m_animBackpack.m_pmeshes);
- m_spriteBackpack.m_pmesh = m_animBackpack.m_pmeshes->GetAtTime(m_lAnimTime);
- m_spriteBackpack.m_psop = m_animBackpack.m_psops->GetAtTime(m_lAnimTime);
- m_spriteBackpack.m_ptex = m_animBackpack.m_ptextures->GetAtTime(m_lAnimTime);
- m_spriteBackpack.m_psphere = m_animBackpack.m_pbounds->GetAtTime(m_lAnimTime);
- m_spriteBackpack.m_ptrans = ((CDudeAnim3D*)m_panimCur)->m_ptransBack->GetAtTime(m_lAnimTime);
- }
- else
- {
- // Hide bakcpack sprite.
- m_spriteBackpack.m_sInFlags |= CSprite::InHidden;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Called by editor to init new object at specified position
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::EditNew( // Returns 0 if successfull, non-zero otherwise
- short sX, // In: New x coord
- short sY, // In: New y coord
- short sZ) // In: New z coord
- {
- short sResult = CCharacter::EditNew(sX, sY, sZ);
- // Init dude
- sResult = Init();
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Helper inline to get a GUI, set its text to the value, and recompose it.
- ////////////////////////////////////////////////////////////////////////////////
- inline
- void SetText( // Returns nothing.
- RGuiItem* pguiRoot, // In: Root GUI.
- long lId, // In: ID of GUI to set text.
- long lVal) // In: Value to set text to.
- {
- RGuiItem* pgui = pguiRoot->GetItemFromId(lId);
- if (pgui != NULL)
- {
- pgui->SetText("%ld", lVal);
- pgui->Compose();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Called by editor to modify object
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::EditModify(void) // Returns 0 if successfull, non-zero otherwise.
- {
- short sResult = CCharacter::EditModify();
- if (sResult == 0)
- {
- RGuiItem* pgui = RGuiItem::LoadInstantiate(FullPathVD(MODIFY_GUI_FILE) );
- if (pgui)
- {
- sResult = m_stockpile.UserEdit(pgui);
- if (sResult == 0)
- {
- // Get values from dialog:
-
- // Currently none.
- // Success.
- }
- else
- {
- TRACE("EditModify(): m_stockpile.UserEdit() failed.\n");
- }
- delete pgui;
- }
- else
- {
- TRACE("EditModify(): Failed to open GUI \"%s\".\n", MODIFY_GUI_FILE);
- sResult = -2;
- }
- }
- else
- {
- TRACE("EditModify(): Base class EditModify() failed.\n");
- sResult = -1;
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Init dude
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::Init(void) // Returns 0 if successfull, non-zero otherwise
- {
- short sResult = 0;
- m_lPrevTime = m_pRealm->m_time.GetGameTime();
- m_lNextBulletTime = m_lPrevTime;
-
- // Get resources
- sResult = GetResources();
- // Prepare shadow (get resources and setup sprite).
- sResult |= PrepareShadow();
- // Setup stand state.
- SetState(State_Stand);
- m_smash.m_bits = CSmash::Good | CSmash::Character;
- m_smash.m_pThing = this;
- // No special flags.
- m_sprite.m_sInFlags = 0;
- // Targeting flag initially starts out as Hidden
- m_TargetSprite.m_sInFlags = CSprite::InHidden;
- // Set alpha blendage.
- m_TargetSprite.m_sAlphaLevel = TARGET_ALPHA_LEVEL;
- // This can be changed with the toggle, and should probably be
- // set initially by the preferences file.
- m_bTargetingHelpEnabled = false;
- // Setup weapon sprite.
- m_spriteWeapon.m_sInFlags = 0;
- m_spriteWeapon.m_pthing = this;
- m_sprite.AddChild(&m_spriteWeapon);
- // Setup backpack sprite.
- m_spriteBackpack.m_sInFlags = 0;
- m_spriteBackpack.m_pthing = this;
- m_sprite.AddChild(&m_spriteBackpack);
- // Setup our crawler.
- m_crawler.m_prealm = m_pRealm;
- m_crawler.m_sVertTolerance = MaxStepUpThreshold;
- m_crawler.Setup(
- sizeof(ms_anubs)/sizeof(ms_anubs[0]),
- ms_anubs,
- MAX_CRAWLER_PUSH_X,
- MAX_CRAWLER_PUSH_Z);
- // Store initial hit points.
- m_sOrigHitPoints = m_stockpile.m_sHitPoints;
- // Start with a weapon.
- m_weapontypeCur = NoWeapon;
- NextWeapon();
- // Cache gun sound effects since the gun has no preload
- CacheSample(g_smidRicochet1);
- CacheSample(g_smidRicochet2);
- CacheSample(g_smidBulletFire);
- CacheSample(g_smidShotgun);
- // Cache your own sound effects
- CacheSample(g_smidDyingYell);
- CacheSample(g_smidBodyImpact2);
- CacheSample(g_smidOutOfBullets);
- CacheSample(g_smidBulletIntoVest);
- CacheSample(g_smidBlownupYell);
- CacheSample(g_smidBurningMainGuy);
- CacheSample(g_smidEmptyWeapon);
- CacheSample(g_smidLoadedWeapon);
- CacheSample(g_smidStep);
- CacheSample(g_smidPickedUpWeapon);
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Kill dude
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Kill(void)
- {
- // Remove the target sprite, if there.
- m_pRealm->m_scene.RemoveSprite(&m_TargetSprite);
- // Free resources
- FreeResources();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Get all required resources
- ////////////////////////////////////////////////////////////////////////////////
- short CDude::GetResources(void) // Returns 0 if successfull, non-zero otherwise
- {
- short sResult = 0;
- // Anim base name Rigid name Event name Loop flags
- // =================== ============= =========== ===========
- sResult = m_animRun.Get ("3d/main_runnogun", NULL, "mainevent", RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animThrow.Get ("3d/main_grenade", "maingrenade", "mainevent", 0);
- sResult |= m_animStand.Get ("3d/main_bobbing", NULL, NULL, RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animDie.Get ("3d/main_die", NULL, "mainevent", 0);
- sResult |= m_animShoot.Get ("3d/main_shoot", "guntip", NULL, RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animRunShoot.Get ("3d/main_runshoot", "guntip", "mainevent", RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animDamage.Get ("3d/main_multi", NULL, NULL, RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animBurning.Get ("3d/main_onfire", NULL, "mainevent", RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animStrafe.Get ("3d/main_strafe", NULL, "mainevent", RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animStrafeShoot.Get("3d/main_strafe", "guntip", "mainevent", RChannel_LoopAtStart | RChannel_LoopAtEnd);
- sResult |= m_animSuicide.Get ("3d/main_suicide", "bhead", "mainevent", 0);
- sResult |= m_animLaunch.Get ("3d/main_missile", "mainmissile", "mainevent", 0);
- sResult |= m_animBlownUp.Get ("3d/main_blownup", NULL, NULL, 0);
- sResult |= m_animGetUp.Get ("3d/main_getup", NULL, NULL, 0);
- sResult |= m_animDuck.Get ("3d/main_duck", NULL, NULL, 0);
- sResult |= m_animRise.Get ("3d/main_rise", NULL, NULL, 0);
- sResult |= m_animExecute.Get ("3d/main_execute", "guntip", NULL, 0);
- sResult |= m_animPickPut.Get ("3d/main_pickput", "lfhand", "mainevent", 0);
- sResult |= m_animIdle.Get ("3d/main_idle", NULL, NULL, 0);
- // Get the different textures this dude could have.
- short i;
- char szResName[RSP_MAX_PATH];
- for (i = 0; i < MaxTextures && sResult == 0; i++)
- {
- sprintf(szResName, "3d/main_color%d.tex", i);
- sResult |= rspGetResource(&g_resmgrGame, szResName, &(m_aptextures[i]) );
- }
- // Get the different weapons this dude could use.
- for (i = NoWeapon; i < NumWeaponTypes; i++)
- {
- if (ms_awdWeapons[i].pszWeaponResName)
- {
- sResult |= m_aanimWeapons[i].Get(ms_awdWeapons[i].pszWeaponResName, NULL, NULL, NULL, RChannel_LoopAtStart | RChannel_LoopAtEnd);
- }
- }
- // Get the backpack.
- sResult |= m_animBackpack.Get(BACKPACK_RES_NAME, NULL, NULL, NULL, RChannel_LoopAtStart | RChannel_LoopAtEnd);
- // Get the targeting sprite
- sResult |= rspGetResource(&g_resmgrGame, m_pRealm->Make2dResPath(TARGETING_FILE), &(m_TargetSprite.m_pImage), RFile::LittleEndian);
-
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Free all resources
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::FreeResources(void)
- {
- // Release resources for animations.
- m_animRun.Release();
- m_animThrow.Release();
- m_animStand.Release();
- m_animDie.Release();
- m_animShoot.Release();
- m_animRunShoot.Release();
- m_animDamage.Release();
- m_animBurning.Release();
- m_animStrafe.Release();
- m_animStrafeShoot.Release();
- m_animSuicide.Release();
- m_animLaunch.Release();
- m_animBlownUp.Release();
- m_animGetUp.Release();
- m_animDuck.Release();
- m_animRise.Release();
- m_animExecute.Release();
- m_animPickPut.Release();
- m_animIdle.Release();
- // Release the different textures.
- short i;
- for (i = 0; i < MaxTextures; i++)
- {
- rspReleaseResource(&g_resmgrGame, &(m_aptextures[i]) );
- }
- // Release the different weapons this dude could use.
- for (i = NoWeapon; i < NumWeaponTypes; i++)
- {
- if (m_aanimWeapons[i].m_pmeshes)
- {
- m_aanimWeapons[i].Release();
- }
- }
- // Release the backpack.
- m_animBackpack.Release();
- // Release the targeting image
- rspReleaseResource(&g_resmgrGame, &(m_TargetSprite.m_pImage));
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Sets a new state based on supplied state enum. Will set animation ptr
- // to proper animation for state and reset animation timer.
- ////////////////////////////////////////////////////////////////////////////////
- bool CDude::SetState( // Returns true if new state realized, false otherwise.
- State state) // New state.
- {
- bool bRealizeNewState = true; // Assume we can enter state.
- State stateOld = m_state; // Remember current state.
- // If persistent state specified . . .
- if (state == State_Persistent)
- {
- // Use last persistent state.
- state = m_statePersistent;
- }
- // See if the state can be realized.
- switch (m_state)
- {
- case State_Idle:
- // Any new state is okay.
- break;
- case State_Stand:
- // Any new state is okay.
- break;
- case State_Run:
- // Any new state is okay.
- break;
- case State_ThrowDone:
- break;
- case State_Throw:
- case State_ThrowRelease:
- case State_ThrowFinish:
- switch (state)
- {
- case State_ThrowRelease:
- case State_ThrowFinish:
- case State_ThrowDone:
- case State_Die:
- case State_Shot:
- case State_BlownUp:
- case State_Burning:
- break;
- default:
- bRealizeNewState = false;
- break;
- }
- break;
- case State_Launch:
- case State_LaunchRelease:
- case State_LaunchFinish:
- switch (state)
- {
- case State_Die:
- case State_Shot:
- case State_BlownUp:
- case State_Burning:
- case State_LaunchRelease:
- case State_LaunchFinish:
- case State_LaunchDone:
- break;
- default:
- bRealizeNewState = false;
- break;
- }
- break;
- case State_LaunchDone:
- break;
- case State_Die:
- switch (state)
- {
- case State_Dead:
- case State_BlownUp:
- break;
- default:
- bRealizeNewState = false;
- break;
- }
- break;
- case State_Dead:
- switch (state)
- {
- case State_Die:
- case State_Shot:
- case State_Burning:
- bRealizeNewState = false;
- break;
- case State_BlownUp:
- break;
- default:
- break;
- }
- break;
- case State_Shooting:
- switch (state)
- {
- case State_Duck:
- bRealizeNewState = false;
- break;
- }
- break;
- case State_RunAndShoot:
- // Can go anywhere from here.
- break;
- case State_Shot:
- switch (state)
- {
- case State_Shot:
- bRealizeNewState = false;
- break;
- case State_BlownUp:
- case State_Die:
- break;
- default:
- // Check for minimum duration since last shot time . . .
- if (m_pRealm->m_time.GetGameTime() < m_lLastShotTime + MIN_SHOT_DURATION)
- {
- bRealizeNewState = false;
- }
- break;
- }
- break;
- case State_BlownUp:
- switch (state)
- {
- case State_BlownUp:
- break;
- default:
- // Check for end of blown up state . . .
- if (m_lAnimTime < m_panimCur->m_psops->TotalTime())
- {
- bRealizeNewState = false;
- }
- break;
- }
- break;
- case State_Burning:
- switch (state)
- {
- case State_Shot:
- case State_BlownUp:
- // Ok, but come back to this state.
- m_statePersistent = m_state;
- break;
- case State_Die:
- case State_Stand:
- // Don't come back.
- m_statePersistent = State_Stand;
- break;
- default:
- bRealizeNewState = false;
- break;
- }
- break;
- case State_Suicide:
- switch (state)
- {
- case State_Dead:
- break;
- default:
- // Cannot leave this state except to die.
- bRealizeNewState = false;
- break;
- }
- break;
- case State_GetUp:
- // Can only switch states due to violence or anim done.
- switch (state)
- {
- case State_Die:
- case State_Shot:
- case State_BlownUp:
- case State_Burning:
- break;
- default:
- // Check for end of get up state . . .
- if (m_lAnimTime < m_panimCur->m_psops->TotalTime())
- {
- bRealizeNewState = false;
- }
- break;
- }
- break;
- case State_Duck:
- // Can go to any other state.
- break;
- case State_Rise:
- // Can go to any other state.
- break;
- case State_Jump:
- case State_JumpForward:
- // Only landing and falling?...damage? blown up? Not sure yet.
- break;
- case State_Fall:
- break;
- case State_Land:
- break;
- case State_LandForward:
- break;
- case State_Execute:
- break;
- case State_PutDown:
- break;
- case State_ObjectReleased:
- break;
- case State_PickUp:
- break;
- }
- // If new state realized . . .
- if (bRealizeNewState == true)
- {
- // Clean up old state.
- switch (stateOld)
- {
- case State_Idle: // No cleaning necessary.
- case State_Stand:
- case State_Die:
- case State_Run:
- case State_Shot:
- case State_Suicide:
- case State_GetUp:
- break;
- case State_Duck:
- // Clear the ducking bit
- m_smash.m_bits &= ~CSmash::Ducking;
- break;
- case State_Dead:
- break;
- case State_Burning:
- // If not coming back to this state . . .
- if (stateOld != m_statePersistent)
- {
- // If the new state is die . . .
- if (state == State_Die)
- {
- // Keep the fire.
- }
- else
- {
- // If there's a fire burning . . .
- CThing* pthingFire;
- if (m_pRealm->m_idbank.GetThingByID(&pthingFire, m_u16IdFire) == 0)
- {
- // Send it a delete message.
- GameMessage msg;
- msg.msg_ObjectDelete.eType = typeObjectDelete;
- msg.msg_ObjectDelete.sPriority = 0;
- SendThingMessage(&msg, pthingFire);
- }
- }
- }
- break;
- case State_PickUp:
- {
- // If there's a powerup that we haven't let go of . . .
- CPowerUp* ppowerup;
- if (m_pRealm->m_idbank.GetThingByID((CThing**)&ppowerup, m_u16IdChild) == 0)
- {
- ppowerup->Drop(m_dX, m_dY, m_dZ);
- }
- break;
- }
- case State_Throw:
- case State_ThrowDone:
- case State_ThrowRelease:
- case State_ThrowFinish:
- case State_PutDown:
- {
- // If there's a weapon that we haven't let go of . . .
- CWeapon* pweapon;
- if (m_pRealm->m_idbank.GetThingByID((CThing**)&pweapon, m_u16IdWeapon) == 0 && state != State_ThrowRelease)
- {
- // It should drop like a rock.
- pweapon->m_dHorizVel = (GetRand() % (short)CGrenade::ms_dThrowHorizVel); // NOTE: ****USING RAND()****
- pweapon->m_dRot = GetRand() % 360;
- ShootWeapon();
- // Delete it!
- GameMessage msg;
- msg.msg_ObjectDelete.eType = typeObjectDelete;
- msg.msg_ObjectDelete.sPriority = 0;
- SendThingMessage(&msg, pweapon);
- }
- break;
- }
- case State_Launch:
- case State_LaunchDone:
- case State_LaunchRelease:
- case State_LaunchFinish:
- case State_Shooting:
- case State_RunAndShoot:
- case State_StrafeAndShoot:
- {
- // Abort weapon launch.
- // If there's a weapon that we haven't launched . . .
- CWeapon* pweapon;
- if (m_pRealm->m_idbank.GetThingByID((CThing**)&pweapon, m_u16IdWeapon) == 0 && state != State_LaunchRelease)
- {
- // Done with it.
- ShootWeapon();
- // Delete it!
- GameMessage msg;
- msg.msg_ObjectDelete.eType = typeObjectDelete;
- msg.msg_ObjectDelete.sPriority = 0;
- SendThingMessage(&msg, pweapon);
- }
- break;
- }
- case State_BlownUp:
- // If dead . . .
- if (m_bDead == true)
- {
- // Simon says, "die."
- state = State_Dead;
- }
- break;
- case State_Execute:
- m_idVictim = CIdBank::IdNil;
- break;
- }
- // Setup new state.
- m_state = state;
- switch (state)
- {
- case State_Idle:
- m_panimCur = NULL;
- // Make sure we're not in the render list.
- m_pRealm->m_scene.RemoveSprite(&m_sprite);
- break;
- case State_Stand:
- m_statePersistent = State_Stand;
- m_panimCur = &m_animStand;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- m_lNextIdleTime = IDLE_ANIM_TIMEOUT;
- break;
- case State_Run:
- if (stateOld != State_Run)
- {
- m_panimCur = &m_animRun;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
-
- m_u8LastEvent = 0;
- }
- break;
- case State_Throw:
- m_panimCur = &m_animThrow;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- break;
- case State_ThrowDone:
- // This state is transitional only.
- break;
- case State_ThrowRelease:
- // This state marks the release of the thrown object.
- break;
- case State_ThrowFinish:
- // During this state the throw animation is played to finish.
- // The thrown item has been released already.
- break;
- case State_Die:
- m_panimCur = &m_animDie;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- // Ahhhhhhhhhh....
- PlaySample(g_smidDyingYell, SampleMaster::Voices);
- m_bGenericEvent1 = false;
- // Make sure he ends up dead.
- m_bDead = true;
- break;
- case State_Dead:
- {
- // If not already dead . . .
- if (m_bDead == false)
- {
- // Note deadness.
- m_bDead = true;
- }
- // Add in our Dead smash bit.
- m_smash.m_bits |= CSmash::Dead;
- // If in multiplayer . . .
- if (m_pRealm->m_flags.bMultiplayer == true)
- {
- // Drop powerup.
- // Create powerup . . .
- CPowerUp* ppowerup = DropPowerUp(&m_stockpile, true);
- if (ppowerup)
- {
- // Clear my stockpile.
- m_stockpile.Zero();
- // Toss it, baby.
- TossPowerUp(ppowerup, 30);
- }
- }
- break;
- }
- case State_Shooting:
- // If not already in this state . . .
- if (stateOld != State_Shooting)
- {
- m_panimCur = &m_animShoot;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- }
- break;
- case State_RunAndShoot:
- // If not already in this state . . .
- if (stateOld != State_RunAndShoot)
- {
- m_panimCur = &m_animRunShoot;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- m_u8LastEvent = 0;
- }
- break;
- case State_Shot:
- m_panimCur = &m_animDamage;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- break;
- case State_BlownUp:
- m_panimCur = &m_animBlownUp;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
-
- m_bGenericEvent1 = false;
- break;
- case State_Burning:
- // If not already in this state . . .
- if (stateOld != State_Burning)
- {
- m_panimCur = &m_animBurning;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
-
- m_u8LastEvent = 0;
- }
- break;
- case State_Strafe:
- // If not already in this state . . .
- if (stateOld != State_Strafe)
- {
- m_panimCur = &m_animStrafe;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
-
- m_u8LastEvent = 0;
- }
- break;
- case State_StrafeAndShoot:
- // If not already in this state . . .
- if (stateOld != State_StrafeAndShoot)
- {
- m_panimCur = &m_animStrafeShoot;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
-
- m_u8LastEvent = 0;
- }
- break;
- case State_Suicide:
- {
- if (StatsAreAllowed) Stat_Suicides++;
- UnlockAchievement(ACHIEVEMENT_COMMIT_SUICIDE);
- m_panimCur = &m_animSuicide;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- m_bBrainSplatted = false;
- m_bGenericEvent1 = false;
- m_dVel = 0.0;
- // Let the demon know.
- GameMessage msg;
- msg.msg_Suicide.eType = typeSuicide;
- msg.msg_Suicide.sPriority = 0;
- CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
- if (pDemon)
- SendThingMessage(&msg, pDemon);
- break;
- }
- case State_Launch:
- m_panimCur = &m_animLaunch;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- break;
- case State_LaunchRelease:
- // This state marks the release of the launched object.
- break;
- case State_LaunchFinish:
- // During this state the launch animation is played to finish.
- // The launched item has been released already.
- break;
- case State_LaunchDone:
- // This state is transitional only.
- break;
- case State_GetUp:
- m_panimCur = &m_animGetUp;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- break;
- case State_Duck:
- // Set the ducking bits so missiles won't hit him.
- m_smash.m_bits |= CSmash::Ducking;
- if (stateOld != State_Duck)
- {
- m_panimCur = &m_animDuck;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- }
- break;
- case State_Rise:
- // If not already in this state . . .
- if (stateOld != State_Rise)
- {
- // If we were just in the duck state . . .
- if (stateOld == State_Duck)
- {
- // We want to only rise based on how ducked we are.
- // If we duck at the same rate we rise, there's a relation
- // between the times of the animations.
- // If not past the end of the duck . . .
- if (m_lAnimTime < m_animDuck.m_psops->TotalTime())
- {
- ASSERT(m_animDuck.m_psops->TotalTime() != 0);
- // Get the ratio between the two animations total times.
- float fRatio = (float)m_animRise.m_psops->TotalTime()
- / (float)m_animDuck.m_psops->TotalTime();
- // Invert the time in the new animations time base.
- m_lAnimTime = m_animRise.m_psops->TotalTime() - m_lAnimTime * fRatio;
- }
- else
- {
- m_lAnimTime = 0;
- }
- }
- else
- {
- m_lAnimTime = 0;
- }
- m_panimCur = &m_animRise;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- }
- break;
- case State_Jump:
- if (stateOld != State_Jump)
- {
- // m_panimCur = &m_animJump;
- ASSERT(0); // No longer a valid state.
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- // Clear trigger.
- m_bJumpVerticalTrigger = false;
- }
- break;
- case State_JumpForward:
- if (stateOld != State_JumpForward)
- {
- // m_panimCur = &m_animJumpForward;
- ASSERT(0); // No longer a valid state.
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- // Clear trigger.
- m_bJumpVerticalTrigger = false;
- }
- break;
- case State_Execute:
- if (stateOld != State_Execute)
- {
- m_panimCur = &m_animExecute;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- m_bGenericEvent1 = false;
- PlaySample(g_smidExecution, SampleMaster::UserFeedBack);
- }
- break;
- case State_PutDown:
- if (stateOld != State_PutDown)
- {
- m_panimCur = &m_animPickPut;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- }
- break;
- case State_ObjectReleased:
- // Use current anim settings.
- break;
- case State_PickUp:
- if (stateOld != State_PickUp)
- {
- m_panimCur = &m_animPickPut;
- m_lAnimTime = 0;
- m_lAnimPrevUpdateTime = m_pRealm->m_time.GetGameTime();
- m_bGenericEvent1 = false;
- }
- break;
- }
- }
- return bRealizeNewState;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Gets info on specified weapon.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::GetWeaponInfo( // Returns nothing.
- WeaponType weapon, // In: Weapon type to query.
- ClassIDType* pidWeapon, // Out: CThing class ID of weapon.
- short** ppsNum) // Out: Ptr to the weapon's counter.
- {
- static short sSafetyNum = 0;
- short *psNumLeft = &sSafetyNum;
- // Switch on weapon type . . .
- switch (weapon)
- {
- case NoWeapon:
- *pidWeapon = 0;
- *ppsNum = &sSafetyNum;
- break;
- case Grenade:
- *pidWeapon = CGrenadeID;
- *ppsNum = &m_stockpile.m_sNumGrenades;
- break;
- case FireBomb:
- *pidWeapon = CFirebombID;
- *ppsNum = &m_stockpile.m_sNumFireBombs;
- break;
- case Rocket:
- *pidWeapon = CRocketID;
- *ppsNum = &m_stockpile.m_sNumMissiles;
- break;
- case Napalm:
- *pidWeapon = CNapalmID;
- *ppsNum = &m_stockpile.m_sNumNapalms;
- break;
- case SemiAutomatic:
- *pidWeapon = CMachineGunID;
- *ppsNum = &m_stockpile.m_sNumBullets;
- break;
- case ShotGun:
- *pidWeapon = CShotGunID;
- *ppsNum = &m_stockpile.m_sNumShells;
- break;
- case FlameThrower:
- *pidWeapon = CFirestreamID; //CFireballID;
- *ppsNum = &m_stockpile.m_sNumFuel;
- break;
- case ProximityMine:
- *pidWeapon = CProximityMineID;
- *ppsNum = &m_stockpile.m_sNumMines;
- break;
- case TimedMine:
- *pidWeapon = CTimedMineID;
- *ppsNum = &m_stockpile.m_sNumMines;
- break;
- case RemoteMine:
- *pidWeapon = CRemoteControlMineID;
- *ppsNum = &m_stockpile.m_sNumMines;
- break;
- case BouncingBettyMine:
- *pidWeapon = CBouncingBettyMineID;
- *ppsNum = &m_stockpile.m_sNumMines;
- break;
- case Heatseeker:
- *pidWeapon = CHeatseekerID;
- *ppsNum = &m_stockpile.m_sNumHeatseekers;
- break;
- case SprayCannon:
- *pidWeapon = CAssaultWeaponID;
- *ppsNum = &m_stockpile.m_sNumShells;
- break;
- case DeathWad:
- *pidWeapon = CDeathWadID;
- *ppsNum = &m_stockpile.m_sNumMissiles;
- break;
- case DoubleBarrel:
- *pidWeapon = CDoubleBarrelID;
- *ppsNum = &m_stockpile.m_sNumShells;
- break;
- default:
- TRACE("GetWeaponInfo(): Query on invalid weapon (%d).\n", (short)weapon);
- break;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Fire specified weapon type.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::ArmWeapon( // Returns nothing.
- WeaponType weapon /*= CurrentWeapon*/) // In: Weapon to fire.
- {
- // If firing not in progress . . .
- if (m_u16IdWeapon == CIdBank::IdNil)
- {
- // If no specific weapon . . .
- if (weapon == CurrentWeapon)
- {
- weapon = m_weapontypeCur;
- }
- // Get current weapon and stockpile.
- short* psNumLeft;
- GetWeaponInfo(weapon, &m_eWeaponType, &psNumLeft);
- ULONG weaponFlag = 0;
- switch (weapon)
- {
- case Grenade: weaponFlag = FLAG_USED_GRENADE; break;
- case FireBomb: weaponFlag = FLAG_USED_MOLOTOV; break;
- case Rocket: weaponFlag = FLAG_USED_ROCKET; break;
- case Napalm: weaponFlag = FLAG_USED_NAPALM; break;
- case SemiAutomatic: weaponFlag = FLAG_USED_M16; break;
- case ShotGun: weaponFlag = FLAG_USED_SHOTGUN; break;
- case FlameThrower: weaponFlag = FLAG_USED_FLAMETHROWER; break;
- case ProximityMine: weaponFlag = FLAG_USED_PROXIMITY_MINE; break;
- case TimedMine: weaponFlag = FLAG_USED_TIMED_MINE; break;
- case RemoteMine: weaponFlag = FLAG_USED_REMOTE_MINE; break;
- case BouncingBettyMine: weaponFlag = FLAG_USED_BETTY_MINE; break;
- case Heatseeker: weaponFlag = FLAG_USED_HEATSEEKER; break;
- case SprayCannon: weaponFlag = FLAG_USED_SPRAY_CANNON; break;
- case DeathWad: weaponFlag = FLAG_USED_DEATHWAD; break;
- case DoubleBarrel: weaponFlag = FLAG_USED_DBL_SHOTGUN; break;
- }
- State stateShoot = State_Throw;
- switch (weapon)
- {
- case FlameThrower:
- case SemiAutomatic:
- case SprayCannon:
- if ((m_dVel >= MIN_RUN_VEL || m_dVel <= -MIN_RUN_VEL || m_dAcc != 0.0))
- {
- stateShoot = State_RunAndShoot;
- }
- else
- {
- switch (m_state)
- {
- case State_Strafe:
- case State_StrafeAndShoot:
- stateShoot = State_StrafeAndShoot;
- break;
- case State_Execute:
- stateShoot = State_Execute;
- break;
- default:
- stateShoot = State_Shooting;
- break;
- }
- }
- break;
- case ShotGun:
- case DoubleBarrel:
- stateShoot = State_Launch;
- break;
- case Grenade:
- case FireBomb:
- stateShoot = State_Throw;
- break;
- case Napalm:
- case Rocket:
- case Heatseeker:
- case DeathWad:
- stateShoot = State_Launch;
- break;
- case ProximityMine:
- case TimedMine:
- case RemoteMine:
- case BouncingBettyMine:
- stateShoot = State_PutDown;
- break;
- }
- // If we have any of this weapon . . .
- if (*psNumLeft >= ms_awdWeapons[weapon].sMinAmmoRequired)
- {
- // Enter our weapon launch state.
- if (SetState(stateShoot) == true)
- {
- if (GetInputMode() != INPUT_MODE_PLAYBACK) // don't let demo mode set these flags, or the endgame will ruin achievements.
- {
- Flag_Achievements |= weaponFlag;
- if ((Flag_Achievements & FLAG_MASK_WEAPONS) == FLAG_MASK_WEAPONS)
- UnlockAchievement(ACHIEVEMENT_USE_EVERY_WEAPON);
- }
- // Remember the type of ammo we're shooting.
- m_weaponShooting = weapon;
- CWeapon* pweapon = PrepareWeapon();
- if (pweapon != NULL)
- {
- GameMessage msg;
- msg.msg_WeaponFire.eType = typeWeaponFire;
- msg.msg_WeaponFire.sPriority = 0;
- msg.msg_WeaponFire.sWeapon = (short) weapon;
- CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
- if (pDemon)
- SendThingMessage(&msg, pDemon);
- }
- }
- else
- {
- // Note that we were unable to arm a weapon.
- // m_weaponShooting = NoWeapon;
- }
- }
- else
- {
- // Switch to the old faithful.
- SetWeapon(SemiAutomatic);
- // Note that we were unable to arm a weapon.
- m_weaponShooting = NoWeapon;
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Shoot current weapon.
- // This should be done when the character releases the weapon it's
- // shooting.
- ////////////////////////////////////////////////////////////////////////////////
- CWeapon* CDude::ShootWeapon(void) // Returns the weapoin ptr or NULL.
- {
- return ShootWeapon(
- COLLISION_BITS_INCLUDE,
- COLLISION_BITS_DONTCARE,
- COLLISION_BITS_EXCLUDE);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Shoot current weapon.
- // This should be done when the character releases the weapon it's
- // shooting.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- CWeapon* CDude::ShootWeapon( // Returns the weapon ptr or NULL.
- CSmash::Bits bitsInclude /*= ms_u32CollideBitsInclude*/,
- CSmash::Bits bitsDontcare /*= ms_u32CollideBitsDontcare*/,
- CSmash::Bits bitsExclude /*= ms_u32CollideBitsExclude*/)
- {
- bool bShootWeapon = true; // Assume we should shoot the weapon.
- CWeapon* pweapon = NULL; // Assume nothing.
- // If the weapon is in an invalid position . . .
- if (ValidateWeaponPosition() == false)
- {
- bShootWeapon = false;
- }
- if (m_weaponShooting != NoWeapon && bShootWeapon == true)
- {
- // Get the weapon info.
- ClassIDType idWeapon;
- short* psNumLeft;
- GetWeaponInfo(m_weaponShooting, &idWeapon, &psNumLeft);
- // ASSERT(idWeapon == m_eWeaponType);
- switch (m_eWeaponType)
- {
- case CFirestreamID: //CFireballID:
- if (m_u16IdWeapon != CIdBank::IdNil)
- {
- }
- else
- {
- bShootWeapon = false;
- }
- break;
- case CShotGunID:
- if (m_stockpile.m_sNumShells > 0)
- {
- }
- else
- {
- // Don't fire.
- bShootWeapon = false;
- }
- break;
- case CDoubleBarrelID:
- if (m_stockpile.m_sNumShells > 1)
- {
- // Subtract one now (another will be taken soon -- cheezy... I know).
- m_stockpile.m_sNumShells--;
- }
- else
- {
- // Don't fire.
- bShootWeapon = false;
- }
- break;
- case CAssaultWeaponID:
- if (m_stockpile.m_sNumShells > 0)
- {
- // Note time of next fire.
- m_lNextBulletTime = m_pRealm->m_time.GetGameTime() + MS_BETWEEN_SPRAYS;
- }
- else
- {
- // Note time of next fire.
- m_lNextBulletTime = m_pRealm->m_time.GetGameTime() + MS_BETWEEN_SPRAYS * 3;
- // Feedback.
- PlaySample(g_smidOutOfBullets, SampleMaster::Weapon);
- // Don't fire.
- bShootWeapon = false;
- }
- break;
- case CMachineGunID:
- // Cannot run out of bullets.
- // Note time of next fire.
- m_lNextBulletTime = m_pRealm->m_time.GetGameTime() + MS_BETWEEN_BULLETS;
- // If we have any of this weapon . . .
- if (m_stockpile.m_sNumBullets < CStockPile::ms_stockpileMax.m_sNumBullets)
- {
- // Success.
- m_stockpile.m_sNumBullets = CStockPile::ms_stockpileMax.m_sNumBullets;
- }
- break;
- }
- // If we actually want to shoot the weapon . . .
- if (bShootWeapon)
- {
- // Deduct ammo.
- *psNumLeft = *psNumLeft - 1;
- pweapon = CCharacter::ShootWeapon(bitsInclude, bitsDontcare, bitsExclude);
- // If a weapon was returned . . .
- if (pweapon)
- {
- // Set the detection bits (not all weapons use these). The only one
- // I know of currently is the heatseeker.
- pweapon->SetDetectionBits(
- CSmash::Character,
- 0,
- m_pRealm->m_flags.bCoopMode ? CSmash::Good : 0);
- }
- }
- }
- return pweapon;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Receive damage.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Damage( // Returns nothing.
- short sHitPoints, // Hit points of damage to do.
- U16 u16ShooterId) // In: Thing responsible for damage.
- {
- // Remember if already dead . . .
- bool bDead = m_bDead;
- if (m_bInvincible == false)
- {
- if (StatsAreAllowed) Stat_DamageTaken += sHitPoints;
- m_stockpile.m_sHitPoints -= sHitPoints;
- // If out of life . . .
- if (m_stockpile.m_sHitPoints <= 0)
- {
- m_stockpile.m_sHitPoints = 0;
- if (m_state != State_Die && m_state != State_Dead)
- {
- // Go to die.
- SetState(State_Die);
- // Even if we fail to enter the die state (like, if we're being
- // blown up). Be dead.
- m_bDead = true;
-
- // If he wasn't already dead when he entered here, then register the kill.
- if (bDead == false)
- ScoreRegisterKill(m_pRealm, GetInstanceID(), u16ShooterId);
- }
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Start the brain splat anim on its way.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::StartBrainSplat(void) // Returns nothing.
- {
- double dBrainX, dBrainY, dBrainZ;
- GetLinkPoint( // Returns nothing.
- m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime), // In: Transform specifying point.
- &dBrainX, // Out: Point specified.
- &dBrainY, // Out: Point specified.
- &dBrainZ); // Out: Point specified.
- // Make absolute by adding dude's position to relative position.
- dBrainX += m_dX;
- dBrainY += m_dY;
- dBrainZ += m_dZ;
- // Create blood chunks.
- short i;
- for (i = 0; i < BRAIN_SPLAT_NUM_CHUNKS; i++)
- {
- // Create blood particles . . .
- CChunk* pchunk = NULL; // Initialized for safety.
- // Note that this will fail if particles are disabled.
- if (CThing::Construct(CChunkID, m_pRealm, (CThing**)&pchunk) == 0)
- {
- pchunk->Setup(
- dBrainX, // Source position.
- dBrainY, // Source position.
- dBrainZ, // Source position.
- m_dRot - 180, // Angle of velocity.
- BRAIN_SPLAT_SWAY, // Angle sway.
- 40, // Velocity (X/Z plane).
- 80, // Velocity (X/Z plane) sway.
- 50, // Velocity (Vertical).
- 100, // Velocity (Vertical) sway.
- CChunk::Blood); // Type of chunk.
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Determines if supplied position is valid tweaking it if necessary.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- bool CDude::MakeValidPosition( // Returns true, if new position was valid.
- // Returns false, if could not reach new position.
- double* pdNewX, // In: x position to validate.
- // Out: New x position.
- double* pdNewY, // In: y position to validate.
- // Out: New y position.
- double* pdNewZ, // In: z position to validate.
- // Out: New z position.
- short sVertTolerance /*= 0*/) // Vertical tolerance.
- {
- bool bValidatedPosition = false; // Assume failure.
- double dCrawlerNewX;
- double dCrawlerNewY;
- double dCrawlerNewZ;
- short sTerrainH;
- // Make sure the position has not changed since our crawlage.
- ASSERT(m_dX == m_dLastCrawledToPosX);
- ASSERT(m_dZ == m_dLastCrawledToPosZ);
- // Restore invalid movements to last good crawl position.
- // The crawler cannot keep us out of things unless it is the only
- // thing responsible for the movement.
- if (m_dX != m_dLastCrawledToPosX)
- m_dX = m_dLastCrawledToPosX;
- if (m_dZ != m_dLastCrawledToPosZ)
- m_dZ = m_dLastCrawledToPosZ;
- // Ask crawler for valid position as close as possible to new position
- if (m_crawler.Move( // Returns 0 if successfull, non-zero otherwise
- m_dX, // In: Position #1 xcoord
- m_dY, // In: Position #1 ycoord
- m_dZ, // In: Position #1 zcoord
- *pdNewX, // In: Position #2 xcoord
- *pdNewY, // In: Position #2 ycoord
- *pdNewZ, // In: Position #2 zcoord
- &dCrawlerNewX, // Out: Final position xcoord
- &dCrawlerNewY, // Out: Final position ycoord
- &dCrawlerNewZ, // Out: Final position zcoord
- &sTerrainH) // Out: Terrain height at new location
- == 0)
- {
- // Success.
- bValidatedPosition = true;
- *pdNewX = dCrawlerNewX;
- *pdNewY = dCrawlerNewY;
- *pdNewZ = dCrawlerNewZ;
- // Stored crawled to position on X/Z plane.
- m_dLastCrawledToPosX = dCrawlerNewX;
- m_dLastCrawledToPosZ = dCrawlerNewZ;
- // If we're gonna be at or below ground level . . .
- if (sTerrainH >= *pdNewY)
- {
- // Get outta there!
- *pdNewY = sTerrainH;
- // Update vertical delta.
- m_dExtVertDeltaVel += -m_dExtVertVel;
- // Reset vertical velocity.
- m_dExtVertVel = 0.0;
-
- m_bAboveTerrain = false;
- }
- else
- {
- m_bAboveTerrain = true;
- }
- }
- else
- {
- // Failure. Homer, I can't seem to move under my own power.
- m_dVel = 0.0;
- m_dAcc = 0.0;
- m_dDrag = 0.0;
- }
- return bValidatedPosition;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Message handlers.
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- // Handles a msg_Shot.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnShotMsg( // Returns nothing.
- Shot_Message* pshotmsg) // In: Message to handle.
- {
- // Remember if already dead . . .
- bool bDead = m_bDead;
- if (StatsAreAllowed)
- {
- Stat_HitsTaken++;
- if (Stat_HitsTaken >= 10000)
- UnlockAchievement(ACHIEVEMENT_TAKE_10000_HITS);
- }
- // Give the msg to CThing3d before we alter it.
- CThing3d::OnShotMsg(pshotmsg);
- short sInitKevlarLayers = m_stockpile.m_sKevlarLayers;
- if (m_stockpile.m_sKevlarLayers > 0)
- {
- pshotmsg->sDamage /= m_stockpile.m_sKevlarLayers * KEVLAR_PROTECTION_MULTIPLIER;
- // Choclate melts vest.
- m_stockpile.m_sKevlarLayers = MAX((short)(m_stockpile.m_sKevlarLayers - (GetRand() & 0x3)), (short)0);
- }
- CCharacter::OnShotMsg(pshotmsg);
- // If we're taking damage . . .
- if (pshotmsg->sDamage > 0)
- {
- Damage(pshotmsg->sDamage, pshotmsg->u16ShooterID);
- // Check for mininum duration since last shot time . . .
- if ( m_pRealm->m_time.GetGameTime() > m_lLastShotTime + MIN_CANNOT_BE_SHOT_DURATION
- || m_state == State_Stand)
- {
- if (SetState(State_Shot) == true)
- {
- m_lLastShotTime = m_pRealm->m_time.GetGameTime();
- }
- }
- }
- // If we have protection . . .
- if (sInitKevlarLayers > 0)
- {
- // Audible and visual feedback.
- PlaySample(g_smidBulletIntoVest, SampleMaster::Weapon);
- double dHitY = m_dY + m_sprite.m_sRadius + RAND_SWAY(VEST_HIT_SWAY);
- // X/Z position depends on angle of shot (it is opposite).
- short sDeflectionAngle = rspMod360(pshotmsg->sAngle + 180);
- double dHitX = m_dX + COSQ[sDeflectionAngle] * TORSO_RADIUS;
- double dHitZ = m_dZ - SINQ[sDeflectionAngle] * TORSO_RADIUS;
- StartAnim(VEST_HIT_RES_NAME, dHitX, dHitY, dHitZ, false);
- // Create a kevlar peice.
- CChunk* pchunk = NULL; // Initialized for safety.
- // Note that this will fail if particles are disabled.
- if (CThing::Construct(CChunkID, m_pRealm, (CThing**)&pchunk) == 0)
- {
- pchunk->Setup(
- dHitX, // Source position.
- dHitY, // Source position.
- dHitZ, // Source position.
- sDeflectionAngle, // Angle of velocity.
- 0, // Angle sway.
- 40, // Velocity (X/Z plane).
- 80, // Velocity (X/Z plane) sway.
- 50, // Velocity (Vertical).
- 100, // Velocity (Vertical) sway.
- CChunk::Kevlar); // Type of chunk.
- }
- }
-
- // If still alive . . .
- if (m_bDead == false)
- {
- if (m_pRealm->m_time.GetGameTime() > m_lLastYellTime + MIN_BETWEEN_YELLS)
- {
- // If we took damage . . .
- if (pshotmsg->sDamage > 0)
- {
- PlaySample(g_smidBlownupYell, SampleMaster::Voices);
- m_lLastYellTime = m_pRealm->m_time.GetGameTime();
- }
- }
- }
- else
- {
- // If not previously dead or dying . . .
- if (bDead == false && m_state != State_Die)
- {
- // Ahhhhhhhhhh....
- PlaySample(g_smidDyingYell, SampleMaster::Voices);
- m_lLastYellTime = m_pRealm->m_time.GetGameTime();
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Handles an Explosion_Message.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnExplosionMsg( // Returns nothing.
- Explosion_Message* pexplosionmsg) // In: Message to handle.
- {
- // Remember if already dead . . .
- bool bDead = m_bDead;
- CCharacter::OnExplosionMsg(pexplosionmsg);
- if (SetState(State_BlownUp) == true)
- {
- // Let's increase his vertical just a bit.
- m_dExtVertVel *= EXPLOSION_VERTICAL_VEL_MULTIPLIER;
- Damage(pexplosionmsg->sDamage, pexplosionmsg->u16ShooterID);
- // If he is carying a flag item, then he should drop it and
- // pass the explosion message on to the flags so they can react.
- DropAllFlags( (GameMessage*)pexplosionmsg);
- // If still alive . . .
- if (m_bDead == false)
- {
- if (m_pRealm->m_time.GetGameTime() > m_lLastYellTime + MIN_BETWEEN_YELLS)
- {
- PlaySample(g_smidBlownupYell, SampleMaster::Voices);
- m_lLastYellTime = m_pRealm->m_time.GetGameTime();
- }
- }
- else
- {
- // If not previously dead . . .
- if (bDead == false)
- {
- // Ahhhhhhhhhh....
- PlaySample(g_smidDyingYell, SampleMaster::Voices);
- m_lLastYellTime = m_pRealm->m_time.GetGameTime();
- }
- }
- }
- m_lLastShotTime = m_pRealm->m_time.GetGameTime();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Handles a Burn_Message.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnBurnMsg( // Returns nothing.
- Burn_Message* pburnmsg) // In: Message to handle.
- {
- if (SetState(State_Burning) == true)
- {
- CCharacter::OnBurnMsg(pburnmsg);
-
- PlaySample(g_smidBurningMainGuy, SampleMaster::Voices);
-
- // If he is carying a flag item, then he should drop them.
- DropAllFlags( (GameMessage*)pburnmsg);
- }
- short sDamage = MAX((short) 1, (short) ((double) pburnmsg->sDamage * (((double) m_pRealm->m_flags.sDifficulty) / 10.0)));
- Damage(sDamage, pburnmsg->u16ShooterID);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Handles a PutMeDown_Message
- // (virtual)
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnPutMeDownMsg( // Returns nothing
- PutMeDown_Message* pputmedownmsg)
- {
- // If he is carrying the flag item, then he should put it down
- if (pputmedownmsg->u16FlagInstanceID != CIdBank::IdNil)
- {
- // Detatch child and update its position
- CThing3d* pthing3d = DetachChild(
- &(pputmedownmsg->u16FlagInstanceID),
- ((CDudeAnim3D*) m_panimCur)->m_ptransLeft->GetAtTime(m_lAnimTime) );
- if (pthing3d)
- {
- pthing3d->m_dX = m_dX;
- pthing3d->m_dY = m_dY;
- pthing3d->m_dZ = m_dZ;
- pthing3d->m_state = State_Die;
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Handles an ObjectDelete_Message.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnDeleteMsg( // Returns nothing.
- ObjectDelete_Message* pdeletemsg) // In: Message to handle.
- {
- CCharacter::OnDeleteMsg(pdeletemsg);
- SetState(State_Delete);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Handles a Suicide_Message.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnSuicideMsg( // Returns nothing.
- Suicide_Message* psuicidemsg) // In: Message to handle.
- {
- CCharacter::OnSuicideMsg(psuicidemsg);
- SetState(State_Suicide);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implements basic functionality while being blown up and returns true
- // until the state is completed.
- // (virtual).
- ////////////////////////////////////////////////////////////////////////////////
- bool CDude::WhileBlownUp(void) // Returns true until state is complete.
- {
- bool bStatePersists = true; // Assume not done.
- double dNewX, dNewY, dNewZ;
- // Get time from last call in seconds.
- long lCurTime = m_pRealm->m_time.GetGameTime();
- double dSeconds = double(lCurTime - m_lPrevTime) / 1000.0;
- // Update Velocities ////////////////////////////////////////////////////////
- UpdateVelocities(dSeconds, ms_dMaxVelForeFast, ms_dMaxVelBackFast);
-
- // Get New Position /////////////////////////////////////////////////////////
- GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
- // Validate New Position ////////////////////////////////////////////////////
- if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, MaxStepUpThreshold) == true)
- {
- // Update Values /////////////////////////////////////////////////////////
- m_dX = dNewX;
- m_dY = dNewY;
- m_dZ = dNewZ;
- UpdateFirePosition();
- }
- else
- {
- // Restore Values ////////////////////////////////////////////////////////
-
- // Didn't actually move and, therefore, did not actually accelerate.
- // Restore velocities.
- // m_dVel -= m_dDeltaVel;
- // m_dExtHorzVel -= m_dExtHorzDeltaVel;
- m_dExtVertVel -= m_dExtVertDeltaVel;
- }
- // If it was above the ground last time and is now below the ground, it must have
- // hit the ground and the blown up state is complete
- if (m_bAboveTerrain == false)
- {
- // If not yet triggered . . .
- if (m_bGenericEvent1 == false)
- {
- PlaySample(g_smidBodyImpact2, SampleMaster::Unspecified);
- m_bGenericEvent1 = true;
- }
- // Make sure its done with current animation also
- if (m_lAnimTime > m_panimCur->m_psops->TotalTime())
- {
- bStatePersists = false;
- }
- }
- return bStatePersists;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Execute the nearest writhing guy, if any.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::OnExecute(void) // Returns nothing.
- {
- // Update execution point via link point.
- double dMuzzleX, dMuzzleY, dMuzzleZ;
- GetLinkPoint( // Returns nothing.
- m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime), // In: Transform specifying point.
- &dMuzzleX, // Out: Point speicfied.
- &dMuzzleY, // Out: Point speicfied.
- &dMuzzleZ); // Out: Point speicfied.
- // Get current weapon and stockpile.
- short* psNumLeft;
- ClassIDType idWeapon;
- GetWeaponInfo(SemiAutomatic, &idWeapon, &psNumLeft);
- if (*psNumLeft > 0)
- {
- // Muzzle flare and sound feedback.
- m_bullets.Flare(
- m_dRot,
- m_dX + dMuzzleX,
- m_dY + dMuzzleY,
- m_dZ + dMuzzleZ,
- m_pRealm);
- // Shoot this thing.
- GameMessage msg;
- msg.msg_Shot.eType = typeShot;
- msg.msg_Shot.sPriority = 0;
- msg.msg_Shot.sAngle = m_dRot;
- msg.msg_Shot.u16ShooterID = m_u16InstanceId;
- msg.msg_Shot.sDamage = 10;
- // Send it the message.
- SendThingMessage(&msg, m_idVictim);
- // Note time of next fire.
- m_lNextBulletTime = m_pRealm->m_time.GetGameTime() + MS_BETWEEN_BULLETS;
- // Deduct a shot.
- *psNumLeft = *psNumLeft - 1;
- }
- else
- {
- // Feedback.
- PlaySample(g_smidOutOfBullets, SampleMaster::Weapon);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implements one-time functionality for when a weapon is destroyed while
- // we were moving it (i.e., before we let go or ShootWeapon()'ed it).
- // This can occur when a weapon, while traveling along our rigid body,
- // enters terrain.
- ////////////////////////////////////////////////////////////////////////////////
- // virtual (overridden here).
- void CDude::OnWeaponDestroyed(void)
- {
- // Feedback that we aborted. Perhaps different by state?
- PlaySample(g_smidGeneralBeep, SampleMaster::UserFeedBack);
- // Finish.
- switch (m_state)
- {
- case State_Throw:
- case State_ThrowRelease:
- case State_ThrowFinish:
- SetState(State_ThrowDone);
- break;
- case State_Launch:
- case State_LaunchRelease:
- case State_LaunchFinish:
- SetState(State_LaunchDone);
- break;
- default:
- // Be done with our state.
- SetState(State_Persistent);
- break;
- }
-
- m_weaponShooting = NoWeapon;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Revive a dead dude. This is a more graceful way than just setting
- // his state. This will restore stockpile and make him animate out of
- // a warp point.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::Revive( // Returns nothing.
- bool bWarpIn /*= true*/) // In: true, to warp in, false to just get up.
- {
- // Must be dead, lying there still in multiplayer mode (or we could be cheating) . . .
- if ( m_bDead == true
- && (m_pRealm->m_flags.bMultiplayer == true || bWarpIn == false) )
- {
- // Drop that fire.
- m_u16IdFire = CIdBank::IdNil;
- // Let's not be responding to old news.
- m_MessageQueue.Empty();
- // Create powerup . . .
- // NOTE that if the dude is going to be warped in (that is, he is going to get
- // reloaded with stuff from the warp), he only drops his current weapon and all
- // his ammo. If he is not going to be warped in (that is, he will NOT get
- // any stuff from a warp), he drops all his stuff so he can pick it back up.
- DropPowerUp(&m_stockpile, bWarpIn);
- // Clear my stockpile.
- m_stockpile.Zero();
- // Have a life.
- m_stockpile.m_sHitPoints = m_sOrigHitPoints;
- m_smash.m_bits &= ~CSmash::Dead;
- m_bDead = false;
- m_sBrightness = 0;
- CDude* pdude = this;
- if (bWarpIn == true)
- {
- // It would be best if this only occurred when we're in the dead state
- // and, hence, on the proper animation.
- // This should flag us to other situations.
- ASSERT(m_state == State_Dead);
- // Render current dead frame into background to stay.
- m_pRealm->m_scene.DeadRender3D(
- m_pRealm->m_phood->m_pimBackground, // Destination image.
- &m_sprite, // Tree of 3D sprites to render.
- m_pRealm->m_phood); // Dst clip rect.
- // First try to find a warp in point . . .
- if (CWarp::WarpInAnywhere(
- m_pRealm,
- &pdude,
- CWarp::CopyStockPile) == 0)
- {
- // Force to base weapon
- SetWeapon(SemiAutomatic, true);
- NextWeapon();
- // Run on screen or out of building or whatever.
- SetState(State_Run);
- m_dVel = ms_dMaxVelForeFast;
- }
- else
- {
- // Just get up, you rogue.
- SetState(State_GetUp);
- }
- }
- else
- {
- // Just get up, you rogue.
- SetState(State_GetUp);
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // ShowTarget - If the targeting aid is turned on, then this will put the
- // targeting sprite on the target.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::ShowTarget()
- {
- if (m_bTargetingHelpEnabled && m_bDead == false)
- {
- // sAngle must be between 0 and 359.
- short sRotY = rspMod360((short) m_dRot);
- short sRangeXZ = 100;
- short sRadius = 20;
- float fRateX = COSQ[sRotY] * sRangeXZ;
- float fRateZ = -SINQ[sRotY] * sRangeXZ;
- float fRateY = 0.0; // If we ever want vertical movement . . .
- // Set initial position to first point to check (NEVER checks original position).
- float fPosX = m_dX + fRateX;
- float fPosY = m_dY + fRateY;
- float fPosZ = m_dZ + fRateZ;
- if (m_TargetSprite.m_psprParent)
- m_TargetSprite.m_psprParent->RemoveChild(&m_TargetSprite);
- ((CThing3d*)this)->m_sprite.AddChild(&m_TargetSprite);
- // Map from 3d to 2d coords
- Map3Dto2D(
- fRateX - m_sprite.m_sRadius / 2,
- m_sprite.m_sRadius * 2,
- fRateZ,
- &m_TargetSprite.m_sX2,
- &m_TargetSprite.m_sY2);
- m_TargetSprite.m_sInFlags &= ~CSprite::InHidden;
- m_TargetSprite.m_sLayer = CRealm::LayerSprite16;
- }
- else
- m_TargetSprite.m_sInFlags |= CSprite::InHidden;
- }
- /*
- void CDude::ShowTarget(void)
- {
- if (m_bTargetingHelpEnabled && m_bDead == false)
- {
- CThing* pTargetThing = NULL;
- if (IlluminateTarget((short) m_dX,
- (short) m_dY,
- (short) m_dZ,
- (short) m_dRot,
- 300,
- 20,
- CSmash::Character,
- CSmash::Good | CSmash::Bad,
- 0,
- &pTargetThing,
- &m_smash))
- {
- if (m_TargetSprite.m_psprParent)
- m_TargetSprite.m_psprParent->RemoveChild(&m_TargetSprite);
- ((CThing3d*) pTargetThing)->m_sprite.AddChild(&m_TargetSprite);
- // Map from 3d to 2d coords
- Map3Dto2D(
- (short) 0,
- (short) 30,
- (short) 0,
- &m_TargetSprite.m_sX2,
- &m_TargetSprite.m_sY2);
- m_TargetSprite.m_sInFlags &= ~CSprite::InHidden;
- }
- else
- {
- m_TargetSprite.m_sInFlags |= CSprite::InHidden;
- }
- }
- else
- m_TargetSprite.m_sInFlags |= CSprite::InHidden;
- }
- */
- ////////////////////////////////////////////////////////////////////////////////
- // Next weapon please.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::NextWeapon(void)
- {
- short sNumTried = 0;
- short sCurWeapon = m_weapontypeCur;
- while (sNumTried < NumWeaponTypes)
- {
- sNumTried++;
- sCurWeapon++;
- if (sCurWeapon == NumWeaponTypes)
- {
- sCurWeapon = NoWeapon + 1;
- }
- if (SetWeapon((WeaponType)sCurWeapon, false) == true)
- {
- break;
- }
- }
- if (sNumTried == NumWeaponTypes)
- {
- SetWeapon(NoWeapon, false);
- }
- PlaySample(g_smidLoadedWeapon, SampleMaster::UserFeedBack);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Previous weapon please.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::PrevWeapon(void)
- {
- short sNumTried = 0;
- short sCurWeapon = m_weapontypeCur;
- while (sNumTried < NumWeaponTypes)
- {
- sNumTried++;
- sCurWeapon--;
- if (sCurWeapon == NoWeapon)
- {
- sCurWeapon = NumWeaponTypes - 1;
- }
- if (SetWeapon((WeaponType)sCurWeapon, false) == true)
- {
- break;
- }
- }
- if (sNumTried == NumWeaponTypes)
- {
- SetWeapon(NoWeapon, false);
- }
- PlaySample(g_smidLoadedWeapon, SampleMaster::UserFeedBack);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Set the current weapon.
- ////////////////////////////////////////////////////////////////////////////////
- bool CDude::SetWeapon( // Returns true if weapon could be set as current.
- WeaponType weapon, // In: New weapon to attempt to make the current.
- bool bSetIfNoAmmo /*= true*/) // In: true to set weapon (even if no ammo).
- {
- bool bSetWeapon = true; // Assume we could set the weapon.
- switch (weapon)
- {
- case NoWeapon:
- break;
- case SemiAutomatic:
- if (m_stockpile.m_sMachineGun == 0)
- {
- bSetWeapon = false;
- }
- break;
- case Grenade:
- break;
- case FireBomb:
- break;
- case Rocket:
- if (m_stockpile.m_sMissileLauncher == 0)
- {
- bSetWeapon = false;
- }
- break;
- case Napalm:
- if (m_stockpile.m_sNapalmLauncher == 0)
- {
- bSetWeapon = false;
- }
- break;
- case ShotGun:
- if (m_stockpile.m_sShotGun == 0)
- {
- bSetWeapon = false;
- }
- break;
- case SprayCannon:
- if (m_stockpile.m_sSprayCannon == 0)
- {
- bSetWeapon = false;
- }
- break;
- case FlameThrower:
- if (m_stockpile.m_sFlameThrower == 0)
- {
- bSetWeapon = false;
- }
- break;
- case BouncingBettyMine:
- case ProximityMine:
- case TimedMine:
- // case RemoteMine: //Fixed crash when changing weapons and firing at the same time
- break;
- case Heatseeker:
- if (m_stockpile.m_sMissileLauncher == 0)
- {
- bSetWeapon = false;
- }
- break;
- case DeathWad:
- if (m_stockpile.m_sDeathWadLauncher == 0)
- {
- bSetWeapon = false;
- }
- break;
- case DoubleBarrel:
- if (m_stockpile.m_sDoubleBarrel == 0)
- {
- bSetWeapon = false;
- }
- break;
- default:
- bSetWeapon = false;
- break;
- }
- // Get info on this weapon.
- ClassIDType idDummy;
- short* psNum;
- GetWeaponInfo(weapon, &idDummy, &psNum);
- // If weapon was available . . .
- if (bSetWeapon == true)
- {
- // If we have no ammo for this one . . .
- if (*psNum <= 0)
- {
- // If set we cannot set when no ammo . . .
- if (bSetIfNoAmmo == false)
- {
- bSetWeapon = false;
- }
- else
- {
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- }
- }
- else
- {
- if (bSetIfNoAmmo == true)
- {
- PlaySample(g_smidLoadedWeapon, SampleMaster::UserFeedBack);
- }
- }
- // If able to change weapons . . .
- if (bSetWeapon == true)
- {
- // Set new weapon.
- m_weapontypeCur = weapon;
- // If we have ammo . . .
- if (*psNum > 0)
- {
- GameMessage msg;
- msg.msg_WeaponSelect.eType = typeWeaponSelect;
- msg.msg_WeaponSelect.sPriority = 0;
- msg.msg_WeaponSelect.sWeapon = (short) m_weapontypeCur;
- CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
- if (pDemon)
- SendThingMessage(&msg, pDemon);
- }
- }
- }
- else
- {
- if (bSetIfNoAmmo == true)
- {
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- }
- }
-
- return bSetWeapon;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Drop a powerup with the settings described by the specified stockpile.
- ////////////////////////////////////////////////////////////////////////////////
- CPowerUp* CDude::DropPowerUp( // Returns new powerup on success; NULL on failure.
- CStockPile* pstockpile, // In: Settings for powerup.
- bool bCurWeaponOnly) // In: true, if only the current weapon should be
- // in the powerup; false, if all.
- {
- CPowerUp* ppowerup = NULL;
- // If not empty . . .
- if (pstockpile->IsEmpty() == false)
- {
- // Create powerup . . .
- if (ConstructWithID(CPowerUpID, m_pRealm, (CThing**)&ppowerup) == 0)
- {
- // Put stockpile into powerup.
- ppowerup->m_stockpile.Copy(pstockpile);
- if (bCurWeaponOnly)
- {
- // Note whether we had the weapon. Not sure how it would be possible
- // but just in case we can somehow have a weapon selected that we do
- // hot have.
- short sHasWeapon = ppowerup->m_stockpile.GetWeapon(m_weapontypeCur);
- // Remove all but our current weapon.
- short sIndex;
- for (sIndex = SemiAutomatic; sIndex <= DoubleBarrel; sIndex++)
- {
- // Zero.
- ppowerup->m_stockpile.GetWeapon(sIndex) = 0;
- }
- // Add back our currently selected weapon.
- ppowerup->m_stockpile.GetWeapon(m_weapontypeCur) = sHasWeapon;
- }
- // Place powerup at our feet.
- ppowerup->Setup(m_dX, m_dY, m_dZ);
- }
- }
- return ppowerup;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Play a step noise if the event is different from the last.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::PlayStep(void) // Returns nothing.
- {
- #if 1
- // If there is an event channel . . .
- if (m_panimCur->m_pevent != NULL)
- {
- // If the current event is different from the last . . .
- U8 u8Event = *((U8*)(m_panimCur->m_pevent->GetAtTime(m_lAnimTime)) );
- if (u8Event > 0 && u8Event != m_u8LastEvent)
- {
- PlaySample(g_smidStep, SampleMaster::Unspecified);
- m_u8LastEvent = u8Event;
- }
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Find someone to execute.
- ////////////////////////////////////////////////////////////////////////////////
- bool CDude::FindExecutee(void) // Returns true, if we found one; false, otherwise.
- {
- bool bFoundOne = false; // Assume not found.
- CSmash* psmashee = NULL; // Safety.
- // Find the closest person including writhers.
- if (m_pRealm->m_smashatorium.QuickCheckClosest(
- &m_smash, // In: CSmash to check
- /* CSmash::Character
- | CSmash::Misc
- | CSmash::Barrel
- | CSmash::Mine
- | */CSmash::AlmostDead, // In: Bits we can hit.
- 0, // In: Bits that you don't care about
- 0, // In: Bits that must be 0 to collide with a given CSmash
- &psmashee) == true)
- {
- // We can handle anyone that wants to reveal their location . . .
- // This can be done via the GetX/Y/Z() functions or their smash . . .
- if ( (psmashee->m_pThing->GetX() != CThing::InvalidPosition
- && psmashee->m_pThing->GetY() != CThing::InvalidPosition
- && psmashee->m_pThing->GetZ() != CThing::InvalidPosition)
- || psmashee->m_pThing->GetSprite() )
- {
- // Found one.
- bFoundOne = true;
- // Remember who.
- m_idVictim = psmashee->m_pThing->GetInstanceID();
- }
- }
- return bFoundOne;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Track executee.
- ////////////////////////////////////////////////////////////////////////////////
- bool CDude::TrackExecutee( // Returns true to persist, false, if we lost the target.
- double dSeconds) // In: Seconds since last iteration.
- {
- bool bPersist = true; // Assume we'll persist.
-
- // Get pointer to target.
- CThing* pthing;
- if (m_pRealm->m_idbank.GetThingByID(&pthing, m_idVictim) == 0)
- {
- double dVictimX;
- double dVictimZ;
- // Try to use smash position first, then resort to thing position.
- CSmash* psmash = pthing->GetSmash();
- if (psmash != NULL)
- {
- // This is generally more accurate for an execution point.
- dVictimX = psmash->m_sphere.sphere.X;
- dVictimZ = psmash->m_sphere.sphere.Z;
- }
- else
- {
- // This'll do though.
- dVictimX = pthing->GetX();
- dVictimZ = pthing->GetZ();
- }
- short sDistX = dVictimX - m_dX;
- short sDistZ = m_dZ - dVictimZ;
- double dSqrDistanceXZ = ABS2(sDistX, sDistZ);
- // Determine angle to target.
- double dRot = rspATan(sDistZ, sDistX);
- // Determine which rotation direction to target is smaller.
- double dDelta = rspDegDelta(m_dRot, dRot);
- // If turning counter clockwise . . .
- if (dDelta > 0.0)
- {
- m_dRot += MIN(dDelta, g_InputSettings.m_dStillFastDegreesPerSec * dSeconds);
- }
- else
- {
- m_dRot += MAX(dDelta, -g_InputSettings.m_dStillFastDegreesPerSec * dSeconds);
- }
- #if 1
- // If too close . . .
- if (dSqrDistanceXZ < MIN_SQR_DISTANCE_TO_EXECUTEE)
- {
- // Back up.
- m_dVel = dSqrDistanceXZ - MIN_SQR_DISTANCE_TO_EXECUTEE;
- }
- #else
- // Another solution, if we don't like the above, is to take
- // the gun and use a transform we create (rather than the
- // rigid body one) and aim the gun directly at the target
- // point.
- #endif
- }
- else
- {
- // Lost our target. Continuing is futile.
- m_idVictim = CIdBank::IdNil;
- bPersist = false;
- }
- return bPersist;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Take a powerup.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::TakePowerUp( // Returns nothing.
- CPowerUp** pppowerup) // In: Power up to take from.
- // Out: Ptr to powerup, if it persisted; NULL otherwise.
- {
- CStockPile* pspMax;
- // Note if we do or will have the backpack.
- if (m_stockpile.m_sBackpack || (*pppowerup)->m_stockpile.m_sBackpack)
- {
- pspMax = &CStockPile::ms_stockpileBackPackMax;
- }
- else
- {
- pspMax = &CStockPile::ms_stockpileMax;
- }
- // Create a stockpile of the amount we can take from the powerup.
- CStockPile spTake;
- spTake.Copy(pspMax);
- spTake.Sub(&m_stockpile);
- // Intersect the amount we can take with the amount available.
- spTake.Intersect( &( (*pppowerup)->m_stockpile) );
- // If we got anything . . .
- if (spTake.IsEmpty() == false)
- {
- // Cash it in.
- m_stockpile.Add( &spTake );
- // If in MP mode, empty the powerup so it goes away. Otherwise, just remove what we took
- if (m_pRealm->m_flags.bMultiplayer)
- (*pppowerup)->m_stockpile.Zero();
- else
- (*pppowerup)->m_stockpile.Sub( &spTake );
- // Play feedback.
- (*pppowerup)->PickUpFeedback();
- // Store its ID so we can attempt to get it if it does persist.
- U16 idInstance = (*pppowerup)->GetInstanceID();
- // Let powerup decide if it should persist.
- (*pppowerup)->RepaginateNow();
- // If it persisted . . .
- if (m_pRealm->m_idbank.GetThingByID((CThing**)pppowerup, idInstance) == 0)
- {
- ASSERT( (*pppowerup)->GetClassID() == CPowerUpID);
- }
- else
- {
- *pppowerup = NULL;
- }
- }
- else
- {
- // Temp feedback for needed nothing from the weapon.
- PlaySample(g_smidOutOfBullets, SampleMaster::UserFeedBack);
- // If in MP mode, eat the powerup
- if (m_pRealm->m_flags.bMultiplayer)
- {
- (*pppowerup)->m_stockpile.Zero();
- (*pppowerup)->RepaginateNow();
- *pppowerup = NULL;
- }
- }
- // If it still exists . . .
- if (*pppowerup)
- {
- // Store its ID so we can attempt to get it if it does persist.
- U16 idInstance = (*pppowerup)->GetInstanceID();
- // Toss it.
- TossPowerUp(*pppowerup, 130);
- // If it persisted . . .
- if (m_pRealm->m_idbank.GetThingByID((CThing**)pppowerup, idInstance) == 0)
- {
- ASSERT( (*pppowerup)->GetClassID() == CPowerUpID);
- }
- else
- {
- *pppowerup = NULL;
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Create a cheat powerup.
- ////////////////////////////////////////////////////////////////////////////////
- CPowerUp* CDude::CreateCheat( // Returns new powerup on success; NULL on failure.
- CStockPile* pstockpile) // In: Settings for powerup.
- {
- // First deduct from the cheat powerup what we cannot use.
- CStockPile spUsable;
- spUsable.Copy( m_stockpile.m_sBackpack ? &CStockPile::ms_stockpileBackPackMax : &CStockPile::ms_stockpileMax );
- spUsable.Sub( &m_stockpile );
- // Intersect with the supplied.
- spUsable.Intersect(pstockpile);
- // Finally, drop it.
- // If it contains anything . . .
- CPowerUp* ppowerup;
- if (spUsable.IsEmpty() == false)
- {
- ppowerup = DropPowerUp( &spUsable, false );
- if (ppowerup)
- {
- // Take it right away.
- TakePowerUp(&ppowerup);
- }
- }
- else
- {
- ppowerup = NULL;
- }
- UnlockAchievement(ACHIEVEMENT_ENABLE_CHEATS);
- Flag_Achievements |= FLAG_USED_CHEATS;
- // Let the demon know.that they are cheating
- GameMessage msg;
- msg.msg_Cheater.eType = typeCheater;
- msg.msg_Cheater.sPriority = 0;
- CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
- if (pDemon)
- SendThingMessage(&msg, pDemon);
- return ppowerup;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Break a powerup open and toss it.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::TossPowerUp( // Returns nothing.
- CPowerUp* ppowerup, // In: Powerup to toss.
- short sVelocity) // In: Velocity of toss.
- {
- // Blow it up.
- GameMessage msg;
- msg.msg_Explosion.eType = typeExplosion;
- msg.msg_Explosion.sPriority = 0;
- msg.msg_Explosion.sDamage = 0;
- msg.msg_Explosion.sX = m_dX;
- msg.msg_Explosion.sY = m_dY;
- msg.msg_Explosion.sZ = m_dZ;
- msg.msg_Explosion.sVelocity = sVelocity;
- msg.msg_Explosion.u16ShooterID = GetInstanceID();
- SendThingMessage(&msg, msg.msg_Explosion.sPriority, ppowerup);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Get the current weapon the dude has ready to use.
- ////////////////////////////////////////////////////////////////////////////////
- CDude::WeaponType CDude::GetCurrentWeapon(void)
- {
- return m_weapontypeCur;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Sets the dude's position. It is very important that the dude is not
- // moved by outside things, other than the warp.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::SetPosition( // Returns nothing.
- double dX, // In: New position for dude.
- double dY, // In: New position for dude.
- double dZ) // In: New position for dude.
- {
- // Set position and update crawler position.
- m_dLastCrawledToPosX = m_dX = dX;
- m_dY = dY;
- m_dLastCrawledToPosZ = m_dZ = dZ;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Get the next child flag item after the specified flag item.
- ////////////////////////////////////////////////////////////////////////////////
- CFlag* CDude::GetNextFlag( // Returns the next flag item after pflag.
- CFlag* pflag) // In: The flag to get the follower of.
- // NULL for first child flag.
- {
- CFlag* pflagNext = NULL;
- CSprite* psprite = pflag ? pflag->m_sprite.m_psprNext : m_sprite.m_psprHeadChild;
- while (psprite && pflagNext == NULL)
- {
- // If this sprite names its owner . . .
- CThing* pthing = psprite->m_pthing;
- if (pthing)
- {
- // If it is a flag . . .
- if (pthing->GetClassID() == CFlagID)
- {
- pflagNext = (CFlag*)pthing;
- }
- }
- // Next Please.
- psprite = psprite->m_psprNext;
- }
- return pflagNext;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Drop all child flag items.
- ////////////////////////////////////////////////////////////////////////////////
- void CDude::DropAllFlags( // Returns nothing.
- GameMessage* pmsg) // In: Message to pass to flags.
- {
- GameMessage msg;
-
- // If no message specified . . .
- if (pmsg == NULL)
- {
- msg.msg_Explosion.eType = typeExplosion;
- msg.msg_Explosion.sPriority = 0;
- msg.msg_Explosion.sDamage = 10;
- msg.msg_Explosion.sX = (short) m_dX;
- msg.msg_Explosion.sY = (short) m_dY;
- msg.msg_Explosion.sZ = (short) m_dZ;
- msg.msg_Explosion.sVelocity = 30;
- msg.msg_Explosion.u16ShooterID = GetInstanceID();
- pmsg = &msg;
- }
- else
- {
- // If it is an explosion message . . .
- if (pmsg->msg_Generic.eType == typeExplosion)
- {
- // Copy it so we can tweak it.
- msg = *pmsg;
- }
- }
- // Loop through all child flags and send them a message and remove them.
- CFlag* pflag = GetNextFlag(NULL);
- CFlag* pflagNext;
- while (pflag)
- {
- // Get the next now b/c this won't be a sibling after we detach it.
- pflagNext = GetNextFlag(pflag);
- U16 u16IdFlag = pflag->GetInstanceID();
-
- // Detach the flag.
- DetachChild(
- &u16IdFlag,
- ((CDudeAnim3D*) m_panimCur)->m_ptransLeft->GetAtTime(m_lAnimTime) );
- // Move it to our position rather than the transformed position b/c we
- // don't know if that's a valid position but we do know that our position
- // is.
- pflag->m_dX = m_dX;
- pflag->m_dY = m_dY;
- pflag->m_dZ = m_dZ;
- // If it's an explosion . . .
- if (pmsg->msg_Generic.eType == typeExplosion)
- {
- // Tweak the message a little.
- pmsg->msg_Explosion.sX = (short) m_dX + RAND_SWAY(30);
- pmsg->msg_Explosion.sZ = (short) m_dZ + RAND_SWAY(30);
- }
- // Forward the specified message.
- SendThingMessage(
- pmsg,
- pflag);
- // Next please.
- pflag = pflagNext;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // EOF
- ////////////////////////////////////////////////////////////////////////////////
|