12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158 |
- #ifdef PRECOMPILEDHEADERS
- #include "Tactical All.h"
- #else
- #include <wchar.h>
- #include <stdio.h>
- #include <string.h>
- #include "wcheck.h"
- #include "Render Fun.h"
- #include "stdlib.h"
- #include "debug.h"
- #include "MemMan.h"
- #include "Overhead Types.h"
- #include "Soldier Control.h"
- #include "Animation Cache.h"
- #include "Animation Data.h"
- #include "Animation Control.h"
- #include "container.h"
- #include <math.h>
- #include "pathai.h"
- #include "Random.h"
- #include "worldman.h"
- #include "Isometric Utils.h"
- #include "Render Dirty.h"
- #include "renderworld.h"
- #include "sys globals.h"
- #include "video.h"
- #include "points.h"
- #include "Win util.h"
- #include "Sound Control.h"
- #include "weapons.h"
- #include "vobject_blitters.h"
- #include "Handle UI.h"
- #include "soldier ani.h"
- #include "Event pump.h"
- #include "opplist.h"
- #include "ai.h"
- #include "interface.h"
- #include "lighting.h"
- #include "faces.h"
- #include "Soldier Profile.h"
- #include "gap.h"
- #include "interface panels.h"
- #include "campaign.h"
- #include "soldier macros.h"
- #include "english.h"
- #include "Squads.h"
- #ifdef NETWORKED
- #include "Networking.h"
- #include "NetworkEvent.h"
- #endif
- #include "structure wrap.h"
- #include "items.h"
- #include "Soundman.h"
- #include "utilities.h"
- #include "Strategic.h"
- #include "soldier tile.h"
- #include "Smell.h"
- #include "Keys.h"
- #include "dialogue control.h"
- #include "soldier functions.h"
- #include "rt time defines.h"
- #include "Exit Grids.h"
- #include "gamescreen.h"
- #include "Quests.h"
- #include "message.h"
- #include "NPC.h"
- #include "SkillCheck.h"
- #include "handle doors.h"
- #include "interface dialogue.h"
- #include "smokeeffects.h"
- #include "GameSettings.h"
- #include "tile animation.h"
- #include "ShopKeeper Interface.h"
- #include "Arms Dealer Init.h"
- #include "vehicles.h"
- #include "rotting corpses.h"
- #include "Interface Control.h"
- #include "strategicmap.h"
- #include "morale.h"
- #include "meanwhile.h"
- #include "drugs and alcohol.h"
- #include "SkillCheck.h"
- #include "boxing.h"
- #include "overhead map.h"
- #endif
- extern INT16 DirIncrementer[8];
- #define PALETTEFILENAME "BINARYDATA\\ja2pal.dat"
- #define LOW_MORALE_BATTLE_SND_THREASHOLD 35
- #define TURNING_FROM_PRONE_OFF 0
- #define TURNING_FROM_PRONE_ON 1
- #define TURNING_FROM_PRONE_START_UP_FROM_MOVE 2
- #define TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE 3
- #define MIN_SUBSEQUENT_SNDS_DELAY 2000
- // Enumerate extended directions
- enum
- {
- EX_NORTH = 0,
- EX_NORTHEAST = 4,
- EX_EAST = 8,
- EX_SOUTHEAST = 12,
- EX_SOUTH = 16,
- EX_SOUTHWEST = 20,
- EX_WEST = 24,
- EX_NORTHWEST = 28,
- EX_NUM_WORLD_DIRECTIONS = 32,
- EX_DIRECTION_IRRELEVANT
- } ExtendedWorldDirections;
- // LUT for conversion from 8-direction to extended direction
- UINT8 ubExtDirection[] =
- {
- EX_NORTH,
- EX_NORTHEAST,
- EX_EAST,
- EX_SOUTHEAST,
- EX_SOUTH,
- EX_SOUTHWEST,
- EX_WEST,
- EX_NORTHWEST
- };
- UINT8 gExtOneCDirection[ EX_NUM_WORLD_DIRECTIONS ] =
- {
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 14,
- 15,
- 16,
- 17,
- 18,
- 19,
- 20,
- 21,
- 22,
- 23,
- 24,
- 25,
- 26,
- 27,
- 28,
- 29,
- 30,
- 31,
- 0,
- 1,
- 2,
- 3,
- };
- typedef struct
- {
- CHAR8 zName[20];
- UINT8 ubRandomVal;
- BOOLEAN fPreload;
- BOOLEAN fBadGuy;
- BOOLEAN fDontAllowTwoInRow;
- BOOLEAN fStopDialogue;
- } BATTLESNDS_STRUCT;
- BATTLESNDS_STRUCT gBattleSndsData[] =
- {
- "ok1", 2, 1, 1, 1, 2,
- "ok2", 0, 1, 1, 1, 2,
- "cool", 0, 1, 0, 1, 0,
- "curse", 0, 1, 1, 1, 0,
- "hit1", 2, 1, 1, 1, 1,
- "hit2", 0, 1, 1, 1, 1,
- "laugh", 0, 1, 1, 1, 0,
- "attn", 0, 1, 0, 1, 0,
- "dying", 0, 1, 1, 1, 1,
- "humm", 0, 0, 0, 1, 1,
- "noth", 0, 0, 0, 1, 1,
- "gotit", 0, 0, 0, 1, 1,
- "lmok1", 2, 1, 0, 1, 2,
- "lmok2", 0, 1, 0, 1, 2,
- "lmattn", 0, 1, 0, 1, 0,
- "locked", 0, 0, 0, 1, 0,
- "enem", 0, 1, 1, 1, 0,
- };
- BOOLEAN IsValidSecondHandShot( SOLDIERTYPE *pSoldier );
- UINT8 bHealthStrRanges[] =
- {
- 15,
- 30,
- 45,
- 60,
- 75,
- 90,
- 101
- };
- INT16 gsTerrainTypeSpeedModifiers[] =
- {
- 5, // Flat ground
- 5, // Floor
- 5, // Paved road
- 5, // Dirt road
- 10, // LOW GRASS
- 15, // HIGH GRASS
- 20, // TRAIN TRACKS
- 20, // LOW WATER
- 25, // MID WATER
- 30 // DEEP WATER
- };
- //Kris:
- //Temporary for testing the speed of the translucency. Pressing Ctrl+L in turn based
- //input will toggle this flag. When clear, the translucency checking is turned off to
- //increase the speed of the game.
- BOOLEAN gfCalcTranslucency = FALSE;
- INT16 gsFullTileDirections[ MAX_FULLTILE_DIRECTIONS ] =
- {
- -1, -WORLD_COLS - 1, -WORLD_COLS
- };
- // Palette ranges
- UINT32 guiNumPaletteSubRanges;
- PaletteSubRangeType *guipPaletteSubRanges = NULL;
- // Palette replacements
- UINT32 guiNumReplacements;
- PaletteReplacementType *guipPaletteReplacements = NULL;
- extern BOOLEAN fReDrawFace;
- extern UINT8 gubWaitingForAllMercsToExitCode;
- BOOLEAN gfGetNewPathThroughPeople = FALSE;
- // LOCAL FUNCTIONS
- // DO NOT CALL UNLESS THROUGH EVENT_SetSoldierPosition
- UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady );
- BOOLEAN CheckForFullStruct( INT16 sGridNo, UINT16 *pusIndex );
- void SetSoldierLocatorOffsets( SOLDIERTYPE *pSoldier );
- void CheckForFullStructures( SOLDIERTYPE *pSoldier );
- BOOLEAN InitNewSoldierState( SOLDIERTYPE *pSoldier, UINT8 ubNewState, UINT16 usStartingAniCode );
- UINT16 GetNewSoldierStateFromNewStance( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance );
- void SetSoldierAniSpeed( SOLDIERTYPE *pSoldier );
- void AdjustForFastTurnAnimation( SOLDIERTYPE *pSoldier );
- UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight );
- void SelectFallAnimation( SOLDIERTYPE *pSoldier );
- BOOLEAN FullStructAlone( INT16 sGridNo, UINT8 ubRadius );
- void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial , UINT8 ubHitLocation);
- void SoldierGotHitBlade( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation );
- void SoldierGotHitPunch( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation );
- void SoldierGotHitExplosion( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation );
- UINT8 CalcScreamVolume( SOLDIERTYPE * pSoldier, UINT8 ubCombinedLoss );
- void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier );
- void HandleSystemNewAISituation( SOLDIERTYPE *pSoldier, BOOLEAN fResetABC );
- UINT16 *CreateEnemyGlow16BPPPalette( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, BOOLEAN fAdjustGreen );
- UINT16 *CreateEnemyGreyGlow16BPPPalette( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, BOOLEAN fAdjustGreen );
- void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed );
- INT32 CheckBleeding( SOLDIERTYPE *pSoldier );
- void EVENT_InternalSetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT16 usNewDirection, BOOLEAN fInitalMove, UINT16 usAnimState );
- #ifdef JA2BETAVERSION
- extern void ValidatePlayersAreInOneGroupOnly();
- extern void MapScreenDefaultOkBoxCallback( UINT8 bExitValue );
- void SAIReportError( STR16 wErrorString );
- #endif
- UINT32 SleepDartSuccumbChance( SOLDIERTYPE * pSoldier );
- void EnableDisableSoldierLightEffects( BOOLEAN fEnableLights );
- void SetSoldierPersonalLightLevel( SOLDIERTYPE *pSoldier );
- void HandleVehicleMovementSound( SOLDIERTYPE *pSoldier, BOOLEAN fOn )
- {
- VEHICLETYPE *pVehicle = &( pVehicleList[ pSoldier->bVehicleID ] );
- if ( fOn )
- {
- if ( pVehicle->iMovementSoundID == NO_SAMPLE )
- {
- pVehicle->iMovementSoundID = PlayJA2Sample( pVehicle->iMoveSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
- }
- }
- else
- {
- if ( pVehicle->iMovementSoundID != NO_SAMPLE )
- {
- SoundStop( pVehicle->iMovementSoundID );
- pVehicle->iMovementSoundID = NO_SAMPLE;
- }
- }
- }
- void AdjustNoAPToFinishMove( SOLDIERTYPE *pSoldier, BOOLEAN fSet )
- {
- if ( pSoldier->ubBodyType == CROW )
- {
- return;
- }
- // Check if we are a vehicle first....
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- // Turn off sound effects....
- if ( fSet )
- {
- HandleVehicleMovementSound( pSoldier, FALSE );
- }
- }
- // Turn off sound effects....
- if ( fSet )
- {
- // Position light....
- // SetCheckSoldierLightFlag( pSoldier );
- }
- else
- {
- // DeleteSoldierLight( pSoldier );
- }
- pSoldier->fNoAPToFinishMove = fSet;
- if ( !fSet )
- {
- // return reason to default value
- pSoldier->ubReasonCantFinishMove = REASON_STOPPED_NO_APS;
- }
- }
- void HandleCrowShadowVisibility( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->ubBodyType == CROW )
- {
- if ( pSoldier->usAnimState == CROW_FLY )
- {
- if ( pSoldier->pAniTile != NULL )
- {
- if ( pSoldier->bLastRenderVisibleValue != -1 )
- {
- HideAniTile( pSoldier->pAniTile, FALSE );
- }
- else
- {
- HideAniTile( pSoldier->pAniTile, TRUE );
- }
- }
- }
- }
- }
- void HandleCrowShadowNewGridNo( SOLDIERTYPE *pSoldier )
- {
- ANITILE_PARAMS AniParams;
- memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) );
- if ( pSoldier->ubBodyType == CROW )
- {
- if ( pSoldier->pAniTile != NULL )
- {
- DeleteAniTile( pSoldier->pAniTile );
- pSoldier->pAniTile = NULL;
- }
- if ( pSoldier->sGridNo != NOWHERE )
- {
- if ( pSoldier->usAnimState == CROW_FLY )
- {
- AniParams.sGridNo = (INT16)pSoldier->sGridNo;
- AniParams.ubLevelID = ANI_SHADOW_LEVEL;
- AniParams.sDelay = pSoldier->sAniDelay;
- AniParams.sStartFrame = 0;
- AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_LOOPING | ANITILE_USE_DIRECTION_FOR_START_FRAME;
- AniParams.sX = pSoldier->sX;
- AniParams.sY = pSoldier->sY;
- AniParams.sZ = 0;
- strcpy( AniParams.zCachedFile, "TILECACHE\\FLY_SHDW.STI" );
- AniParams.uiUserData3 = pSoldier->bDirection;
- pSoldier->pAniTile = CreateAnimationTile( &AniParams );
- HandleCrowShadowVisibility( pSoldier );
- }
- }
- }
- }
- void HandleCrowShadowRemoveGridNo( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->ubBodyType == CROW )
- {
- if ( pSoldier->usAnimState == CROW_FLY )
- {
- if ( pSoldier->pAniTile != NULL )
- {
- DeleteAniTile( pSoldier->pAniTile );
- pSoldier->pAniTile = NULL;
- }
- }
- }
- }
- void HandleCrowShadowNewDirection( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->ubBodyType == CROW )
- {
- if ( pSoldier->usAnimState == CROW_FLY )
- {
- if ( pSoldier->pAniTile != NULL )
- {
- pSoldier->pAniTile->uiUserData3 = pSoldier->bDirection;
- }
- }
- }
- }
- void HandleCrowShadowNewPosition( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->ubBodyType == CROW )
- {
- if ( pSoldier->usAnimState == CROW_FLY )
- {
- if ( pSoldier->pAniTile != NULL )
- {
- pSoldier->pAniTile->sRelativeX = pSoldier->sX;
- pSoldier->pAniTile->sRelativeY = pSoldier->sY;
- }
- }
- }
- }
- INT8 CalcActionPoints(SOLDIERTYPE *pSold)
- {
- UINT8 ubPoints,ubMaxAPs;
- INT8 bBandage;
- // dead guys don't get any APs (they shouldn't be here asking for them!)
- if (!pSold->bLife)
- return(0);
- // people with sleep dart drug who have collapsed get no APs
- if ( (pSold->bSleepDrugCounter > 0) && pSold->bCollapsed )
- return( 0 );
- // Calculate merc's action points at 100% capability (range is 10 - 25)
- // round fractions of .5 up (that's why the +20 before the division!
- ubPoints = 5 + (((10 * EffectiveExpLevel( pSold ) +
- 3 * EffectiveAgility( pSold ) +
- 2 * pSold->bLifeMax +
- 2 * EffectiveDexterity( pSold ) ) + 20) / 40);
- //if (GameOption[INCREASEDAP] % 2 == 1)
- //points += AP_INCREASE;
- // Calculate bandage
- bBandage = pSold->bLifeMax - pSold->bLife - pSold->bBleeding;
- // If injured, reduce action points accordingly (by up to 2/3rds)
- if (pSold->bLife < pSold->bLifeMax)
- {
- ubPoints -= (2 * ubPoints * (pSold->bLifeMax - pSold->bLife + (bBandage / 2))) /
- (3 * pSold->bLifeMax);
- }
- // If tired, reduce action points accordingly (by up to 1/2)
- if (pSold->bBreath < 100)
- ubPoints -= (ubPoints * (100 - pSold->bBreath)) / 200;
- if (pSold->sWeightCarriedAtTurnStart > 100)
- {
- ubPoints = (UINT8) ( ((UINT32)ubPoints) * 100 / pSold->sWeightCarriedAtTurnStart );
- }
- // If resulting APs are below our permitted minimum, raise them to it!
- if (ubPoints < AP_MINIMUM)
- ubPoints = AP_MINIMUM;
- // make sure action points doesn't exceed the permitted maximum
- ubMaxAPs = gubMaxActionPoints[ pSold->ubBodyType ];
- //if (GameOption[INCREASEDAP] % 2 == 1)
- // maxAPs += AP_INCREASE;
- // If resulting APs are below our permitted minimum, raise them to it!
- if (ubPoints > ubMaxAPs)
- ubPoints = ubMaxAPs;
- if ( pSold->ubBodyType == BLOODCAT )
- {
- // use same as young monsters
- ubPoints = (ubPoints * AP_YOUNG_MONST_FACTOR) / 10;
- }
- else if (pSold->uiStatusFlags & SOLDIER_MONSTER)
- {
- // young monsters get extra APs
- if ( pSold->ubBodyType == YAF_MONSTER || pSold->ubBodyType == YAM_MONSTER || pSold->ubBodyType == INFANT_MONSTER )
- {
- ubPoints = (ubPoints * AP_YOUNG_MONST_FACTOR) / 10;
- }
- // if frenzied, female monsters get more APs! (for young females, cumulative!)
- if (pSold->bFrenzied)
- {
- ubPoints = (ubPoints * AP_MONST_FRENZY_FACTOR) / 10;
- }
- }
- // adjust APs for phobia situations
- if ( pSold->ubProfile != NO_PROFILE )
- {
- if ( (gMercProfiles[ pSold->ubProfile ].bPersonalityTrait == CLAUSTROPHOBIC) && (gbWorldSectorZ > 0) )
- {
- ubPoints = (ubPoints * AP_CLAUSTROPHOBE) / 10;
- }
- else if ( (gMercProfiles[ pSold->ubProfile ].bPersonalityTrait == FEAR_OF_INSECTS) && (MercSeesCreature( pSold ) ) )
- {
- ubPoints = (ubPoints * AP_AFRAID_OF_INSECTS) / 10;
- }
- }
- // Adjusat APs due to drugs...
- HandleAPEffectDueToDrugs( pSold, &ubPoints );
- // If we are a vehicle, adjust APS...
- if ( pSold->uiStatusFlags & SOLDIER_VEHICLE )
- {
- AdjustVehicleAPs( pSold, &ubPoints );
- }
- // if we are in boxing mode, adjust APs... THIS MUST BE LAST!
- if ( gTacticalStatus.bBoxingState == BOXING || gTacticalStatus.bBoxingState == PRE_BOXING )
- {
- ubPoints /= 2;
- }
- return (ubPoints);
- }
- void CalcNewActionPoints( SOLDIERTYPE *pSoldier )
- {
- if ( gTacticalStatus.bBoxingState == BOXING || gTacticalStatus.bBoxingState == PRE_BOXING )
- {
- // if we are in boxing mode, carry 1/2 as many points
- if (pSoldier->bActionPoints > MAX_AP_CARRIED / 2)
- {
- pSoldier->bActionPoints = MAX_AP_CARRIED / 2;
- }
- }
- else
- {
- if (pSoldier->bActionPoints > MAX_AP_CARRIED)
- {
- pSoldier->bActionPoints = MAX_AP_CARRIED;
- }
- }
- pSoldier->bActionPoints += CalcActionPoints( pSoldier);
- // Don't max out if we are drugged....
- if ( !GetDrugEffect( pSoldier, DRUG_TYPE_ADRENALINE ) )
- {
- pSoldier->bActionPoints = __min( pSoldier->bActionPoints, gubMaxActionPoints[ pSoldier->ubBodyType ] );
- }
- pSoldier->bInitialActionPoints = pSoldier->bActionPoints;
- }
- void DoNinjaAttack( SOLDIERTYPE *pSoldier )
- {
- //UINT32 uiMercFlags;
- UINT16 usSoldierIndex;
- SOLDIERTYPE *pTSoldier;
- UINT8 ubTDirection;
- UINT8 ubTargetStance;
- usSoldierIndex = WhoIsThere2( pSoldier->sTargetGridNo, pSoldier->bLevel );
- if ( usSoldierIndex != NOBODY )
- {
- GetSoldier( &pTSoldier, usSoldierIndex );
- // Look at stance of target
- ubTargetStance = gAnimControl[ pTSoldier->usAnimState ].ubEndHeight;
- // Get his life...if < certain value, do finish!
- if ( (pTSoldier->bLife <= 30 || pTSoldier->bBreath <= 30) && ubTargetStance != ANIM_PRONE )
- {
- // Do finish!
- ChangeSoldierState( pSoldier, NINJA_SPINKICK, 0 , FALSE );
- }
- else
- {
- if ( ubTargetStance != ANIM_PRONE )
- {
- if ( Random( 2 ) == 0 )
- {
- ChangeSoldierState( pSoldier, NINJA_LOWKICK, 0 , FALSE );
- }
- else
- {
- ChangeSoldierState( pSoldier, NINJA_PUNCH, 0 , FALSE );
- }
- // CHECK IF HE CAN SEE US, IF SO CHANGE DIRECTION
- if ( pTSoldier->bOppList[ pSoldier->ubID ] == 0 && pTSoldier->bTeam != pSoldier->bTeam )
- {
- if ( !( pTSoldier->uiStatusFlags & ( SOLDIER_MONSTER | SOLDIER_ANIMAL | SOLDIER_VEHICLE ) ) )
- {
- ubTDirection = (UINT8)GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier );
- SendSoldierSetDesiredDirectionEvent( pTSoldier, ubTDirection );
- }
- }
- }
- else
- {
- // CHECK OUR STANCE
- if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH )
- {
- // SET DESIRED STANCE AND SET PENDING ANIMATION
- SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH );
- pSoldier->usPendingAnimation = PUNCH_LOW;
- }
- else
- {
- // USE crouched one
- // NEED TO CHANGE STANCE IF NOT CROUCHD!
- EVENT_InitNewSoldierAnim( pSoldier, PUNCH_LOW, 0 , FALSE );
- }
- }
- }
- }
- if ( pSoldier->ubProfile == 33 )
- {
- UINT32 uiSoundID;
- SOUNDPARMS spParms;
- INT32 iFaceIndex;
- // Play sound!
- memset(&spParms, 0xff, sizeof(SOUNDPARMS));
- spParms.uiSpeed = RATE_11025;
- spParms.uiVolume = (INT8)CalculateSpeechVolume( HIGHVOLUME );
- // If we are an enemy.....reduce due to volume
- if ( pSoldier->bTeam != gbPlayerNum )
- {
- spParms.uiVolume = SoundVolume( (UINT8)spParms.uiVolume, pSoldier->sGridNo );
- }
- spParms.uiLoop = 1;
- spParms.uiPan = SoundDir( pSoldier->sGridNo );
- spParms.uiPriority=GROUP_PLAYER;
- if ( pSoldier->usAnimState == NINJA_SPINKICK )
- {
- uiSoundID = SoundPlay( "BATTLESNDS\\033_CHOP2.WAV", &spParms );
- }
- else
- {
- if ( Random( 2 ) == 0 )
- {
- uiSoundID = SoundPlay( "BATTLESNDS\\033_CHOP3.WAV", &spParms );
- }
- else
- {
- uiSoundID = SoundPlay( "BATTLESNDS\\033_CHOP1.WAV", &spParms );
- }
- }
- if ( uiSoundID != SOUND_ERROR )
- {
- pSoldier->uiBattleSoundID = uiSoundID;
- if ( pSoldier->ubProfile != NO_PROFILE )
- {
- // Get soldier's face ID
- iFaceIndex = pSoldier->iFaceIndex;
- // Check face index
- if ( iFaceIndex != -1 )
- {
- ExternSetFaceTalking( iFaceIndex, uiSoundID );
- }
- }
- }
- }
- }
- BOOLEAN CreateSoldierCommon( UINT8 ubBodyType, SOLDIERTYPE *pSoldier, UINT16 usSoldierID, UINT16 usState )
- {
- BOOLEAN fSuccess = FALSE;
- INT32 iCounter = 0;
- //if we are loading a saved game, we DO NOT want to reset the opplist, look for enemies, or say a dying commnet
- if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
- {
- // Set initial values for opplist!
- InitSoldierOppList( pSoldier );
- HandleSight( pSoldier, SIGHT_LOOK );
- // Set some quote flags
- if ( pSoldier->bLife >= OKLIFE )
- {
- pSoldier->fDyingComment = FALSE;
- }
- else
- {
- pSoldier->fDyingComment = TRUE;
- }
- }
- // ATE: Reset some timer flags...
- pSoldier->uiTimeSameBattleSndDone = 0;
- // ATE: Reset every time.....
- pSoldier->fSoldierWasMoving = TRUE;
- pSoldier->iTuringSoundID = NO_SAMPLE;
- pSoldier->uiTimeSinceLastBleedGrunt = 0;
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- pSoldier->iPositionSndID = NewPositionSnd( NOWHERE, POSITION_SOUND_FROM_SOLDIER, (UINT32)pSoldier, QUEEN_AMBIENT_NOISE );
- }
- // ANYTHING AFTER HERE CAN FAIL
- do
- {
- if (usSoldierID <= gTacticalStatus.Team[ OUR_TEAM ].bLastID)
- {
- pSoldier->pKeyRing = MemAlloc( NUM_KEYS * sizeof( KEY_ON_RING ) );
- memset( pSoldier->pKeyRing , 0, NUM_KEYS * sizeof( KEY_ON_RING ) );
- for( iCounter = 0; iCounter < NUM_KEYS; iCounter++ )
- {
- pSoldier->pKeyRing[ iCounter ].ubKeyID = INVALID_KEY_NUMBER;
- }
- }
- else
- {
- pSoldier->pKeyRing = NULL;
- }
- // Create frame cache
- if( InitAnimationCache( usSoldierID, &( pSoldier->AnimCache) ) == FALSE )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed animation cache creation" ) );
- break;
- }
- if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
- {
- // Init new soldier state
- // OFFSET FIRST ANIMATION FRAME FOR NEW MERCS
- if ( usState != STANDING )
- {
- EVENT_InitNewSoldierAnim( pSoldier, usState, (UINT8)0, TRUE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, usState, (UINT8)Random( 10 ), TRUE );
- }
- }
- else
- {
- /// if we don't have a world loaded, and are in a bad anim, goto standing.
- // bad anims are: HOPFENCE,
- // CLIMBDOWNROOF, FALLFORWARD_ROOF,FALLOFF, CLIMBUPROOF
- if( !gfWorldLoaded &&
- ( usState == HOPFENCE ||
- usState == CLIMBDOWNROOF ||
- usState == FALLFORWARD_ROOF ||
- usState == FALLOFF ||
- usState == CLIMBUPROOF ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, STANDING, 0, TRUE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, usState, pSoldier->usAniCode, TRUE );
- }
- }
- //if ( pSoldier->pBackGround != NULL )
- // MemFree( pSoldier->pBackGround );
- // INIT ANIMATION DATA
- //if((pSoldier->pBackGround=MemAlloc(SOLDIER_UNBLIT_SIZE))==NULL)
- //{
- // DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed unblit memory allocation" ) );
- // break;
- //}
- //memset(pSoldier->pBackGround, 0, SOLDIER_UNBLIT_SIZE);
- //if((pSoldier->pZBackground=MemAlloc(SOLDIER_UNBLIT_SIZE))==NULL)
- //{
- // DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed unblit memory allocation" ) );
- // break;
- //}
- //memset(pSoldier->pZBackground, 0, SOLDIER_UNBLIT_SIZE);
- // Init palettes
- if( CreateSoldierPalettes( pSoldier ) == FALSE )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed in creating soldier palettes" ) );
- break;
- }
-
- fSuccess = TRUE;
- } while( FALSE );
- if ( !fSuccess )
- {
- DeleteSoldier( (pSoldier ) );
- }
- return( fSuccess );
- }
- BOOLEAN DeleteSoldier( SOLDIERTYPE *pSoldier )
- {
- UINT32 cnt;
- INT32 iGridNo;
- INT8 bDir;
- BOOLEAN fRet;
- if ( pSoldier != NULL )
- {
- //if(pSoldier->pBackGround!=NULL)
- //MemFree(pSoldier->pBackGround);
- //if(pSoldier->pZBackground!=NULL)
- //MemFree(pSoldier->pZBackground);
- if( pSoldier->sGridNo != NOWHERE )
- {
- // Remove adjacency records
- for (bDir = 0; bDir < NUM_WORLD_DIRECTIONS; bDir++)
- {
- iGridNo = pSoldier->sGridNo + DirIncrementer[ bDir ];
- if( iGridNo >= 0 && iGridNo < WORLD_MAX )
- {
- gpWorldLevelData[ iGridNo ].ubAdjacentSoldierCnt--;
- }
- }
- }
-
- // Delete key ring
- if (pSoldier->pKeyRing)
- {
- MemFree( pSoldier->pKeyRing );
- pSoldier->pKeyRing = NULL;
- }
- // Delete faces
- DeleteSoldierFace( pSoldier );
- // FREE PALETTES
- if ( pSoldier->p8BPPPalette != NULL )
- {
- MemFree( pSoldier->p8BPPPalette );
- pSoldier->p8BPPPalette = NULL;
- }
- if ( pSoldier->p16BPPPalette != NULL )
- {
- MemFree( pSoldier->p16BPPPalette );
- pSoldier->p16BPPPalette = NULL;
- }
- for ( cnt = 0; cnt < NUM_SOLDIER_SHADES; cnt++ )
- {
- if ( pSoldier->pShades[ cnt ] != NULL )
- {
- MemFree( pSoldier->pShades[ cnt ] );
- pSoldier->pShades[ cnt ] = NULL;
- }
- }
- for ( cnt = 0; cnt < NUM_SOLDIER_EFFECTSHADES; cnt++ )
- {
- if ( pSoldier->pEffectShades[ cnt ] != NULL )
- {
- MemFree( pSoldier->pEffectShades[ cnt ] );
- pSoldier->pEffectShades[ cnt ] = NULL;
- }
- }
- // Delete glows
- for ( cnt = 0; cnt < 20; cnt++ )
- {
- if ( pSoldier->pGlowShades[ cnt ] != NULL )
- {
- MemFree( pSoldier->pGlowShades[ cnt ] );
- pSoldier->pGlowShades[ cnt ] = NULL;
- }
- }
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- DeletePositionSnd( pSoldier->iPositionSndID );
- }
- // Free any animations we may have locked...
- UnLoadCachedAnimationSurfaces( pSoldier->ubID, &( pSoldier->AnimCache) );
- // Free Animation cache
- DeleteAnimationCache( pSoldier->ubID, &( pSoldier->AnimCache) );
- // Soldier is not active
- pSoldier->bActive = FALSE;
- // Remove light
- DeleteSoldierLight( pSoldier );
- // Remove reseved movement value
- UnMarkMovementReserved( pSoldier );
-
- }
- // REMOVE SOLDIER FROM SLOT!
- fRet = RemoveMercSlot( pSoldier );
-
- if (!fRet)
- {
- RemoveAwaySlot( pSoldier );
- }
- return( TRUE );
- }
- BOOLEAN CreateSoldierLight( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->bTeam != gbPlayerNum )
- {
- return( FALSE );
- }
- // DO ONLY IF WE'RE AT A GOOD LEVEL
- if ( pSoldier->iLight == -1 )
- {
- // ATE: Check for goggles in headpos....
- if ( pSoldier->inv[ HEAD1POS ].usItem == NIGHTGOGGLES ||
- pSoldier->inv[ HEAD2POS ].usItem == NIGHTGOGGLES )
- {
- if( ( pSoldier->iLight=LightSpriteCreate("Light3", 0 ) )==(-1))
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed loading light" ) );
- return( FALSE );
- }
- else
- {
- LightSprites[ pSoldier->iLight ].uiFlags |= MERC_LIGHT;
- }
- }
- else if ( pSoldier->inv[ HEAD1POS ].usItem == UVGOGGLES ||
- pSoldier->inv[ HEAD2POS ].usItem == UVGOGGLES )
- {
- if( ( pSoldier->iLight=LightSpriteCreate("Light4", 0 ) )==(-1))
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed loading light" ) );
- return( FALSE );
- }
- else
- {
- LightSprites[ pSoldier->iLight ].uiFlags |= MERC_LIGHT;
- }
- }
- else
- {
- if( ( pSoldier->iLight=LightSpriteCreate("Light2", 0 ) )==(-1))
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier: Failed loading light" ) );
- return( FALSE );
- }
- else
- {
- LightSprites[ pSoldier->iLight ].uiFlags |= MERC_LIGHT;
- }
- }
- if ( pSoldier->bLevel != 0 )
- {
- LightSpriteRoofStatus(pSoldier->iLight, TRUE );
- }
- }
- return( TRUE );
- }
- BOOLEAN ReCreateSoldierLight( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->bTeam != gbPlayerNum )
- {
- return( FALSE );
- }
- if ( !pSoldier->bActive )
- {
- return( FALSE );
- }
- if ( !pSoldier->bInSector )
- {
- return( FALSE );
- }
- // Delete Light!
- DeleteSoldierLight( pSoldier );
- if ( pSoldier->iLight == -1 )
- {
- CreateSoldierLight( pSoldier );
- }
- return( TRUE );
- }
- BOOLEAN ReCreateSelectedSoldierLight( )
- {
- SOLDIERTYPE *pSoldier;
- if ( gusSelectedSoldier == NO_SOLDIER )
- {
- return( FALSE );
- }
- pSoldier = MercPtrs[ gusSelectedSoldier ];
- return( ReCreateSoldierLight( pSoldier ) );
- }
- BOOLEAN DeleteSoldierLight( SOLDIERTYPE *pSoldier )
- {
- if( pSoldier->iLight!=(-1) )
- {
- LightSpriteDestroy( pSoldier->iLight );
- pSoldier->iLight = -1;
- }
- return( TRUE );
- }
- // FUNCTIONS CALLED BY EVENT PUMP
- /////////////////////////////////
- BOOLEAN ChangeSoldierState( SOLDIERTYPE *pSoldier, UINT16 usNewState, UINT16 usStartingAniCode, BOOLEAN fForce )
- {
- EV_S_CHANGESTATE SChangeState;
- // Send message that we have changed states
- SChangeState.usNewState = usNewState;
- SChangeState.usSoldierID = pSoldier->ubID;
- SChangeState.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- SChangeState.usStartingAniCode = usStartingAniCode;
- SChangeState.sXPos = pSoldier->sX;
- SChangeState.sYPos = pSoldier->sY;
- SChangeState.fForce = fForce;
- SChangeState.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- //AddGameEvent( S_CHANGESTATE, 0, &SChangeState );
- EVENT_InitNewSoldierAnim( pSoldier, SChangeState.usNewState, SChangeState.usStartingAniCode, SChangeState.fForce );
- return( TRUE );
- }
- // This function reevaluates the stance if the guy sees us!
- BOOLEAN ReevaluateEnemyStance( SOLDIERTYPE *pSoldier, UINT16 usAnimState )
- {
- INT32 cnt, iClosestEnemy = NOBODY;
- INT16 sTargetXPos, sTargetYPos;
- BOOLEAN fReturnVal = FALSE;
- INT16 sDist, sClosestDist = 10000;
- // make the chosen one not turn to face us
- if ( OK_ENEMY_MERC( pSoldier ) && pSoldier->ubID != gTacticalStatus.ubTheChosenOne && gAnimControl[ usAnimState ].ubEndHeight == ANIM_STAND && !( pSoldier->uiStatusFlags & SOLDIER_UNDERAICONTROL) )
- {
- if ( pSoldier->fTurningFromPronePosition == TURNING_FROM_PRONE_OFF )
- {
- // If we are a queen and see enemies, goto ready
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- if ( gAnimControl[ usAnimState ].uiFlags & ( ANIM_BREATH ) )
- {
- if ( pSoldier->bOppCnt > 0 )
- {
- EVENT_InitNewSoldierAnim( pSoldier, QUEEN_INTO_READY, 0 , TRUE );
- return( TRUE );
- }
- }
- }
- // ATE: Don't do this if we're not a merc.....
- if ( !IS_MERC_BODY_TYPE( pSoldier ) )
- {
- return( FALSE );
- }
-
- if ( gAnimControl[ usAnimState ].uiFlags & ( ANIM_MERCIDLE | ANIM_BREATH ) )
- {
- if ( pSoldier->bOppCnt > 0 )
- {
- // Pick a guy this buddy sees and turn towards them!
- for ( cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++ )
- {
- if ( pSoldier->bOppList[ cnt ] == SEEN_CURRENTLY )
- {
- sDist = PythSpacesAway( pSoldier->sGridNo, MercPtrs[ cnt ]->sGridNo );
- if (sDist < sClosestDist)
- {
- sClosestDist = sDist;
- iClosestEnemy = cnt;
- }
- }
- }
- if (iClosestEnemy != NOBODY)
- {
- // Change to fire ready animation
- ConvertGridNoToXY( MercPtrs[ iClosestEnemy ]->sGridNo, &sTargetXPos, &sTargetYPos );
- pSoldier->fDontChargeReadyAPs = TRUE;
- // Ready weapon
- fReturnVal = SoldierReadyWeapon( pSoldier, sTargetXPos, sTargetYPos, FALSE );
- return( fReturnVal );
- }
-
- }
- }
- }
- }
- return( FALSE );
- }
-
- void CheckForFreeupFromHit( SOLDIERTYPE *pSoldier, UINT32 uiOldAnimFlags, UINT32 uiNewAnimFlags, UINT16 usOldAniState, UINT16 usNewState )
- {
- // THIS COULD POTENTIALLY CALL EVENT_INITNEWAnim() if the GUY was SUPPRESSED
- // CHECK IF THE OLD ANIMATION WAS A HIT START THAT WAS NOT FOLLOWED BY A HIT FINISH
- // IF SO, RELEASE ATTACKER FROM ATTACKING
- // If old and new animations are the same, do nothing!
- if ( usOldAniState == QUEEN_HIT && usNewState == QUEEN_HIT )
- {
- return;
- }
- if ( usOldAniState != usNewState && ( uiOldAnimFlags & ANIM_HITSTART ) && !( uiNewAnimFlags & ANIM_HITFINISH ) && !( uiNewAnimFlags & ANIM_IGNOREHITFINISH ) && !(pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT ) )
- {
- // Release attacker
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, normal hit animation ended NEW: %s ( %d ) OLD: %s ( %d )", gAnimControl[ usNewState ].zAnimStr, usNewState, gAnimControl[ usOldAniState ].zAnimStr, pSoldier->usOldAniState ) );
- ReleaseSoldiersAttacker( pSoldier );
- //FREEUP GETTING HIT FLAG
- pSoldier->fGettingHit = FALSE;
- // ATE: if our guy, have 10% change of say damn, if still conscious...
- if ( pSoldier->bTeam == gbPlayerNum && pSoldier->bLife >= OKLIFE )
- {
- if ( Random( 10 ) == 0 )
- {
- DoMercBattleSound( pSoldier, (INT8)( BATTLE_SOUND_CURSE1 ) );
- }
- }
- }
- // CHECK IF WE HAVE FINSIHED A HIT WHILE DOWN
- // OBLY DO THIS IF 1 ) We are dead already or 2 ) We are alive still
- if ( ( uiOldAnimFlags & ANIM_HITWHENDOWN ) && ( ( pSoldier->uiStatusFlags & SOLDIER_DEAD ) || pSoldier->bLife != 0 ) )
- {
- // Release attacker
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, animation of kill on the ground ended") );
- ReleaseSoldiersAttacker( pSoldier );
- //FREEUP GETTING HIT FLAG
- pSoldier->fGettingHit = FALSE;
- if ( pSoldier->bLife == 0 )
- {
- //ATE: Set previous attacker's value!
- // This is so that the killer can say their killed quote....
- pSoldier->ubAttackerID = pSoldier->ubPreviousAttackerID;
- }
- }
- }
- // THIS IS CALLED FROM AN EVENT ( S_CHANGESTATE )!
- BOOLEAN EVENT_InitNewSoldierAnim( SOLDIERTYPE *pSoldier, UINT16 usNewState, UINT16 usStartingAniCode, BOOLEAN fForce )
- {
- UINT16 usNewGridNo = 0;
- INT16 sAPCost = 0;
- INT16 sBPCost = 0;
- UINT32 uiOldAnimFlags;
- UINT32 uiNewAnimFlags;
- UINT16 usSubState;
- UINT16 usItem;
- BOOLEAN fTryingToRestart = FALSE;
- CHECKF( usNewState < NUMANIMATIONSTATES );
- ///////////////////////////////////////////////////////////////////////
- // DO SOME CHECKS ON OUR NEW ANIMATION!
- /////////////////////////////////////////////////////////////////////
- // If we are NOT loading a game, continue normally
- if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
- {
- // CHECK IF WE ARE TRYING TO INTURRUPT A SCRIPT WHICH WE DO NOT WANT INTERRUPTED!
- if ( pSoldier->fInNonintAnim )
- {
- return( FALSE );
- }
- if ( pSoldier->fRTInNonintAnim )
- {
- if ( !(gTacticalStatus.uiFlags & INCOMBAT) )
- {
- return( FALSE );
- }
- else
- {
- pSoldier->fRTInNonintAnim = FALSE;
- }
- }
- // Check if we can restart this animation if it's the same as our current!
- if ( usNewState == pSoldier->usAnimState )
- {
- if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_NORESTART ) && !fForce )
- {
- fTryingToRestart = TRUE;
- }
- }
- // Check state, if we are not at the same height, set this ani as the pending one and
- // change stance accordingly
- // ATE: ONLY IF WE ARE STARTING AT START OF ANIMATION!
- if ( usStartingAniCode == 0 )
- {
- if ( gAnimControl[ usNewState ].ubHeight != gAnimControl[ pSoldier->usAnimState ].ubEndHeight &&
- !( gAnimControl[ usNewState ].uiFlags & ( ANIM_STANCECHANGEANIM | ANIM_IGNORE_AUTOSTANCE ) ) )
- {
- // Check if we are going from crouched height to prone height, and adjust fast turning accordingly
- // Make guy turn while crouched THEN go into prone
- if ( ( gAnimControl[ usNewState ].ubEndHeight == ANIM_PRONE && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH ) && !( gTacticalStatus.uiFlags & INCOMBAT ) )
- {
- pSoldier->fTurningUntilDone = TRUE;
- pSoldier->ubPendingStanceChange = gAnimControl[ usNewState ].ubEndHeight;
- pSoldier->usPendingAnimation = usNewState;
- return( TRUE );
- }
- // Check if we are in realtime and we are going from stand to crouch
- else if ( gAnimControl[ usNewState ].ubEndHeight == ANIM_CROUCH && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND && ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING ) && ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
- {
- pSoldier->ubDesiredHeight = gAnimControl[ usNewState ].ubEndHeight;
- // Continue with this course of action IE: Do animation and skip from stand to crouch
- }
- // Check if we are in realtime and we are going from crouch to stand
- else if ( gAnimControl[ usNewState ].ubEndHeight == ANIM_STAND && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH && ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING ) && ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) && pSoldier->usAnimState != HELIDROP )
- {
- pSoldier->ubDesiredHeight = gAnimControl[ usNewState ].ubEndHeight;
- // Continue with this course of action IE: Do animation and skip from stand to crouch
- }
- else
- {
- // ONLY DO FOR EVERYONE BUT PLANNING GUYS
- if ( pSoldier->ubID < MAX_NUM_SOLDIERS )
- {
- // Set our next moving animation to be pending, after
- pSoldier->usPendingAnimation = usNewState;
- // Set new state to be animation to move to new stance
- SendChangeSoldierStanceEvent( pSoldier, gAnimControl[ usNewState ].ubHeight );
- return( TRUE );
- }
- }
- }
- }
- if ( usNewState == ADJACENT_GET_ITEM )
- {
- if ( pSoldier->ubPendingDirection != NO_PENDING_DIRECTION )
- {
- EVENT_InternalSetSoldierDesiredDirection( pSoldier, pSoldier->ubPendingDirection, FALSE, pSoldier->usAnimState );
- pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
- pSoldier->usPendingAnimation = ADJACENT_GET_ITEM;
- pSoldier->fTurningUntilDone = TRUE;
- SoldierGotoStationaryStance( pSoldier );
- return( TRUE );
- }
- }
- if ( usNewState == CLIMBUPROOF )
- {
- if ( pSoldier->ubPendingDirection != NO_PENDING_DIRECTION )
- {
- EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->ubPendingDirection );
- pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
- pSoldier->usPendingAnimation = CLIMBUPROOF;
- pSoldier->fTurningUntilDone = TRUE;
- SoldierGotoStationaryStance( pSoldier );
- return( TRUE );
- }
- }
- if ( usNewState == CLIMBDOWNROOF )
- {
- if ( pSoldier->ubPendingDirection != NO_PENDING_DIRECTION )
- {
- EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->ubPendingDirection );
- pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
- pSoldier->usPendingAnimation = CLIMBDOWNROOF;
- pSoldier->fTurningFromPronePosition = FALSE;
- pSoldier->fTurningUntilDone = TRUE;
- SoldierGotoStationaryStance( pSoldier );
- return( TRUE );
- }
- }
- // ATE: Don't raise/lower automatically if we are low on health,
- // as our gun looks lowered anyway....
- //if ( pSoldier->bLife > INJURED_CHANGE_THREASHOLD )
- {
- // Don't do some of this if we are a monster!
- // ATE: LOWER AIMATION IS GOOD, RAISE ONE HOWEVER MAY CAUSE PROBLEMS FOR AI....
- if ( !(pSoldier->uiStatusFlags & SOLDIER_MONSTER ) && pSoldier->ubBodyType != ROBOTNOWEAPON && pSoldier->bTeam == gbPlayerNum )
- {
- // If this animation is a raise_weapon animation
- if ( ( gAnimControl[ usNewState ].uiFlags & ANIM_RAISE_WEAPON ) && !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_RAISE_WEAPON | ANIM_NOCHANGE_WEAPON ) ) )
- {
- // We are told that we need to rasie weapon
- // Do so only if
- // 1) We have a rifle in hand...
- usItem = pSoldier->inv[ HANDPOS ].usItem;
- if ( usItem != NOTHING && (Item[ usItem ].fFlags & ITEM_TWO_HANDED) && usItem != ROCKET_LAUNCHER )
- {
- // Switch on height!
- switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // 2) OK, all's fine... lower weapon first....
- pSoldier->usPendingAnimation = usNewState;
- // Set new state to be animation to move to new stance
- usNewState = RAISE_RIFLE;
- }
- }
- }
- // If this animation is a lower_weapon animation
- if ( ( gAnimControl[ usNewState ].uiFlags & ANIM_LOWER_WEAPON ) && !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_LOWER_WEAPON | ANIM_NOCHANGE_WEAPON ) ) )
- {
- // We are told that we need to rasie weapon
- // Do so only if
- // 1) We have a rifle in hand...
- usItem = pSoldier->inv[ HANDPOS ].usItem;
- if ( usItem != NOTHING && (Item[ usItem ].fFlags & ITEM_TWO_HANDED) && usItem != ROCKET_LAUNCHER )
- {
- // Switch on height!
- switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // 2) OK, all's fine... lower weapon first....
- pSoldier->usPendingAnimation = usNewState;
- // Set new state to be animation to move to new stance
- usNewState = LOWER_RIFLE;
- }
- }
- }
- }
- }
- // Are we cowering and are tyring to move, getup first...
- if ( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING && pSoldier->usAnimState == COWERING && gAnimControl[ usNewState ].ubEndHeight == ANIM_STAND )
- {
- pSoldier->usPendingAnimation = usNewState;
- // Set new state to be animation to move to new stance
- usNewState = END_COWER;
- }
-
- // If we want to start swatting, put a pending animation
- if( pSoldier->usAnimState != START_SWAT && usNewState == SWATTING )
- {
- // Set new state to be animation to move to new stance
- usNewState = START_SWAT;
- }
- if( pSoldier->usAnimState == SWATTING && usNewState == CROUCHING )
- {
- // Set new state to be animation to move to new stance
- usNewState = END_SWAT;
- }
- if( pSoldier->usAnimState == WALKING && usNewState == STANDING && pSoldier->bLife < INJURED_CHANGE_THREASHOLD && pSoldier->ubBodyType <= REGFEMALE && !MercInWater( pSoldier ) )
- {
- // Set new state to be animation to move to new stance
- usNewState = END_HURT_WALKING;
- }
- // Check if we are an enemy, and we are in an animation what should be overriden
- // by if he sees us or not.
- if ( ReevaluateEnemyStance( pSoldier, usNewState ) )
- {
- return( TRUE );
- }
- // OK.......
- if ( pSoldier->ubBodyType > REGFEMALE )
- {
- if ( pSoldier->bLife < INJURED_CHANGE_THREASHOLD )
- {
- if ( usNewState == READY_RIFLE_STAND )
- {
- // pSoldier->usPendingAnimation2 = usNewState;
- // usNewState = FROM_INJURED_TRANSITION;
- }
- }
- }
- // Alrighty, check if we should free buddy up!
- if ( usNewState == GIVING_AID )
- {
- UnSetUIBusy( pSoldier->ubID );
- }
- // SUBSTITUDE VARIOUS REG ANIMATIONS WITH ODD BODY TYPES
- if ( SubstituteBodyTypeAnimation( pSoldier, usNewState, &usSubState ) )
- {
- usNewState = usSubState;
- }
- // CHECK IF WE CAN DO THIS ANIMATION!
- if ( IsAnimationValidForBodyType( pSoldier, usNewState ) == FALSE )
- {
- return( FALSE );
- }
- // OK, make guy transition if a big merc...
- if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE )
- {
- if ( usNewState == KNEEL_DOWN && pSoldier->usAnimState != BIGMERC_CROUCH_TRANS_INTO )
- {
- UINT16 usItem;
- // Do we have a rifle?
- usItem = pSoldier->inv[ HANDPOS ].usItem;
- if ( usItem != NOTHING )
- {
- if ( Item[ usItem ].usItemClass == IC_GUN && usItem != ROCKET_LAUNCHER )
- {
- if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) )
- {
- usNewState = BIGMERC_CROUCH_TRANS_INTO;
- }
- }
- }
- }
- if ( usNewState == KNEEL_UP && pSoldier->usAnimState != BIGMERC_CROUCH_TRANS_OUTOF )
- {
- UINT16 usItem;
- // Do we have a rifle?
- usItem = pSoldier->inv[ HANDPOS ].usItem;
- if ( usItem != NOTHING )
- {
- if ( Item[ usItem ].usItemClass == IC_GUN && usItem != ROCKET_LAUNCHER )
- {
- if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) )
- {
- usNewState = BIGMERC_CROUCH_TRANS_OUTOF;
- }
- }
- }
- }
- }
- // OK, if we have reverse set, do the side step!
- if ( pSoldier->bReverse )
- {
- if ( usNewState == WALKING || usNewState == RUNNING || usNewState == SWATTING )
- {
- // CHECK FOR SIDEWAYS!
- if ( pSoldier->bDirection == gPurpendicularDirection[ pSoldier->bDirection ][ pSoldier->usPathingData[ pSoldier->usPathIndex ] ] )
- {
- // We are perpendicular!
- usNewState = SIDE_STEP;
- }
- else
- {
- if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH )
- {
- usNewState = SWAT_BACKWARDS;
- }
- else
- {
- // Here, change to opposite direction
- usNewState = WALK_BACKWARDS;
- }
- }
- }
- }
- // ATE: Patch hole for breath collapse for roofs, fences
- if ( usNewState == CLIMBUPROOF || usNewState == CLIMBDOWNROOF || usNewState == HOPFENCE )
- {
- // Check for breath collapse if a given animation like
- if ( CheckForBreathCollapse( pSoldier ) || pSoldier->bCollapsed )
- {
- // UNset UI
- UnSetUIBusy( pSoldier->ubID );
- SoldierCollapse( pSoldier );
-
- pSoldier->bBreathCollapsed = FALSE;
- return( FALSE );
- }
- }
- // If we are in water.....and trying to run, change to run
- if ( pSoldier->bOverTerrainType == LOW_WATER || pSoldier->bOverTerrainType == MED_WATER )
- {
- // Check animation
- // Change to walking
- if ( usNewState == RUNNING )
- {
- usNewState = WALKING;
- }
- }
- // Turn off anipause flag for any anim!
- pSoldier->uiStatusFlags &= (~SOLDIER_PAUSEANIMOVE);
- // Unset paused for no APs.....
- AdjustNoAPToFinishMove( pSoldier, FALSE );
- if ( usNewState == CRAWLING && pSoldier->usDontUpdateNewGridNoOnMoveAnimChange == 1 )
- {
- if ( pSoldier->fTurningFromPronePosition != TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE )
- {
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_START_UP_FROM_MOVE;
- }
- // ATE: IF we are starting to crawl, but have to getup to turn first......
- if ( pSoldier->fTurningFromPronePosition == TURNING_FROM_PRONE_START_UP_FROM_MOVE )
- {
- usNewState = PRONE_UP;
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE;
- }
- }
-
- // We are about to start moving
- // Handle buddy beginning to move...
- // check new gridno, etc
- // ATE: Added: Make check that old anim is not a moving one as well
- if ( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING && !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING ) || ( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING && fForce ) )
- {
- BOOLEAN fKeepMoving;
- if ( usNewState == CRAWLING && pSoldier->usDontUpdateNewGridNoOnMoveAnimChange == LOCKED_NO_NEWGRIDNO )
- {
- // Turn off lock once we are crawling once...
- pSoldier->usDontUpdateNewGridNoOnMoveAnimChange = 1;
- }
- // ATE: Additional check here if we have just been told to update animation ONLY, not goto gridno stuff...
- if ( !pSoldier->usDontUpdateNewGridNoOnMoveAnimChange )
- {
- if ( usNewState != SWATTING )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Handling New gridNo for %d: Old %s, New %s", pSoldier->ubID, gAnimControl[ pSoldier->usAnimState ].zAnimStr , gAnimControl[ usNewState ].zAnimStr) );
- if ( !( gAnimControl[ usNewState ].uiFlags & ANIM_SPECIALMOVE ) )
- {
- // Handle goto new tile...
- if ( HandleGotoNewGridNo( pSoldier, &fKeepMoving, TRUE, usNewState ) )
- {
- if ( !fKeepMoving )
- {
- return( FALSE );
- }
- // Make sure desy = zeroed out...
- // pSoldier->fPastXDest = pSoldier->fPastYDest = FALSE;
- }
- else
- {
- if ( pSoldier->bBreathCollapsed )
- {
- // UNset UI
- UnSetUIBusy( pSoldier->ubID );
- SoldierCollapse( pSoldier );
-
- pSoldier->bBreathCollapsed = FALSE;
- }
- return( FALSE );
- }
- }
- else
- {
- // Change desired direction
- // Just change direction
- EVENT_InternalSetSoldierDestination( pSoldier, pSoldier->usPathingData[ pSoldier->usPathIndex ], FALSE, pSoldier->usAnimState );
- }
- //check for services
- ReceivingSoldierCancelServices( pSoldier );
- GivingSoldierCancelServices( pSoldier );
- // Check if we are a vehicle, and start playing noise sound....
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- HandleVehicleMovementSound( pSoldier, TRUE );
- }
- }
- }
- }
- else
- {
- // Check for stopping movement noise...
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- HandleVehicleMovementSound( pSoldier, FALSE );
- // If a vehicle, set hewight to 0
- SetSoldierHeight( pSoldier, (FLOAT)( 0 ) );
- }
- }
- // Reset to false always.....
- // ( Unless locked )
- if ( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING )
- {
- if ( pSoldier->usDontUpdateNewGridNoOnMoveAnimChange != LOCKED_NO_NEWGRIDNO )
- {
- pSoldier->usDontUpdateNewGridNoOnMoveAnimChange = FALSE;
- }
- }
- if ( fTryingToRestart )
- {
- return( FALSE );
- }
- }
- // ATE: If this is an AI guy.. unlock him!
- if ( gTacticalStatus.fEnemySightingOnTheirTurn )
- {
- if ( gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID == pSoldier->ubID )
- {
- pSoldier->fPauseAllAnimation = FALSE;
- gTacticalStatus.fEnemySightingOnTheirTurn = FALSE;
- }
- }
- ///////////////////////////////////////////////////////////////////////
- // HERE DOWN - WE HAVE MADE A DESCISION!
- /////////////////////////////////////////////////////////////////////
- uiOldAnimFlags = gAnimControl[ pSoldier->usAnimState ].uiFlags;
- uiNewAnimFlags = gAnimControl[ usNewState ].uiFlags;
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)DirectionInc( pSoldier->usPathingData[ pSoldier->usPathIndex ] ) );
- // CHECKING IF WE HAVE A HIT FINISH BUT NO DEATH IS DONE WITH A SPECIAL ANI CODE
- // IN THE HIT FINSIH ANI SCRIPTS
- // CHECKING IF WE HAVE FINISHED A DEATH ANIMATION IS DONE WITH A SPECIAL ANI CODE
- // IN THE DEATH SCRIPTS
- // CHECK IF THIS NEW STATE IS NON-INTERRUPTABLE
- // IF SO - SET NON-INT FLAG
- if ( uiNewAnimFlags & ANIM_NONINTERRUPT )
- {
- pSoldier->fInNonintAnim = TRUE;
- }
- if ( uiNewAnimFlags & ANIM_RT_NONINTERRUPT )
- {
- pSoldier->fRTInNonintAnim = TRUE;
- }
- // CHECK IF WE ARE NOT AIMING, IF NOT, RESET LAST TAGRET!
- if ( !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) && !(gAnimControl[ usNewState ].uiFlags & ANIM_FIREREADY ) )
- {
- // ATE: Also check for the transition anims to not reset this
- // this should have used a flag but we're out of them....
- if ( usNewState != READY_RIFLE_STAND && usNewState != READY_RIFLE_PRONE && usNewState != READY_RIFLE_CROUCH && usNewState != ROBOT_SHOOT )
- {
- pSoldier->sLastTarget = NOWHERE;
- }
- }
- // If a special move state, release np aps
- if ( ( gAnimControl[ usNewState ].uiFlags & ANIM_SPECIALMOVE ) )
- {
- AdjustNoAPToFinishMove( pSoldier, FALSE );
- }
- if ( gAnimControl[ usNewState ].uiFlags & ANIM_UPDATEMOVEMENTMODE )
- {
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- // pSoldier->usUIMovementMode = GetMoveStateBasedOnStance( pSoldier, gAnimControl[ usNewState ].ubEndHeight );
- }
- }
- // ATE: If not a moving animation - turn off reverse....
- if ( !( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING ) )
- {
- pSoldier->bReverse = FALSE;
- }
- // ONLY DO FOR EVERYONE BUT PLANNING GUYS
- if ( pSoldier->ubID < MAX_NUM_SOLDIERS )
- {
- // Do special things based on new state
- switch( usNewState )
- {
- case STANDING:
- // Update desired height
- pSoldier->ubDesiredHeight = ANIM_STAND;
- break;
- case CROUCHING:
- // Update desired height
- pSoldier->ubDesiredHeight = ANIM_CROUCH;
- break;
- case PRONE:
- // Update desired height
- pSoldier->ubDesiredHeight = ANIM_PRONE;
- break;
- case READY_RIFLE_STAND:
- case READY_RIFLE_PRONE:
- case READY_RIFLE_CROUCH:
- case READY_DUAL_STAND:
- case READY_DUAL_CROUCH:
- case READY_DUAL_PRONE:
- // OK, get points to ready weapon....
- if ( !pSoldier->fDontChargeReadyAPs )
- {
- sAPCost = GetAPsToReadyWeapon( pSoldier, usNewState );
- DeductPoints( pSoldier, sAPCost, sBPCost );
- }
- else
- {
- pSoldier->fDontChargeReadyAPs = FALSE;
- }
- break;
- case WALKING:
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->ubPendingActionAnimCount = 0;
- break;
- case SWATTING:
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->ubPendingActionAnimCount = 0;
- break;
- case CRAWLING:
- // Turn off flag...
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
- pSoldier->ubPendingActionAnimCount = 0;
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- break;
- case RUNNING:
- // Only if our previous is not running
- if ( pSoldier->usAnimState != RUNNING )
- {
- sAPCost = AP_START_RUN_COST;
- DeductPoints( pSoldier, sAPCost, sBPCost );
- }
- // Set pending action count to 0
- pSoldier->ubPendingActionAnimCount = 0;
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- break;
- case ADULTMONSTER_WALKING:
- pSoldier->ubPendingActionAnimCount = 0;
- break;
- case ROBOT_WALK:
- pSoldier->ubPendingActionAnimCount = 0;
- break;
- case KNEEL_UP:
- case KNEEL_DOWN:
- case BIGMERC_CROUCH_TRANS_INTO:
- case BIGMERC_CROUCH_TRANS_OUTOF:
- if ( !pSoldier->fDontChargeAPsForStanceChange )
- {
- DeductPoints( pSoldier, AP_CROUCH, BP_CROUCH );
- }
- pSoldier->fDontChargeAPsForStanceChange = FALSE;
- break;
- case PRONE_UP:
- case PRONE_DOWN:
- // ATE: If we are NOT waiting for prone down...
- if ( pSoldier->fTurningFromPronePosition < TURNING_FROM_PRONE_START_UP_FROM_MOVE && !pSoldier->fDontChargeAPsForStanceChange )
- {
- // ATE: Don't do this if we are still 'moving'....
- if ( pSoldier->sGridNo == pSoldier->sFinalDestination || pSoldier->usPathIndex == 0 )
- {
- DeductPoints( pSoldier, AP_PRONE, BP_PRONE );
- }
- }
- pSoldier->fDontChargeAPsForStanceChange = FALSE;
- break;
- //Deduct points for stance change
- //sAPCost = GetAPsToChangeStance( pSoldier, gAnimControl[ usNewState ].ubEndHeight );
- //DeductPoints( pSoldier, sAPCost, 0 );
- //break;
- case START_AID:
- DeductPoints( pSoldier, AP_START_FIRST_AID, BP_START_FIRST_AID );
- break;
- case CUTTING_FENCE:
- DeductPoints( pSoldier, AP_USEWIRECUTTERS, BP_USEWIRECUTTERS );
- break;
- case PLANT_BOMB:
- DeductPoints( pSoldier, AP_DROP_BOMB, 0 );
- break;
- case STEAL_ITEM:
- DeductPoints( pSoldier, AP_STEAL_ITEM, 0 );
- break;
- case CROW_DIE:
- // Delete shadow of crow....
- if ( pSoldier->pAniTile != NULL )
- {
- DeleteAniTile( pSoldier->pAniTile );
- pSoldier->pAniTile = NULL;
- }
- break;
- case CROW_FLY:
-
- // Ate: startup a shadow ( if gridno is set )
- HandleCrowShadowNewGridNo( pSoldier );
- break;
- case CROW_EAT:
- // ATE: Make sure height level is 0....
- SetSoldierHeight( pSoldier, (FLOAT)(0) );
- HandleCrowShadowRemoveGridNo( pSoldier );
- break;
- case USE_REMOTE:
- DeductPoints( pSoldier, AP_USE_REMOTE, 0 );
- break;
- //case PUNCH:
- //Deduct points for punching
- //sAPCost = MinAPsToAttack( pSoldier, pSoldier->sGridNo, FALSE );
- //DeductPoints( pSoldier, sAPCost, 0 );
- //break;
- case HOPFENCE:
- DeductPoints( pSoldier, AP_JUMPFENCE, BP_JUMPFENCE );
- break;
- // Deduct aps for falling down....
- case FALLBACK_HIT_STAND:
- case FALLFORWARD_FROMHIT_STAND:
- DeductPoints( pSoldier, AP_FALL_DOWN, BP_FALL_DOWN );
- break;
- case FALLFORWARD_FROMHIT_CROUCH:
- DeductPoints( pSoldier, (AP_FALL_DOWN/2), (BP_FALL_DOWN/2) );
- break;
- case QUEEN_SWIPE:
- // ATE: set damage counter...
- pSoldier->uiPendingActionData1 = 0;
- break;
- case CLIMBDOWNROOF:
- // disable sight
- gTacticalStatus.uiFlags |= DISALLOW_SIGHT;
- DeductPoints( pSoldier, AP_CLIMBOFFROOF, BP_CLIMBOFFROOF );
- break;
- case CLIMBUPROOF:
- // disable sight
- gTacticalStatus.uiFlags |= DISALLOW_SIGHT;
- DeductPoints( pSoldier, AP_CLIMBROOF, BP_CLIMBROOF );
- break;
- case JUMP_OVER_BLOCKING_PERSON:
-
- // Set path....
- {
- UINT16 usNewGridNo;
- DeductPoints( pSoldier, AP_JUMP_OVER, BP_JUMP_OVER );
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( pSoldier->bDirection ) );
- usNewGridNo = NewGridNo( (UINT16)usNewGridNo, DirectionInc( pSoldier->bDirection ) );
- pSoldier->usPathDataSize = 0;
- pSoldier->usPathIndex = 0;
- pSoldier->usPathingData[ pSoldier->usPathDataSize ] = pSoldier->bDirection;
- pSoldier->usPathDataSize++;
- pSoldier->usPathingData[ pSoldier->usPathDataSize ] = pSoldier->bDirection;
- pSoldier->usPathDataSize++;
- pSoldier->sFinalDestination = usNewGridNo;
- // Set direction
- EVENT_InternalSetSoldierDestination( pSoldier, pSoldier->usPathingData[ pSoldier->usPathIndex ], FALSE, JUMP_OVER_BLOCKING_PERSON );
- }
- break;
-
- case GENERIC_HIT_STAND:
- case GENERIC_HIT_CROUCH:
- case STANDING_BURST_HIT:
- case ADULTMONSTER_HIT:
- case ADULTMONSTER_DYING:
- case COW_HIT:
- case COW_DYING:
- case BLOODCAT_HIT:
- case BLOODCAT_DYING:
- case WATER_HIT:
- case WATER_DIE:
- case DEEP_WATER_HIT:
- case DEEP_WATER_DIE:
- case RIFLE_STAND_HIT:
- case LARVAE_HIT:
- case LARVAE_DIE:
- case QUEEN_HIT:
- case QUEEN_DIE:
- case INFANT_HIT:
- case INFANT_DIE:
- case CRIPPLE_HIT:
- case CRIPPLE_DIE:
- case CRIPPLE_DIE_FLYBACK:
- case ROBOTNW_HIT:
- case ROBOTNW_DIE:
- // Set getting hit flag to TRUE
- pSoldier->fGettingHit = TRUE;
- break;
- case CHARIOTS_OF_FIRE:
- case BODYEXPLODING:
- // Merc on fire!
- pSoldier->uiPendingActionData1 = PlaySoldierJA2Sample( pSoldier->ubID, ( FIRE_ON_MERC ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 5, SoundDir( pSoldier->sGridNo ), TRUE );
- break;
- }
- }
- // Remove old animation profile
- HandleAnimationProfile( pSoldier, pSoldier->usAnimState, TRUE );
- // From animation control, set surface
- if ( SetSoldierAnimationSurface( pSoldier, usNewState ) == FALSE )
- {
- return( FALSE );
- }
- // Set state
- pSoldier->usOldAniState = pSoldier->usAnimState;
- pSoldier->sOldAniCode = pSoldier->usAniCode;
- // Change state value!
- pSoldier->usAnimState = usNewState;
- pSoldier->sZLevelOverride = -1;
- if ( !( pSoldier->uiStatusFlags & SOLDIER_LOCKPENDINGACTIONCOUNTER ) )
- {
- //ATE Cancel ANY pending action...
- if ( pSoldier->ubPendingActionAnimCount > 0 && ( gAnimControl[ pSoldier->usOldAniState ].uiFlags & ANIM_MOVING ) )
- {
- // Do some special things for some actions
- switch( pSoldier->ubPendingAction )
- {
- case MERC_GIVEITEM:
- // Unset target as enaged
- MercPtrs[ pSoldier->uiPendingActionData4 ]->uiStatusFlags &= (~SOLDIER_ENGAGEDINACTION);
- break;
- }
- pSoldier->ubPendingAction = NO_PENDING_ACTION;
- }
- else
- {
- // Increment this for almost all animations except some movement ones...
- // That's because this represents ANY animation other than the one we began when the pending action was started
- // ATE: Added to ignore this count if we are waiting for someone to move out of our way...
- if ( usNewState != START_SWAT && usNewState != END_SWAT && !( gAnimControl[ usNewState ].uiFlags & ANIM_NOCHANGE_PENDINGCOUNT ) && !pSoldier->fDelayedMovement && !( pSoldier->uiStatusFlags & SOLDIER_ENGAGEDINACTION ) )
- {
- pSoldier->ubPendingActionAnimCount++;
- }
- }
- }
- // Set new animation profile
- HandleAnimationProfile( pSoldier, usNewState, FALSE );
- // Reset some animation values
- pSoldier->fForceShade = FALSE;
- CheckForFreeupFromHit( pSoldier, uiOldAnimFlags, uiNewAnimFlags, pSoldier->usOldAniState, usNewState );
- // CHECK IF WE ARE AT AN IDLE ACTION
- #if 0
- if ( gAnimControl[ usNewState ].uiFlags & ANIM_IDLE )
- {
- pSoldier->bAction = ACTION_DONE;
- }
- else
- {
- pSoldier->bAction = ACTION_BUSY;
- }
- #endif
- // Set current frame
- pSoldier->usAniCode = usStartingAniCode;
- // ATE; For some animations that could use some variations, do so....
- if (usNewState == CHARIOTS_OF_FIRE || usNewState == BODYEXPLODING )
- {
- pSoldier->usAniCode = (UINT16)( Random( 10 ) );
- }
- // ATE: Default to first frame....
- // Will get changed ( probably ) by AdjustToNextAnimationFrame()
- ConvertAniCodeToAniFrame( pSoldier, (INT16)( 0 ) );
- // Set delay speed
- SetSoldierAniSpeed( pSoldier );
- // Reset counters
- RESETTIMECOUNTER( pSoldier->UpdateCounter, pSoldier->sAniDelay );
-
- // Adjust to new animation frame ( the first one )
- AdjustToNextAnimationFrame( pSoldier );
- // Setup offset information for UI above guy
- SetSoldierLocatorOffsets( pSoldier );
- // If our own guy...
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- // Are we stationary?
- if ( gAnimControl[ usNewState ].uiFlags & ANIM_STATIONARY )
- {
- // Position light....
- // SetCheckSoldierLightFlag( pSoldier );
- }
- else
- {
- // Hide light.....
- // DeleteSoldierLight( pSoldier );
- }
- }
- // If we are certain animations, reload palette
- if ( usNewState == VEHICLE_DIE || usNewState == CHARIOTS_OF_FIRE || usNewState == BODYEXPLODING )
- {
- CreateSoldierPalettes( pSoldier );
- }
- // ATE: if the old animation was a movement, and new is not, play sound...
- // OK, play final footstep sound...
- if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
- {
- if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STATIONARY ) &&
- ( gAnimControl[ pSoldier->usOldAniState ].uiFlags & ANIM_MOVING ) )
- {
- PlaySoldierFootstepSound( pSoldier );
- }
- }
- // Free up from stance change
- FreeUpNPCFromStanceChange( pSoldier );
- return( TRUE );
- }
- void InternalRemoveSoldierFromGridNo( SOLDIERTYPE *pSoldier, BOOLEAN fForce )
- {
- INT8 bDir;
- INT32 iGridNo;
- if((pSoldier->sGridNo!=NO_MAP_POS) )
- {
- if ( pSoldier->bInSector || fForce )
- {
- // Remove from world ( old pos )
- RemoveMerc( pSoldier->sGridNo, pSoldier, FALSE );
- HandleAnimationProfile( pSoldier, pSoldier->usAnimState, TRUE );
- // Remove records of this guy being adjacent
- for (bDir = 0; bDir < NUM_WORLD_DIRECTIONS; bDir++)
- {
- iGridNo = pSoldier->sGridNo + DirIncrementer[ bDir ];
- if( iGridNo >= 0 && iGridNo < WORLD_MAX )
- {
- gpWorldLevelData[ iGridNo ].ubAdjacentSoldierCnt--;
- }
- }
- HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, FALSE , FALSE );
- // Remove reseved movement value
- UnMarkMovementReserved( pSoldier );
- HandleCrowShadowRemoveGridNo( pSoldier );
- // Reset gridno...
- pSoldier->sGridNo = NO_MAP_POS;
- }
- }
- }
- void RemoveSoldierFromGridNo( SOLDIERTYPE *pSoldier )
- {
- InternalRemoveSoldierFromGridNo( pSoldier, FALSE );
- }
- void EVENT_InternalSetSoldierPosition( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos ,BOOLEAN fUpdateDest, BOOLEAN fUpdateFinalDest, BOOLEAN fForceRemove )
- {
- INT16 sNewGridNo;
- // Not if we're dead!
- if ( ( pSoldier->uiStatusFlags & SOLDIER_DEAD ) )
- {
- return;
- }
- // Set new map index
- sNewGridNo = GETWORLDINDEXFROMWORLDCOORDS(dNewYPos, dNewXPos );
- if ( fUpdateDest )
- {
- pSoldier->sDestination = sNewGridNo;
- }
- if ( fUpdateFinalDest )
- {
- pSoldier->sFinalDestination = sNewGridNo;
- }
- // Copy old values
- pSoldier->dOldXPos = pSoldier->dXPos;
- pSoldier->dOldYPos = pSoldier->dYPos;
- // Set New pos
- pSoldier->dXPos = dNewXPos;
- pSoldier->dYPos = dNewYPos;
- pSoldier->sX = (INT16)dNewXPos;
- pSoldier->sY = (INT16)dNewYPos;
- HandleCrowShadowNewPosition( pSoldier );
- SetSoldierGridNo( pSoldier, sNewGridNo, fForceRemove );
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- if ( gGameSettings.fOptions[ TOPTION_MERC_ALWAYS_LIGHT_UP ] )
- {
- SetCheckSoldierLightFlag( pSoldier );
- }
- }
- // ATE: Mirror calls if we are a vehicle ( for all our passengers )
- UpdateAllVehiclePassengersGridNo( pSoldier );
- }
- void EVENT_SetSoldierPosition( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos )
- {
- EVENT_InternalSetSoldierPosition( pSoldier, dNewXPos, dNewYPos ,TRUE, TRUE, FALSE );
- }
- void EVENT_SetSoldierPositionForceDelete( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos )
- {
- EVENT_InternalSetSoldierPosition( pSoldier, dNewXPos, dNewYPos ,TRUE, TRUE, TRUE );
- }
- void EVENT_SetSoldierPositionAndMaybeFinalDest( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos, BOOLEAN fUpdateFinalDest )
- {
- EVENT_InternalSetSoldierPosition( pSoldier, dNewXPos, dNewYPos ,TRUE, fUpdateFinalDest, FALSE );
- }
- void EVENT_SetSoldierPositionAndMaybeFinalDestAndMaybeNotDestination( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos, BOOLEAN fUpdateDest, BOOLEAN fUpdateFinalDest )
- {
- EVENT_InternalSetSoldierPosition( pSoldier, dNewXPos, dNewYPos ,fUpdateDest, fUpdateFinalDest, FALSE );
- }
- void InternalSetSoldierHeight( SOLDIERTYPE *pSoldier, FLOAT dNewHeight, BOOLEAN fUpdateLevel )
- {
- INT8 bOldLevel = pSoldier->bLevel;
- pSoldier->dHeightAdjustment = dNewHeight;
- pSoldier->sHeightAdjustment = (INT16)pSoldier->dHeightAdjustment;
- if ( !fUpdateLevel )
- {
- return;
- }
- if ( pSoldier->sHeightAdjustment > 0 )
- {
- pSoldier->bLevel = SECOND_LEVEL;
- ApplyTranslucencyToWalls((INT16)(pSoldier->dXPos/CELL_X_SIZE), (INT16)(pSoldier->dYPos/CELL_Y_SIZE));
- //LightHideTrees((INT16)(pSoldier->dXPos/CELL_X_SIZE), (INT16)(pSoldier->dYPos/CELL_Y_SIZE));
- //ConcealAllWalls();
- //pSoldier->pLevelNode->ubShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubShadeLevel;
- //pSoldier->pLevelNode->ubSumLights=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubSumLights;
- //pSoldier->pLevelNode->ubMaxLights=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubMaxLights;
- //pSoldier->pLevelNode->ubNaturalShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubNaturalShadeLevel;
- }
- else
- {
- pSoldier->bLevel = FIRST_LEVEL;
- //pSoldier->pLevelNode->ubShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubShadeLevel;
- //pSoldier->pLevelNode->ubSumLights=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubSumLights;
- //pSoldier->pLevelNode->ubMaxLights=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubMaxLights;
- //pSoldier->pLevelNode->ubNaturalShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubNaturalShadeLevel;
- }
- if ( bOldLevel == 0 && pSoldier->bLevel == 0 )
- {
- }
- else
- {
- // Show room at new level
- //HideRoom( pSoldier->sGridNo, pSoldier );
- }
- }
- void SetSoldierHeight( SOLDIERTYPE *pSoldier, FLOAT dNewHeight )
- {
- InternalSetSoldierHeight( pSoldier, dNewHeight, TRUE );
- }
- void SetSoldierGridNo( SOLDIERTYPE *pSoldier, INT16 sNewGridNo, BOOLEAN fForceRemove )
- {
- BOOLEAN fInWaterValue;
- INT8 bDir;
- INT32 cnt;
- SOLDIERTYPE * pEnemy;
- //INT16 sX, sY, sWorldX, sZLevel;
- // Not if we're dead!
- if ( ( pSoldier->uiStatusFlags & SOLDIER_DEAD ) )
- {
- return;
- }
- if ( sNewGridNo != pSoldier->sGridNo || pSoldier->pLevelNode == NULL )
- {
- // Check if we are moving AND this is our next dest gridno....
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING | ANIM_SPECIALMOVE ) )
- {
- if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
- {
- if ( sNewGridNo != pSoldier->sDestination )
- {
- // THIS MUST be our new one......MAKE IT SO
- sNewGridNo = pSoldier->sDestination;
- }
- // Now check this baby....
- if ( sNewGridNo == pSoldier->sGridNo )
- {
- return;
- }
- }
- }
- pSoldier->sOldGridNo = pSoldier->sGridNo;
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- SetPositionSndGridNo( pSoldier->iPositionSndID, sNewGridNo );
- }
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- InternalRemoveSoldierFromGridNo( pSoldier, fForceRemove );
- }
- // CHECK IF OUR NEW GIRDNO IS VALID,IF NOT DONOT SET!
- if ( !GridNoOnVisibleWorldTile( sNewGridNo ) )
- {
- pSoldier->sGridNo = sNewGridNo;
- return;
- }
- // Alrighty, update UI for this guy, if he's the selected guy...
- if ( gusSelectedSoldier == pSoldier->ubID )
- {
- if ( guiCurrentEvent == C_WAIT_FOR_CONFIRM )
- {
- // Update path!
- gfPlotNewMovement = TRUE;
- }
- }
- // Reset some flags for optimizations..
- pSoldier->sWalkToAttackGridNo = NOWHERE;
- // ATE: Make sure!
- // RemoveMerc( pSoldier->sGridNo, pSoldier, FALSE );
- pSoldier->sGridNo = sNewGridNo;
- // OK, check for special code to close door...
- if ( pSoldier->bEndDoorOpenCode == 2 )
- {
- pSoldier->bEndDoorOpenCode = 0;
- HandleDoorChangeFromGridNo( pSoldier, pSoldier->sEndDoorOpenCodeData, FALSE );
- }
- // OK, Update buddy's strategic insertion code....
- pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
- pSoldier->usStrategicInsertionData = sNewGridNo;
-
- // Remove this gridno as a reserved place!
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- UnMarkMovementReserved( pSoldier );
- }
- if ( pSoldier->sInitialGridNo == 0 )
- {
- pSoldier->sInitialGridNo = sNewGridNo;
- pSoldier->usPatrolGrid[0] = sNewGridNo;
- }
- // Add records of this guy being adjacent
- for (bDir = 0; bDir < NUM_WORLD_DIRECTIONS; bDir++)
- {
- gpWorldLevelData[ pSoldier->sGridNo + DirIncrementer[ bDir ] ].ubAdjacentSoldierCnt++;
- }
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- DropSmell( pSoldier );
- }
- // HANDLE ANY SPECIAL RENDERING SITUATIONS
- pSoldier->sZLevelOverride = -1;
- // If we are over a fence ( hopping ), make us higher!
- if ( IsJumpableFencePresentAtGridno( sNewGridNo ) )
- {
- //sX = MapX( sNewGridNo );
- //sY = MapY( sNewGridNo );
- //GetWorldXYAbsoluteScreenXY( sX, sY, &sWorldX, &sZLevel);
- //pSoldier->sZLevelOverride = (sZLevel*Z_SUBLAYERS)+ROOF_Z_LEVEL;
- pSoldier->sZLevelOverride = TOPMOST_Z_LEVEL;
- }
- // Add/ remove tree if we are near it
- // CheckForFullStructures( pSoldier );
- // Add merc at new pos
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- AddMercToHead( pSoldier->sGridNo, pSoldier, TRUE );
- // If we are in the middle of climbing the roof!
- if ( pSoldier->usAnimState == CLIMBUPROOF )
- {
- if(pSoldier->iLight!=(-1))
- LightSpriteRoofStatus(pSoldier->iLight, TRUE );
- }
- else if ( pSoldier->usAnimState == CLIMBDOWNROOF )
- {
- if(pSoldier->iLight!=(-1))
- LightSpriteRoofStatus(pSoldier->iLight, FALSE );
- }
- //JA2Gold:
- //if the player wants the merc to cast the fake light AND it is night
- if( pSoldier->bTeam != OUR_TEAM || gGameSettings.fOptions[ TOPTION_MERC_CASTS_LIGHT ] && NightTime() )
- {
- if ( pSoldier->bLevel > 0 && gpWorldLevelData[pSoldier->sGridNo].pRoofHead != NULL )
- {
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubShadeLevel;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubSumLights=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubSumLights;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubMaxLights=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubMaxLights;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubNaturalShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pRoofHead->ubNaturalShadeLevel;
- }
- else
- {
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubShadeLevel;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubSumLights=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubSumLights;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubMaxLights=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubMaxLights;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubNaturalShadeLevel=gpWorldLevelData[pSoldier->sGridNo].pLandHead->ubNaturalShadeLevel;
- }
- }
- ///HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, TRUE, FALSE );
- HandleAnimationProfile( pSoldier, pSoldier->usAnimState, FALSE );
- HandleCrowShadowNewGridNo( pSoldier );
- }
- pSoldier->bOldOverTerrainType = pSoldier->bOverTerrainType;
- pSoldier->bOverTerrainType = GetTerrainType( pSoldier->sGridNo );
- // OK, check that our animation is up to date!
- // Check our water value
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- fInWaterValue = MercInWater( pSoldier );
- // ATE: If ever in water MAKE SURE WE WALK AFTERWOODS!
- if ( fInWaterValue )
- {
- pSoldier->usUIMovementMode = WALKING;
- }
- if ( fInWaterValue != pSoldier->fPrevInWater )
- {
- //Update Animation data
- SetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
-
- // Update flag
- pSoldier->fPrevInWater = fInWaterValue;
- // Update sound...
- if ( fInWaterValue )
- {
- PlaySoldierJA2Sample( pSoldier->ubID, ENTER_WATER_1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
- }
- else
- {
- // ATE: Check if we are going from water to land - if so, resume
- // with regular movement mode...
- EVENT_InitNewSoldierAnim( pSoldier, pSoldier->usUIMovementMode, 0 , FALSE );
- }
-
- }
-
- // OK, If we were not in deep water but we are now, handle deep animations!
- if ( pSoldier->bOverTerrainType == DEEP_WATER && pSoldier->bOldOverTerrainType != DEEP_WATER )
- {
- // Based on our current animation, change!
- switch( pSoldier->usAnimState )
- {
- case WALKING:
- case RUNNING:
- // IN deep water, swim!
- // Make transition from low to deep
- EVENT_InitNewSoldierAnim( pSoldier, LOW_TO_DEEP_WATER, 0 , FALSE );
- pSoldier->usPendingAnimation = DEEP_WATER_SWIM;
- PlayJA2Sample( ENTER_DEEP_WATER_1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
- }
- }
- // Damage water if in deep water....
- if ( pSoldier->bOverTerrainType == MED_WATER || pSoldier->bOverTerrainType == DEEP_WATER )
- {
- WaterDamage( pSoldier );
- }
- // OK, If we were in deep water but we are NOT now, handle mid animations!
- if ( pSoldier->bOverTerrainType != DEEP_WATER && pSoldier->bOldOverTerrainType == DEEP_WATER )
- {
- // Make transition from low to deep
- EVENT_InitNewSoldierAnim( pSoldier, DEEP_TO_LOW_WATER, 0 , FALSE );
- pSoldier->usPendingAnimation = pSoldier->usUIMovementMode;
- }
- }
- // are we now standing in tear gas without a decently working gas mask?
- if ( GetSmokeEffectOnTile( sNewGridNo, pSoldier->bLevel ) )
- {
- BOOLEAN fSetGassed = TRUE;
- // If we have a functioning gas mask...
- if ( pSoldier->inv[ HEAD1POS ].usItem == GASMASK && pSoldier->inv[ HEAD1POS ].bStatus[ 0 ] >= GASMASK_MIN_STATUS )
- {
- fSetGassed = FALSE;
- }
- if ( pSoldier->inv[ HEAD2POS ].usItem == GASMASK && pSoldier->inv[ HEAD2POS ].bStatus[ 0 ] >= GASMASK_MIN_STATUS )
- {
- fSetGassed = FALSE;
- }
- if ( fSetGassed )
- {
- pSoldier->uiStatusFlags |= SOLDIER_GASSED;
- }
- }
- if ( pSoldier->bTeam == gbPlayerNum && pSoldier->bStealthMode )
- {
- // Merc got to a new tile by "sneaking". Did we theoretically sneak
- // past an enemy?
- if ( pSoldier->bOppCnt > 0 ) // opponents in sight
- {
- // check each possible enemy
- for ( cnt = 0; cnt < MAX_NUM_SOLDIERS; cnt++ )
- {
- pEnemy = MercPtrs[ cnt ];
- // if this guy is here and alive enough to be looking for us
- if ( pEnemy->bActive && pEnemy->bInSector && ( pEnemy->bLife >= OKLIFE ) )
- {
- // no points for sneaking by the neutrals & friendlies!!!
- if ( !pEnemy->bNeutral && ( pSoldier->bSide != pEnemy->bSide ) && (pEnemy->ubBodyType != COW && pEnemy->ubBodyType != CROW) )
- {
- // if we SEE this particular oppponent, and he DOESN'T see us... and he COULD see us...
- if ( (pSoldier->bOppList[ cnt ] == SEEN_CURRENTLY) &&
- pEnemy->bOppList[ pSoldier->ubID ] != SEEN_CURRENTLY &&
- PythSpacesAway( pSoldier->sGridNo, pEnemy->sGridNo ) < DistanceVisible( pEnemy, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, pSoldier->sGridNo, pSoldier->bLevel ) )
- {
- // AGILITY (5): Soldier snuck 1 square past unaware enemy
- StatChange( pSoldier, AGILAMT, 5, FALSE );
- // Keep looping, we'll give'em 1 point for EACH such enemy!
- }
- }
- }
- }
- }
- }
- // Adjust speed based on terrain, etc
- SetSoldierAniSpeed( pSoldier );
- }
- else
- {
- int i = 0;
- }
- }
- void EVENT_FireSoldierWeapon( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo )
- {
- INT16 sTargetXPos, sTargetYPos;
- BOOLEAN fDoFireRightAway = FALSE;
- // CANNOT BE SAME GRIDNO!
- if ( pSoldier->sGridNo == sTargetGridNo )
- {
- return;
- }
- if ( pSoldier->ubID == 33 )
- {
- int i = 0;
- }
- // Increment the number of people busy doing stuff because of an attack
- //if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
- //{
- gTacticalStatus.ubAttackBusyCount++;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting attack, attack count now %d", gTacticalStatus.ubAttackBusyCount) );
- //}
- // Set soldier's target gridno
- // This assignment was redundent because it's already set in
- // the actual event call
- pSoldier->sTargetGridNo = sTargetGridNo;
- //pSoldier->sLastTarget = sTargetGridNo;
- pSoldier->ubTargetID = WhoIsThere2( sTargetGridNo, pSoldier->bTargetLevel );
- if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass & IC_GUN)
- {
- if (pSoldier->bDoBurst)
- {
- // Set the TOTAL number of bullets to be fired
- // Can't shoot more bullets than we have in our magazine!
- pSoldier->bBulletsLeft = __min( Weapon[pSoldier->inv[ pSoldier->ubAttackingHand ].usItem].ubShotsPerBurst, pSoldier->inv[ pSoldier->ubAttackingHand ].ubGunShotsLeft );
- }
- else if ( IsValidSecondHandShot( pSoldier ) )
- {
- // two-pistol attack - two bullets!
- pSoldier->bBulletsLeft = 2;
- }
- else
- {
- pSoldier->bBulletsLeft = 1;
- }
- if (pSoldier->inv[ pSoldier->ubAttackingHand ].ubGunAmmoType == AMMO_BUCKSHOT)
- {
- pSoldier->bBulletsLeft *= NUM_BUCKSHOT_PELLETS;
- }
- }
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting attack, bullets left %d", pSoldier->bBulletsLeft) );
-
- // Convert our grid-not into an XY
- ConvertGridNoToXY( sTargetGridNo, &sTargetXPos, &sTargetYPos );
- // Change to fire animation
- // Ready weapon
- SoldierReadyWeapon( pSoldier, sTargetXPos, sTargetYPos, FALSE );
-
- // IF WE ARE AN NPC, SLIDE VIEW TO SHOW WHO IS SHOOTING
- {
- //if ( pSoldier->fDoSpread )
- //{
- // If we are spreading burst, goto right away!
- //EVENT_InitNewSoldierAnim( pSoldier, SelectFireAnimation( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ), 0, FALSE );
- //}
- // else
- {
- if (pSoldier->uiStatusFlags & SOLDIER_MONSTER )
- {
- // Force our direction!
- EVENT_SetSoldierDirection( pSoldier, pSoldier->bDesiredDirection );
- EVENT_InitNewSoldierAnim( pSoldier, SelectFireAnimation( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ), 0, FALSE );
- }
- else
- {
- // IF WE ARE IN REAl-TIME, FIRE IMMEDIATELY!
- if ( ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
- {
- //fDoFireRightAway = TRUE;
- }
- // Check if our weapon has no intermediate anim...
- switch( pSoldier->inv[ HANDPOS ].usItem )
- {
- case ROCKET_LAUNCHER:
- case MORTAR:
- case GLAUNCHER:
- fDoFireRightAway = TRUE;
- break;
- }
- if ( fDoFireRightAway )
- {
- // Set to true so we don't get toasted twice for APs..
- pSoldier->fDontUnsetLastTargetFromTurn = TRUE;
- // Make sure we don't try and do fancy prone turning.....
- pSoldier->fTurningFromPronePosition = FALSE;
- // Force our direction!
- EVENT_SetSoldierDirection( pSoldier, pSoldier->bDesiredDirection );
- EVENT_InitNewSoldierAnim( pSoldier, SelectFireAnimation( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ), 0, FALSE );
- }
- else
- {
- // Set flag indicating we are about to shoot once destination direction is hit
- pSoldier->fTurningToShoot = TRUE;
- if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bVisible != -1)
- {
- LocateSoldier( pSoldier->ubID, DONTSETLOCATOR );
- }
- }
- }
- }
- }
- }
- //gAnimControl[ pSoldier->usAnimState ].ubEndHeight
- // ChangeSoldierState( pSoldier, SHOOT_RIFLE_STAND, 0 , FALSE );
- UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight )
- {
- INT16 sDist;
- UINT16 usItem;
- FLOAT dTargetX;
- FLOAT dTargetY;
- FLOAT dTargetZ;
- BOOLEAN fDoLowShot = FALSE;
- //Do different things if we are a monster
- if (pSoldier->uiStatusFlags & SOLDIER_MONSTER)
- {
- switch( pSoldier->ubBodyType )
- {
- case ADULTFEMALEMONSTER:
- case AM_MONSTER:
- case YAF_MONSTER:
- case YAM_MONSTER:
- return( MONSTER_SPIT_ATTACK );
- break;
- case LARVAE_MONSTER:
- break;
- case INFANT_MONSTER:
- return( INFANT_ATTACK );
- break;
- case QUEENMONSTER:
- return( QUEEN_SPIT );
- break;
- }
- return( TRUE );
- }
- if ( pSoldier->ubBodyType == ROBOTNOWEAPON )
- {
- if ( pSoldier->bDoBurst > 0 )
- {
- return( ROBOT_BURST_SHOOT );
- }
- else
- {
- return( ROBOT_SHOOT );
- }
- }
- // Check for rocket laucncher....
- if ( pSoldier->inv[ HANDPOS ].usItem == ROCKET_LAUNCHER )
- {
- return( SHOOT_ROCKET );
- }
- // Check for rocket laucncher....
- if ( pSoldier->inv[ HANDPOS ].usItem == MORTAR )
- {
- return( SHOOT_MORTAR );
- }
- // Check for tank cannon
- if ( pSoldier->inv[ HANDPOS ].usItem == TANK_CANNON )
- {
- return( TANK_SHOOT );
- }
- if ( pSoldier->ubBodyType == TANK_NW || pSoldier->ubBodyType == TANK_NE )
- {
- return( TANK_BURST );
- }
- // Determine which animation to do...depending on stance and gun in hand...
- switch ( ubHeight )
- {
- case ANIM_STAND:
- usItem = pSoldier->inv[ HANDPOS ].usItem;
- // CHECK 2ND HAND!
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- // Increment the number of people busy doing stuff because of an attack
- //gTacticalStatus.ubAttackBusyCount++;
- //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting attack with 2 guns, attack count now %d", gTacticalStatus.ubAttackBusyCount) );
- return( SHOOT_DUAL_STAND );
- }
- else
- {
- // OK, while standing check distance away from target, and shoot low if we should!
- sDist = PythSpacesAway( pSoldier->sGridNo, pSoldier->sTargetGridNo );
- //ATE: OK, SEE WERE WE ARE TARGETING....
- GetTargetWorldPositions( pSoldier, pSoldier->sTargetGridNo, &dTargetX, &dTargetY, &dTargetZ );
- //CalculateSoldierZPos( pSoldier, FIRING_POS, &dFirerZ );
- if ( sDist <= 2 && dTargetZ <= 100 )
- {
- fDoLowShot = TRUE;
- }
- // ATE: Made distence away long for psitols such that they never use this....
- //if ( !(Item[ usItem ].fFlags & ITEM_TWO_HANDED) )
- //{
- // fDoLowShot = FALSE;
- //}
- // Don't do any low shots if in water
- if ( MercInWater( pSoldier ) )
- {
- fDoLowShot = FALSE;
- }
-
- if ( pSoldier->bDoBurst > 0 )
- {
- if ( fDoLowShot )
- {
- return( FIRE_BURST_LOW_STAND );
- }
- else
- {
- return( STANDING_BURST );
- }
- }
- else
- {
- if ( fDoLowShot )
- {
- return( FIRE_LOW_STAND );
- }
- else
- {
- return( SHOOT_RIFLE_STAND );
- }
- }
- }
- break;
- case ANIM_PRONE:
- if ( pSoldier->bDoBurst > 0 )
- {
- // pSoldier->fBurstCompleted = FALSE;
- return( PRONE_BURST );
- }
- else
- {
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( SHOOT_DUAL_PRONE );
- }
- else
- {
- return( SHOOT_RIFLE_PRONE );
- }
- }
- break;
- case ANIM_CROUCH:
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- // Increment the number of people busy doing stuff because of an attack
- //gTacticalStatus.ubAttackBusyCount++;
- //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting attack with 2 guns, attack count now %d", gTacticalStatus.ubAttackBusyCount) );
- return( SHOOT_DUAL_CROUCH );
- }
- else
- {
- if ( pSoldier->bDoBurst > 0 )
- {
- // pSoldier->fBurstCompleted = FALSE;
- return( CROUCHED_BURST );
- }
- else
- {
- return( SHOOT_RIFLE_CROUCH );
- }
- }
- break;
- default:
- AssertMsg( FALSE, String( "SelectFireAnimation: ERROR - Invalid height %d", ubHeight ) );
- break;
- }
- // If here, an internal error has occured!
- Assert( FALSE );
- return ( 0 );
- }
- UINT16 GetMoveStateBasedOnStance( SOLDIERTYPE *pSoldier, UINT8 ubStanceHeight )
- {
- // Determine which animation to do...depending on stance and gun in hand...
- switch ( ubStanceHeight )
- {
- case ANIM_STAND:
- if ( pSoldier->fUIMovementFast && !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
- {
- return( RUNNING );
- }
- else
- {
- return( WALKING );
- }
- break;
- case ANIM_PRONE:
- if ( pSoldier->fUIMovementFast )
- {
- return( CRAWLING );
- }
- else
- {
- return( CRAWLING );
- }
- break;
- case ANIM_CROUCH:
- if ( pSoldier->fUIMovementFast )
- {
- return( SWATTING );
- }
- else
- {
- return( SWATTING );
- }
- break;
- default:
- AssertMsg( FALSE, String( "GetMoveStateBasedOnStance: ERROR - Invalid height %d", ubStanceHeight ) );
- break;
- }
- // If here, an internal error has occured!
- Assert( FALSE );
- return ( 0 );
- }
- void SelectFallAnimation( SOLDIERTYPE *pSoldier )
- {
- // Determine which animation to do...depending on stance and gun in hand...
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- EVENT_InitNewSoldierAnim( pSoldier, FLYBACK_HIT, 0 , FALSE );
- break;
- case ANIM_PRONE:
- EVENT_InitNewSoldierAnim( pSoldier, FLYBACK_HIT, 0 , FALSE );
- break;
- }
- }
- BOOLEAN SoldierReadyWeapon( SOLDIERTYPE *pSoldier, INT16 sTargetXPos, INT16 sTargetYPos, BOOLEAN fEndReady )
- {
- INT16 sFacingDir;
- sFacingDir = GetDirectionFromXY( sTargetXPos , sTargetYPos, pSoldier );
- return( InternalSoldierReadyWeapon( pSoldier, (INT8)sFacingDir, fEndReady ) );
- }
- BOOLEAN InternalSoldierReadyWeapon( SOLDIERTYPE *pSoldier, UINT8 sFacingDir, BOOLEAN fEndReady )
- {
- UINT16 usAnimState;
- BOOLEAN fReturnVal = FALSE;
- // Handle monsters differently
- if (pSoldier->uiStatusFlags & SOLDIER_MONSTER)
- {
- if ( !fEndReady )
- {
- EVENT_SetSoldierDesiredDirection( pSoldier, sFacingDir );
- }
- return( FALSE );
- }
- usAnimState = PickSoldierReadyAnimation( pSoldier, fEndReady );
- if ( usAnimState != INVALID_ANIMATION )
- {
- EVENT_InitNewSoldierAnim( pSoldier, usAnimState, 0 , FALSE );
- fReturnVal = TRUE;
- }
- if ( !fEndReady )
- {
- // Ready direction for new facing direction
- if ( usAnimState == INVALID_ANIMATION )
- {
- usAnimState = pSoldier->usAnimState;
- }
- EVENT_InternalSetSoldierDesiredDirection( pSoldier, sFacingDir, FALSE, usAnimState );
- // Check if facing dir is different from ours and change direction if so!
- //if ( sFacingDir != pSoldier->bDirection )
- //{
- // DeductPoints( pSoldier, AP_CHANGE_FACING, 0 );
- //}//
- }
- return( fReturnVal );
- }
- UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady )
- {
- // Invalid animation if nothing in our hands
- if ( pSoldier->inv[ HANDPOS ].usItem == NOTHING )
- {
- return( INVALID_ANIMATION );
- }
- if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- return( INVALID_ANIMATION );
- }
- if ( pSoldier->ubBodyType == ROBOTNOWEAPON )
- {
- return( INVALID_ANIMATION );
- }
- // Check if we have a gun.....
- if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass != IC_GUN && pSoldier->inv[ HANDPOS ].usItem != GLAUNCHER )
- {
- return( INVALID_ANIMATION );
- }
- if ( pSoldier->inv[ HANDPOS ].usItem == ROCKET_LAUNCHER )
- {
- return( INVALID_ANIMATION );
- }
- if ( pSoldier->ubBodyType == TANK_NW || pSoldier->ubBodyType == TANK_NE )
- {
- return( INVALID_ANIMATION );
- }
- if ( fEndReady )
- {
- // IF our gun is already drawn, do not change animation, just direction
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE ))
- {
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // CHECK 2ND HAND!
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( END_DUAL_STAND );
- }
- else
- {
- return( END_RIFLE_STAND );
- }
- break;
- case ANIM_PRONE:
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( END_DUAL_PRONE );
- }
- else
- {
- return( END_RIFLE_PRONE );
- }
- break;
- case ANIM_CROUCH:
- // CHECK 2ND HAND!
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( END_DUAL_CROUCH );
- }
- else
- {
- return( END_RIFLE_CROUCH );
- }
- break;
- }
- }
- }
- else
- {
- // IF our gun is already drawn, do not change animation, just direction
- if ( !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE ) ) )
- {
- {
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // CHECK 2ND HAND!
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( READY_DUAL_STAND );
- }
- else
- {
- return( READY_RIFLE_STAND );
- }
- break;
- case ANIM_PRONE:
- // Go into crouch, turn, then go into prone again
- //ChangeSoldierStance( pSoldier, ANIM_CROUCH );
- //pSoldier->ubDesiredHeight = ANIM_PRONE;
- //ChangeSoldierState( pSoldier, PRONE_UP );
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( READY_DUAL_PRONE );
- }
- else
- {
- return( READY_RIFLE_PRONE );
- }
- break;
- case ANIM_CROUCH:
- // CHECK 2ND HAND!
- if ( IsValidSecondHandShot( pSoldier ) )
- {
- return( READY_DUAL_CROUCH );
- }
- else
- {
- return( READY_RIFLE_CROUCH );
- }
- break;
- }
- }
- }
- }
- return( INVALID_ANIMATION );
- }
- extern SOLDIERTYPE * FreeUpAttackerGivenTarget( UINT8 ubID, UINT8 ubTargetID );
- extern SOLDIERTYPE * ReduceAttackBusyGivenTarget( UINT8 ubID, UINT8 ubTargetID );
- // ATE: THIS FUNCTION IS USED FOR ALL SOLDIER TAKE DAMAGE FUNCTIONS!
- void EVENT_SoldierGotHit( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, INT16 sBreathLoss, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation, INT16 sSubsequent, INT16 sLocationGrid )
- {
- UINT8 ubCombinedLoss, ubVolume, ubReason;
- SOLDIERTYPE * pNewSoldier;
- ubReason = 0;
- // ATE: If we have gotten hit, but are still in our attack animation, reduce count!
- switch ( pSoldier->usAnimState )
- {
- case SHOOT_ROCKET:
- case SHOOT_MORTAR:
- case THROW_ITEM:
- case LOB_ITEM:
-
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - ATTACK ANIMATION %s ENDED BY HIT ANIMATION, Now %d", gAnimControl[ pSoldier->usAnimState ].zAnimStr, gTacticalStatus.ubAttackBusyCount ) );
- ReduceAttackBusyCount( pSoldier->ubID, FALSE );
- break;
- }
- // DO STUFF COMMON FOR ALL TYPES
- if ( ubAttackerID != NOBODY)
- {
- MercPtrs[ubAttackerID]->bLastAttackHit = TRUE;
- }
- // Set attacker's ID
- pSoldier->ubAttackerID = ubAttackerID;
- if ( !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
- {
- // Increment being attacked count
- pSoldier->bBeingAttackedCount++;
- }
- // if defender is a vehicle, there will be no hit animation played!
- if ( !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
- {
- // Increment the number of people busy doing stuff because of an attack (busy doing hit anim!)
- gTacticalStatus.ubAttackBusyCount++;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Person got hit, attack count now %d", gTacticalStatus.ubAttackBusyCount) );
- }
- // ATE; Save hit location info...( for later anim determination stuff )
- pSoldier->ubHitLocation = ubHitLocation;
- // handle morale for heavy damage attacks
- if ( sDamage > 25 )
- {
- if ( pSoldier->ubAttackerID != NOBODY && MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum )
- {
- HandleMoraleEvent( MercPtrs[ pSoldier->ubAttackerID ], MORALE_DID_LOTS_OF_DAMAGE, MercPtrs[ pSoldier->ubAttackerID ]->sSectorX, MercPtrs[ pSoldier->ubAttackerID ]->sSectorY, MercPtrs[ pSoldier->ubAttackerID ]->bSectorZ );
- }
- if (pSoldier->bTeam == gbPlayerNum)
- {
- HandleMoraleEvent( pSoldier, MORALE_TOOK_LOTS_OF_DAMAGE, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
- }
- }
- // SWITCH IN TYPE OF WEAPON
- if ( ubSpecial == FIRE_WEAPON_TOSSED_OBJECT_SPECIAL )
- {
- ubReason = TAKE_DAMAGE_OBJECT;
- }
- else if ( Item[ usWeaponIndex ].usItemClass & IC_TENTACLES )
- {
- ubReason = TAKE_DAMAGE_TENTACLES;
- }
- else if ( Item[ usWeaponIndex ].usItemClass & ( IC_GUN | IC_THROWING_KNIFE ) )
- {
- if ( ubSpecial == FIRE_WEAPON_SLEEP_DART_SPECIAL )
- {
- UINT32 uiChance;
- // put the drug in!
- pSoldier->bSleepDrugCounter = 10;
- uiChance = SleepDartSuccumbChance( pSoldier );
- if ( PreRandom( 100 ) < uiChance )
- {
- // succumb to the drug!
- sBreathLoss = (INT16)( pSoldier->bBreathMax * 100 );
- }
- }
- else if ( ubSpecial == FIRE_WEAPON_BLINDED_BY_SPIT_SPECIAL )
- {
- // blinded!!
- if ( (pSoldier->bBlindedCounter == 0) )
- {
- // say quote
- if (pSoldier->uiStatusFlags & SOLDIER_PC)
- {
- TacticalCharacterDialogue( pSoldier, QUOTE_BLINDED );
- }
- DecayIndividualOpplist( pSoldier );
- }
- // will always increase counter by at least 1
- pSoldier->bBlindedCounter += (sDamage / 8) + 1;
- // Dirty panel
- fInterfacePanelDirty = DIRTYLEVEL2;
- }
- sBreathLoss += BP_GET_HIT;
- ubReason = TAKE_DAMAGE_GUNFIRE;
- }
- else if ( Item[ usWeaponIndex ].usItemClass & IC_BLADE )
- {
- sBreathLoss = BP_GET_HIT;
- ubReason = TAKE_DAMAGE_BLADE;
- }
- else if ( Item[ usWeaponIndex ].usItemClass & IC_PUNCH )
- {
- // damage from hand-to-hand is 1/4 normal, 3/4 breath.. the sDamage value
- // is actually how much breath we'll take away
- sBreathLoss = sDamage * 100;
- sDamage = sDamage / PUNCH_REAL_DAMAGE_PORTION;
- if ( AreInMeanwhile() && gCurrentMeanwhileDef.ubMeanwhileID == INTERROGATION )
- {
- sBreathLoss = 0;
- sDamage /= 2;
- }
- ubReason = TAKE_DAMAGE_HANDTOHAND;
- }
- else if ( Item[ usWeaponIndex ].usItemClass & IC_EXPLOSV )
- {
- if ( usWeaponIndex == STRUCTURE_EXPLOSION )
- {
- ubReason = TAKE_DAMAGE_STRUCTURE_EXPLOSION;
- }
- else
- {
- ubReason = TAKE_DAMAGE_EXPLOSION;
- }
- }
- else
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Control: Weapon class not handled in SoldierGotHit( ) %d", usWeaponIndex ) );
- }
- // CJC: moved to after SoldierTakeDamage so that any quotes from the defender
- // will not be said if they are knocked out or killed
- if ( ubReason != TAKE_DAMAGE_TENTACLES && ubReason != TAKE_DAMAGE_OBJECT )
- {
- // OK, OK: THis is hairy, however, it's ness. because the normal freeup call uses the
- // attckers intended target, and here we want to use thier actual target....
- // ATE: If it's from GUNFIRE damage, keep in mind bullets...
- if ( Item[ usWeaponIndex ].usItemClass & IC_GUN )
- {
- pNewSoldier = FreeUpAttackerGivenTarget( pSoldier->ubAttackerID, pSoldier->ubID );
- }
- else
- {
- pNewSoldier = ReduceAttackBusyGivenTarget( pSoldier->ubAttackerID, pSoldier->ubID );
- }
- if (pNewSoldier != NULL)
- {
- pSoldier = pNewSoldier;
- }
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Tried to free up attacker, attack count now %d", gTacticalStatus.ubAttackBusyCount) );
- }
- // OK, If we are a vehicle.... damage vehicle...( people inside... )
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- SoldierTakeDamage( pSoldier, ANIM_CROUCH, sDamage, sBreathLoss, ubReason, pSoldier->ubAttackerID, NOWHERE, FALSE, TRUE );
- return;
- }
- // DEDUCT LIFE
- ubCombinedLoss = SoldierTakeDamage( pSoldier, ANIM_CROUCH, sDamage, sBreathLoss, ubReason, pSoldier->ubAttackerID, NOWHERE, FALSE, TRUE );
- // ATE: OK, Let's check our ASSIGNMENT state,
- // If anything other than on a squad or guard, make them guard....
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- if ( pSoldier->bAssignment >= ON_DUTY && pSoldier->bAssignment != ASSIGNMENT_POW )
- {
- if( pSoldier->fMercAsleep )
- {
- pSoldier->fMercAsleep = FALSE;
- pSoldier -> fForcedToStayAwake = FALSE;
- // refresh map screen
- fCharacterInfoPanelDirty = TRUE;
- fTeamPanelDirty = TRUE;
- }
- AddCharacterToAnySquad( pSoldier );
- }
- }
- // SCREAM!!!!
- ubVolume = CalcScreamVolume( pSoldier, ubCombinedLoss );
- // IF WE ARE AT A HIT_STOP ANIMATION
- // DO APPROPRIATE HITWHILE DOWN ANIMATION
- if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_HITSTOP ) || pSoldier->usAnimState != JFK_HITDEATH_STOP )
- {
- MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->bLevel, pSoldier->bOverTerrainType, ubVolume, NOISE_SCREAM);
- }
- // IAN ADDED THIS SAT JUNE 14th : HAVE TO SHOW VICTIM!
- if (gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT) && pSoldier->bVisible != -1 && pSoldier->bTeam == gbPlayerNum )
- LocateSoldier(pSoldier->ubID,DONTSETLOCATOR);
- if ( Item[ usWeaponIndex ].usItemClass & IC_BLADE )
- {
- PlayJA2Sample( (UINT32)( KNIFE_IMPACT ), RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
- }
- else
- {
- PlayJA2Sample( (UINT32)( BULLET_IMPACT_1 + Random(3) ), RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
- }
- // PLAY RANDOM GETTING HIT SOUND
- // ONLY IF WE ARE CONSCIOUS!
- if ( pSoldier->bLife >= CONSCIOUSNESS )
- {
- if ( pSoldier->ubBodyType == CROW )
- {
- // Exploding crow...
- PlayJA2Sample( CROW_EXPLODE_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
- }
- else
- {
- // ATE: This is to disallow large amounts of smaples being played which is load!
- if ( pSoldier->fGettingHit && pSoldier->usAniCode != STANDING_BURST_HIT )
- {
- }
- else
- {
- DoMercBattleSound( pSoldier, (INT8)( BATTLE_SOUND_HIT1 + Random( 2 ) ) );
- }
- }
- }
- // CHECK FOR DOING HIT WHILE DOWN
- if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_HITSTOP ) )
- {
- switch( pSoldier->usAnimState )
- {
- case FLYBACKHIT_STOP:
- ChangeSoldierState( pSoldier, FALLBACK_DEATHTWICH, 0, FALSE );
- break;
- case STAND_FALLFORWARD_STOP:
- ChangeSoldierState( pSoldier, GENERIC_HIT_DEATHTWITCHNB, 0, FALSE );
- break;
- case JFK_HITDEATH_STOP:
- ChangeSoldierState( pSoldier, JFK_HITDEATH_TWITCHB, 0, FALSE );
- break;
- case FALLBACKHIT_STOP:
- ChangeSoldierState( pSoldier, FALLBACK_HIT_DEATHTWITCHNB, 0, FALSE );
- break;
- case PRONE_LAYFROMHIT_STOP:
- ChangeSoldierState( pSoldier, PRONE_HIT_DEATHTWITCHNB, 0, FALSE );
- break;
- case PRONE_HITDEATH_STOP:
- ChangeSoldierState( pSoldier, PRONE_HIT_DEATHTWITCHB, 0 , FALSE );
- break;
- case FALLFORWARD_HITDEATH_STOP:
- ChangeSoldierState( pSoldier, GENERIC_HIT_DEATHTWITCHB, 0 , FALSE );
- break;
- case FALLBACK_HITDEATH_STOP:
- ChangeSoldierState( pSoldier, FALLBACK_HIT_DEATHTWITCHB, 0 , FALSE );
- break;
- case FALLOFF_DEATH_STOP:
- ChangeSoldierState( pSoldier, FALLOFF_TWITCHB, 0 , FALSE );
- break;
- case FALLOFF_STOP:
- ChangeSoldierState( pSoldier, FALLOFF_TWITCHNB, 0 , FALSE );
- break;
- case FALLOFF_FORWARD_DEATH_STOP:
- ChangeSoldierState( pSoldier, FALLOFF_FORWARD_TWITCHB, 0 , FALSE );
- break;
- case FALLOFF_FORWARD_STOP:
- ChangeSoldierState( pSoldier, FALLOFF_FORWARD_TWITCHNB, 0 , FALSE );
- break;
-
- default:
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Control: Death state %d has no death hit", pSoldier->usAnimState ) );
- }
- return;
- }
- // Set goback to aim after hit flag!
- // Only if we were aiming!
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY )
- {
- pSoldier->fGoBackToAimAfterHit = TRUE;
- }
- // IF COWERING, PLAY SPECIFIC GENERIC HIT STAND...
- if ( pSoldier->uiStatusFlags & SOLDIER_COWERING )
- {
- if ( pSoldier->bLife == 0 || IS_MERC_BODY_TYPE( pSoldier ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_STAND, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, CIV_COWER_HIT, 0 , FALSE );
- }
- return;
- }
- // Change based on body type
- switch( pSoldier->ubBodyType )
- {
- case COW:
- EVENT_InitNewSoldierAnim( pSoldier, COW_HIT, 0 , FALSE );
- return;
- break;
- case BLOODCAT:
- EVENT_InitNewSoldierAnim( pSoldier, BLOODCAT_HIT, 0 , FALSE );
- return;
- break;
- case ADULTFEMALEMONSTER:
- case AM_MONSTER:
- case YAF_MONSTER:
- case YAM_MONSTER:
- EVENT_InitNewSoldierAnim( pSoldier, ADULTMONSTER_HIT, 0 , FALSE );
- return;
- break;
- case LARVAE_MONSTER:
- EVENT_InitNewSoldierAnim( pSoldier, LARVAE_HIT, 0 , FALSE );
- return;
- break;
- case QUEENMONSTER:
- EVENT_InitNewSoldierAnim( pSoldier, QUEEN_HIT, 0 , FALSE );
- return;
- break;
- case CRIPPLECIV:
- {
- // OK, do some code here to allow the fact that poor buddy can be thrown back if it's a big enough hit...
- EVENT_InitNewSoldierAnim( pSoldier, CRIPPLE_HIT, 0 , FALSE );
- //pSoldier->bLife = 0;
- //EVENT_InitNewSoldierAnim( pSoldier, CRIPPLE_DIE_FLYBACK, 0 , FALSE );
- }
- return;
- break;
- case ROBOTNOWEAPON:
- EVENT_InitNewSoldierAnim( pSoldier, ROBOTNW_HIT, 0 , FALSE );
- return;
- break;
- case INFANT_MONSTER:
- EVENT_InitNewSoldierAnim( pSoldier, INFANT_HIT, 0 , FALSE );
- return;
- case CROW:
- EVENT_InitNewSoldierAnim( pSoldier, CROW_DIE, 0 , FALSE );
- return;
- //case FATCIV:
- case MANCIV:
- case MINICIV:
- case DRESSCIV:
- case HATKIDCIV:
- case KIDCIV:
-
- // OK, if life is 0 and not set as dead ( this is a death hit... )
- if ( !( pSoldier->uiStatusFlags & SOLDIER_DEAD ) && pSoldier->bLife == 0 )
- {
- // Randomize death!
- if ( Random( 2 ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, CIV_DIE2, 0 , FALSE );
- return;
- }
- }
- // IF here, go generic hit ALWAYS.....
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_STAND, 0 , FALSE );
- return;
- break;
- }
- // If here, we are a merc, check if we are in water
- if ( pSoldier->bOverTerrainType == LOW_WATER )
- {
- EVENT_InitNewSoldierAnim( pSoldier, WATER_HIT, 0 , FALSE );
- return;
- }
- if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- EVENT_InitNewSoldierAnim( pSoldier, DEEP_WATER_HIT, 0 , FALSE );
- return;
- }
- // SWITCH IN TYPE OF WEAPON
- if ( Item[ usWeaponIndex ].usItemClass & ( IC_GUN | IC_THROWING_KNIFE ) )
- {
- SoldierGotHitGunFire( pSoldier, usWeaponIndex, sDamage, bDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation );
- }
- if ( Item[ usWeaponIndex ].usItemClass & IC_BLADE )
- {
- SoldierGotHitBlade( pSoldier, usWeaponIndex, sDamage, bDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation );
- }
- if ( Item[ usWeaponIndex ].usItemClass & IC_EXPLOSV || Item[ usWeaponIndex ].usItemClass & IC_TENTACLES )
- {
- SoldierGotHitExplosion( pSoldier, usWeaponIndex, sDamage, bDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation );
- }
- if ( Item[ usWeaponIndex ].usItemClass & IC_PUNCH )
- {
- SoldierGotHitPunch( pSoldier, usWeaponIndex, sDamage, bDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation );
- }
- }
- UINT8 CalcScreamVolume( SOLDIERTYPE * pSoldier, UINT8 ubCombinedLoss )
- {
- // NB explosions are so loud they should drown out screams
- UINT8 ubVolume;
- if (ubCombinedLoss < 1)
- {
- ubVolume = 1;
- }
- else
- {
- ubVolume = ubCombinedLoss;
- }
- // Victim yells out in pain, making noise. Yelps are louder from greater
- // wounds, but softer for more experienced soldiers.
- if (ubVolume > (10 - EffectiveExpLevel( pSoldier ) ))
- {
- ubVolume = 10 - EffectiveExpLevel( pSoldier );
- }
- /*
- // the "Speck factor"... He's a whiner, and extra-sensitive to pain!
- if (ptr->trait == NERVOUS)
- ubVolume += 2;
- */
- if (ubVolume < 0)
- {
- ubVolume = 0;
- }
- return( ubVolume );
- }
- void DoGenericHit( SOLDIERTYPE *pSoldier, UINT8 ubSpecial, INT16 bDirection )
- {
- // Based on stance, select generic hit animation
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // For now, check if we are affected by a burst
- // For now, if the weapon was a gun, special 1 == burst
- // ATE: Only do this for mercs!
- if ( ubSpecial == FIRE_WEAPON_BURST_SPECIAL && pSoldier->ubBodyType <= REGFEMALE )
- {
- //SetSoldierDesiredDirection( pSoldier, bDirection );
- EVENT_SetSoldierDirection( pSoldier, (INT8)bDirection );
- EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
- EVENT_InitNewSoldierAnim( pSoldier, STANDING_BURST_HIT, 0 , FALSE );
- }
- else
- {
- // Check in hand for rifle
- if ( SoldierCarriesTwoHandedWeapon( pSoldier ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, RIFLE_STAND_HIT, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_STAND, 0 , FALSE );
- }
- }
- break;
- case ANIM_PRONE:
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_PRONE, 0 , FALSE );
- break;
- case ANIM_CROUCH:
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_CROUCH, 0 , FALSE );
- break;
- }
- }
- void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation )
- {
- UINT16 usNewGridNo;
- BOOLEAN fBlownAway = FALSE;
- BOOLEAN fHeadHit = FALSE;
- BOOLEAN fFallenOver = FALSE;
-
- // MAYBE CHANGE TO SPECIAL ANIMATION BASED ON VALUE SET BY DAMAGE CALCULATION CODE
- // ALL THESE ONLY WORK ON STANDING PEOPLE
- if (!(pSoldier->uiStatusFlags & SOLDIER_MONSTER) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND)
- {
- if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
- {
- if (ubSpecial == FIRE_WEAPON_HEAD_EXPLODE_SPECIAL)
- {
- if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
- {
- if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH)
- {
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (INT8)( DirectionInc( pSoldier->bDirection ) ) );
- // CHECK OK DESTINATION!
- if ( OKFallDirection( pSoldier, usNewGridNo, pSoldier->bLevel, pSoldier->bDirection, JFK_HITDEATH ) )
- {
- usNewGridNo = NewGridNo( (UINT16)usNewGridNo, (INT8)( DirectionInc( pSoldier->bDirection ) ) );
- if ( OKFallDirection( pSoldier, usNewGridNo, pSoldier->bLevel, pSoldier->bDirection, pSoldier->usAnimState ) )
- {
- fHeadHit = TRUE;
- }
- }
- }
- }
- }
- else if (ubSpecial == FIRE_WEAPON_CHEST_EXPLODE_SPECIAL)
- {
- if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
- {
- if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH)
- {
- // possibly play torso explosion anim!
- if (pSoldier->bDirection == bDirection)
- {
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ pSoldier->bDirection ] ) );
- if ( OKFallDirection( pSoldier, usNewGridNo, pSoldier->bLevel, gOppositeDirection[ bDirection ], FLYBACK_HIT ) )
- {
- usNewGridNo = NewGridNo( (UINT16)usNewGridNo, DirectionInc( gOppositeDirection[ bDirection ] ) );
- if ( OKFallDirection( pSoldier, usNewGridNo, pSoldier->bLevel, gOppositeDirection[ bDirection ], pSoldier->usAnimState ) )
- {
- fBlownAway = TRUE;
- }
- }
- }
- }
- }
- }
- else if (ubSpecial == FIRE_WEAPON_LEG_FALLDOWN_SPECIAL)
- {
- // possibly play fall over anim!
- // this one is NOT restricted by distance
- if (IsValidStance( pSoldier, ANIM_PRONE ) )
- {
- // Can't be in water, or not standing
- if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND && !MercInWater( pSoldier ) )
- {
- fFallenOver = TRUE;
- ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 20 ], pSoldier->name );
- }
- }
- }
- }
- }
- // IF HERE AND GUY IS DEAD, RETURN!
- if ( pSoldier->uiStatusFlags & SOLDIER_DEAD )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker,Dead soldier hit" ) );
- ReleaseSoldiersAttacker( pSoldier );
- return;
- }
- if ( fFallenOver )
- {
- SoldierCollapse( pSoldier );
- return;
- }
- if ( fBlownAway )
- {
- // Only for mercs...
- if ( pSoldier->ubBodyType < 4 )
- {
- ChangeToFlybackAnimation( pSoldier, (INT8)bDirection );
- return;
- }
- }
- if ( fHeadHit )
- {
- // Only for mercs ( or KIDS! )
- if ( pSoldier->ubBodyType < 4 || pSoldier->ubBodyType == HATKIDCIV || pSoldier->ubBodyType == KIDCIV )
- {
- EVENT_InitNewSoldierAnim( pSoldier, JFK_HITDEATH, 0 , FALSE );
- return;
- }
- }
- DoGenericHit( pSoldier, ubSpecial, bDirection );
- }
- void SoldierGotHitExplosion( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation )
- {
- INT16 sNewGridNo;
-
- // IF HERE AND GUY IS DEAD, RETURN!
- if ( pSoldier->uiStatusFlags & SOLDIER_DEAD )
- {
- return;
- }
- //check for services
- ReceivingSoldierCancelServices( pSoldier );
- GivingSoldierCancelServices( pSoldier );
- if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
- {
- if ( Explosive[ Item[ usWeaponIndex ].ubClassIndex ].ubRadius >= 3 && pSoldier->bLife == 0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE )
- {
- if ( sRange >= 2 && sRange <= 4 )
- {
- DoMercBattleSound( pSoldier, (INT8)( BATTLE_SOUND_HIT1 + Random( 2 ) ) );
- EVENT_InitNewSoldierAnim( pSoldier, CHARIOTS_OF_FIRE, 0 , FALSE );
- return;
- }
- else if ( sRange <= 1 )
- {
- DoMercBattleSound( pSoldier, (INT8)( BATTLE_SOUND_HIT1 + Random( 2 ) ) );
- EVENT_InitNewSoldierAnim( pSoldier, BODYEXPLODING, 0 , FALSE );
- return;
- }
- }
- }
- // If we can't fal back or such, so generic hit...
- if ( pSoldier->ubBodyType >= 4 )
- {
- DoGenericHit( pSoldier, 0, bDirection );
- return;
- }
- // Based on stance, select generic hit animation
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- case ANIM_CROUCH:
- EVENT_SetSoldierDirection( pSoldier, (INT8)bDirection );
- EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
- // Check behind us!
- sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bDirection ] ) );
- if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->bLevel, gOppositeDirection[ bDirection ], FLYBACK_HIT ) )
- {
- ChangeToFallbackAnimation( pSoldier, (INT8)bDirection );
- }
- else
- {
- if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
- {
- BeginTyingToFall( pSoldier );
- EVENT_InitNewSoldierAnim( pSoldier, FALLFORWARD_FROMHIT_STAND, 0, FALSE );
- }
- else
- {
- SoldierCollapse( pSoldier );
- }
- }
- break;
- case ANIM_PRONE:
- SoldierCollapse( pSoldier );
- break;
- }
- }
- void SoldierGotHitBlade( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation )
- {
-
- // IF HERE AND GUY IS DEAD, RETURN!
- if ( pSoldier->uiStatusFlags & SOLDIER_DEAD )
- {
- return;
- }
- // Based on stance, select generic hit animation
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // Check in hand for rifle
- if ( SoldierCarriesTwoHandedWeapon( pSoldier ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, RIFLE_STAND_HIT, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_STAND, 0 , FALSE );
- }
- break;
- case ANIM_CROUCH:
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_CROUCH, 0 , FALSE );
- break;
- case ANIM_PRONE:
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_PRONE, 0 , FALSE );
- break;
- }
- }
- void SoldierGotHitPunch( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation )
- {
-
- // IF HERE AND GUY IS DEAD, RETURN!
- if ( pSoldier->uiStatusFlags & SOLDIER_DEAD )
- {
- return;
- }
- // Based on stance, select generic hit animation
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // Check in hand for rifle
- if ( SoldierCarriesTwoHandedWeapon( pSoldier ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, RIFLE_STAND_HIT, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_STAND, 0 , FALSE );
- }
- break;
- case ANIM_CROUCH:
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_CROUCH, 0 , FALSE );
- break;
- case ANIM_PRONE:
- EVENT_InitNewSoldierAnim( pSoldier, GENERIC_HIT_PRONE, 0 , FALSE );
- break;
- }
- }
- BOOLEAN EVENT_InternalGetNewSoldierPath( SOLDIERTYPE *pSoldier, UINT16 sDestGridNo, UINT16 usMovementAnim, BOOLEAN fFromUI, BOOLEAN fForceRestartAnim )
- {
- INT32 iDest;
- INT16 sNewGridNo;
- BOOLEAN fContinue;
- UINT32 uiDist;
- UINT16 usAnimState;
- UINT16 usMoveAnimState = usMovementAnim;
- INT16 sMercGridNo;
- UINT16 usPathingData[ MAX_PATH_LIST_SIZE ];
- UINT8 ubPathingMaxDirection;
- BOOLEAN fAdvancePath = TRUE;
- UINT8 fFlags = 0;
- // Ifd this code, make true if a player
- if ( fFromUI == 3 )
- {
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- fFromUI = 1;
- }
- else
- {
- fFromUI = 0;
- }
- }
- // ATE: if a civ, and from UI, and were cowering, remove from cowering
- if ( AM_AN_EPC( pSoldier ) && fFromUI )
- {
- if ( pSoldier->uiStatusFlags & SOLDIER_COWERING )
- {
- SetSoldierCowerState( pSoldier, FALSE );
- usMoveAnimState = WALKING;
- }
- }
- pSoldier->bGoodContPath = FALSE;
- if ( pSoldier->fDelayedMovement )
- {
- if ( pSoldier->ubDelayedMovementFlags & DELAYED_MOVEMENT_FLAG_PATH_THROUGH_PEOPLE )
- {
- fFlags = PATH_THROUGH_PEOPLE;
- }
- else
- {
- fFlags = PATH_IGNORE_PERSON_AT_DEST;
- }
- pSoldier->fDelayedMovement = FALSE;
- }
- if ( gfGetNewPathThroughPeople )
- {
- fFlags = PATH_THROUGH_PEOPLE;
- }
- // ATE: Some stuff here for realtime, going through interface....
- if ( ( !( gTacticalStatus.uiFlags & INCOMBAT ) && ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING ) && fFromUI == 1 ) || fFromUI == 2 )
- {
- if ( pSoldier->bCollapsed )
- {
- return( FALSE );
- }
- sMercGridNo = pSoldier->sGridNo;
- pSoldier->sGridNo = pSoldier->sDestination;
- // Check if path is good before copying it into guy's path...
- if ( FindBestPath( pSoldier, sDestGridNo, pSoldier->bLevel, pSoldier->usUIMovementMode, NO_COPYROUTE, fFlags ) == 0 )
- {
- // Set to old....
- pSoldier->sGridNo = sMercGridNo;
- return( FALSE );
- }
- uiDist = FindBestPath( pSoldier, sDestGridNo, pSoldier->bLevel, pSoldier->usUIMovementMode, COPYROUTE, fFlags );
- pSoldier->sGridNo = sMercGridNo;
- pSoldier->sFinalDestination = sDestGridNo;
- if ( uiDist > 0 )
- {
- // Add one to path data size....
- if ( fAdvancePath )
- {
- memcpy( usPathingData, pSoldier->usPathingData, sizeof( usPathingData ) );
- ubPathingMaxDirection = (UINT8)usPathingData[ MAX_PATH_LIST_SIZE -1 ];
- memcpy( &(pSoldier->usPathingData[1]), usPathingData, sizeof( usPathingData ) - sizeof( UINT16 ) );
- // If we have reach the max, go back one sFinalDest....
- if ( pSoldier->usPathDataSize == MAX_PATH_LIST_SIZE )
- {
- //pSoldier->sFinalDestination = NewGridNo( (UINT16)pSoldier->sFinalDestination, DirectionInc( gOppositeDirection[ ubPathingMaxDirection ] ) );
- }
- else
- {
- pSoldier->usPathDataSize++;
- }
- }
- usMoveAnimState = pSoldier->usUIMovementMode;
- if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- usMoveAnimState = DEEP_WATER_SWIM;
- }
- // Change animation only.... set value to NOT call any goto new gridno stuff.....
- if ( usMoveAnimState != pSoldier->usAnimState )
- {
- //
- pSoldier->usDontUpdateNewGridNoOnMoveAnimChange = TRUE;
- EVENT_InitNewSoldierAnim( pSoldier, usMoveAnimState, 0, FALSE );
- }
- return( TRUE );
- }
- return( FALSE );
- }
- // we can use the soldier's level here because we don't have pathing across levels right now...
- if (pSoldier->bPathStored)
- {
- fContinue = TRUE;
- }
- else
- {
- iDest = FindBestPath( pSoldier, sDestGridNo, pSoldier->bLevel, usMovementAnim, COPYROUTE, fFlags );
- fContinue = (iDest != 0);
- }
- // Only if we can get a path here
- if ( fContinue )
- {
- // Debug messages
- DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Soldier %d: Get new path", pSoldier->ubID ) );
- // Set final destination
- pSoldier->sFinalDestination = sDestGridNo;
- pSoldier->fPastXDest = 0;
- pSoldier->fPastYDest = 0;
- // CHECK IF FIRST TILE IS FREE
- sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( (UINT8)pSoldier->usPathingData[ pSoldier->usPathIndex ] ) );
- // If true, we're OK, if not, WAIT for a guy to pass!
- // If we are in deep water, we can only swim!
- if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- usMoveAnimState = DEEP_WATER_SWIM;
- }
- // If we were aiming, end aim!
- usAnimState = PickSoldierReadyAnimation( pSoldier, TRUE );
- // Add a pending animation first!
- // Only if we were standing!
- if ( usAnimState != INVALID_ANIMATION && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
- {
- EVENT_InitNewSoldierAnim( pSoldier, usAnimState, 0, FALSE );
- pSoldier->usPendingAnimation = usMoveAnimState;
- }
- else
- {
- // Call local copy for change soldier state!
- EVENT_InitNewSoldierAnim( pSoldier, usMoveAnimState, 0, fForceRestartAnim );
- }
- // Change desired direction
- // ATE: Here we have a situation where in RT, we may have
- // gotten a new path, but we are alreayd moving.. so
- // at leasty change new dest. This will be redundent if the ANI is a totaly new one
- return( TRUE );
- }
- return( FALSE );
- }
- void EVENT_GetNewSoldierPath( SOLDIERTYPE *pSoldier, UINT16 sDestGridNo, UINT16 usMovementAnim )
- {
- // ATE: Default restart of animation to TRUE
- EVENT_InternalGetNewSoldierPath( pSoldier, sDestGridNo, usMovementAnim, FALSE, TRUE );
- }
- // Change our state based on stance, to stop!
- void StopSoldier( SOLDIERTYPE *pSoldier )
- {
- ReceivingSoldierCancelServices( pSoldier );
- GivingSoldierCancelServices( pSoldier );
- if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STATIONARY ) )
- {
- //SoldierGotoStationaryStance( pSoldier );
- EVENT_StopMerc( pSoldier, pSoldier->sGridNo, pSoldier->bDirection );
- }
- // Set desination
- pSoldier->sFinalDestination = pSoldier->sGridNo;
- }
- void SoldierGotoStationaryStance( SOLDIERTYPE *pSoldier )
- {
- // ATE: This is to turn off fast movement, that us used to change movement mode
- // for ui display on stance changes....
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- //pSoldier->fUIMovementFast = FALSE;
- }
- // The queen, if she sees anybody, goes to ready, not normal breath....
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- if ( pSoldier->bOppCnt > 0 || pSoldier->bTeam == gbPlayerNum )
- {
- EVENT_InitNewSoldierAnim( pSoldier, QUEEN_READY, 0 , TRUE );
- return;
- }
- }
- // Check if we are in deep water!
- if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- // IN deep water, tred!
- EVENT_InitNewSoldierAnim( pSoldier, DEEP_WATER_TRED, 0 , FALSE );
- }
- else if ( pSoldier->ubServicePartner != NOBODY && pSoldier->bLife >= OKLIFE && pSoldier->bBreath > 0 )
- {
- EVENT_InitNewSoldierAnim( pSoldier, GIVING_AID, 0 , FALSE );
- }
- else
- {
- // Change state back to stationary state for given height
- switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- // If we are cowering....goto cower state
- if ( pSoldier->uiStatusFlags & SOLDIER_COWERING )
- {
- EVENT_InitNewSoldierAnim( pSoldier, START_COWER, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, STANDING, 0 , FALSE );
- }
- break;
- case ANIM_CROUCH:
- // If we are cowering....goto cower state
- if ( pSoldier->uiStatusFlags & SOLDIER_COWERING )
- {
- EVENT_InitNewSoldierAnim( pSoldier, COWERING, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, CROUCHING, 0 , FALSE );
- }
- break;
- case ANIM_PRONE:
- EVENT_InitNewSoldierAnim( pSoldier, PRONE, 0 , FALSE );
- break;
- }
- }
- }
- void ChangeSoldierStance( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance )
- {
- UINT16 usNewState;
- // Check if they are the same!
- if ( ubDesiredStance == gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- // Free up from stance change
- FreeUpNPCFromStanceChange( pSoldier );
- return;
- }
- // Set UI Busy
- SetUIBusy( pSoldier->ubID );
- // ATE: If we are an NPC, cower....
- if ( pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= KIDCIV )
- {
- if ( ubDesiredStance == ANIM_STAND )
- {
- SetSoldierCowerState( pSoldier, FALSE );
- }
- else
- {
- SetSoldierCowerState( pSoldier, TRUE );
- }
- }
- else
- {
- usNewState = GetNewSoldierStateFromNewStance( pSoldier, ubDesiredStance );
- // Set desired stance
- pSoldier->ubDesiredHeight = ubDesiredStance;
- // Now change to appropriate animation
- EVENT_InitNewSoldierAnim( pSoldier, usNewState, 0 , FALSE );
- }
- }
- void EVENT_InternalSetSoldierDestination( SOLDIERTYPE *pSoldier, UINT16 usNewDirection, BOOLEAN fFromMove, UINT16 usAnimState )
- {
- UINT16 usNewGridNo;
- INT16 sXPos, sYPos;
- // Get dest gridno, convert to center coords
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( usNewDirection ) );
- ConvertMapPosToWorldTileCenter( usNewGridNo, &sXPos, &sYPos );
- // Save new dest gridno, x, y
- pSoldier->sDestination = usNewGridNo;
- pSoldier->sDestXPos = sXPos;
- pSoldier->sDestYPos = sYPos;
- pSoldier->bMovementDirection = (INT8)usNewDirection;
- // OK, ATE: If we are side_stepping, calculate a NEW desired direction....
- if ( pSoldier->bReverse && usAnimState == SIDE_STEP )
- {
- UINT8 ubPerpDirection;
- // Get a new desired direction,
- ubPerpDirection = gPurpendicularDirection[ pSoldier->bDirection ][ usNewDirection ];
- // CHange actual and desired direction....
- EVENT_SetSoldierDirection( pSoldier, ubPerpDirection );
- pSoldier->bDesiredDirection = pSoldier->bDirection;
- }
- else
- {
- if ( !( gAnimControl[ usAnimState ].uiFlags & ANIM_SPECIALMOVE ) )
- {
- EVENT_InternalSetSoldierDesiredDirection( pSoldier, usNewDirection, fFromMove, usAnimState );
- }
- }
- }
- void EVENT_SetSoldierDestination( SOLDIERTYPE *pSoldier, UINT16 usNewDirection )
- {
- EVENT_InternalSetSoldierDestination( pSoldier, usNewDirection, FALSE, pSoldier->usAnimState );
- }
- // function to determine which direction a creature can turn in
- INT8 MultiTiledTurnDirection( SOLDIERTYPE * pSoldier, INT8 bStartDirection, INT8 bDesiredDirection )
- {
- INT8 bTurningIncrement;
- INT8 bCurrentDirection;
- INT8 bLoop;
- UINT16 usStructureID, usAnimSurface;
- STRUCTURE_FILE_REF * pStructureFileRef;
- BOOLEAN fOk = FALSE;
- // start by trying to turn in quickest direction
- bTurningIncrement = (INT8) QuickestDirection( bStartDirection, bDesiredDirection );
- usAnimSurface = DetermineSoldierAnimationSurface( pSoldier, pSoldier->usUIMovementMode );
- pStructureFileRef = GetAnimationStructureRef( pSoldier->ubID, usAnimSurface, pSoldier->usUIMovementMode );
- if ( !pStructureFileRef )
- {
- // without structure data, well, assume quickest direction
- return( bTurningIncrement );
- }
- // ATE: Only if we have a levelnode...
- if ( pSoldier->pLevelNode != NULL && pSoldier->pLevelNode->pStructureData != NULL )
- {
- usStructureID = pSoldier->pLevelNode->pStructureData->usStructureID;
- }
- else
- {
- usStructureID = INVALID_STRUCTURE_ID;
- }
- bLoop = 0;
- bCurrentDirection = bStartDirection;
- while( bLoop < 2 )
- {
- while( bCurrentDirection != bDesiredDirection )
- {
- bCurrentDirection += bTurningIncrement;
- // did we wrap directions?
- if ( bCurrentDirection < 0 )
- {
- bCurrentDirection = (MAXDIR - 1);
- }
- else if ( bCurrentDirection >= MAXDIR )
- {
- bCurrentDirection = 0;
- }
- // check to see if we can add creature in that direction
- fOk = OkayToAddStructureToWorld( pSoldier->sGridNo, pSoldier->bLevel, &(pStructureFileRef->pDBStructureRef[ gOneCDirection[ bCurrentDirection ] ]), usStructureID );
- if (!fOk)
- {
- break;
- }
- }
- if ( (bCurrentDirection == bDesiredDirection) && fOk )
- {
- // success!!
- return( bTurningIncrement );
- }
- bLoop++;
- if ( bLoop < 2 )
- {
- // change direction of loop etc
- bCurrentDirection = bStartDirection;
- bTurningIncrement *= -1;
- }
- }
- // nothing found... doesn't matter much what we return
- return( bTurningIncrement );
- }
- void EVENT_InternalSetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT16 usNewDirection, BOOLEAN fInitalMove, UINT16 usAnimState )
- {
- //if ( usAnimState == WALK_BACKWARDS )
- if ( pSoldier->bReverse && usAnimState != SIDE_STEP )
- {
- // OK, check if we are going to go in the exact opposite than our facing....
- usNewDirection = gOppositeDirection[ usNewDirection ];
- }
- pSoldier->bDesiredDirection = (INT8)usNewDirection;
- // If we are prone, goto crouched first!
- // ONly if we are stationary, and only if directions are differnet!
- // ATE: If we are fNoAPsToFinnishMove, stop what we were doing and
- // reset flag.....
- if ( pSoldier->fNoAPToFinishMove && ( gAnimControl[ usAnimState ].uiFlags & ANIM_MOVING ) )
- {
- // ATE; Commented this out: NEVER, EVER, start a new anim from this function, as an eternal loop will result....
- //SoldierGotoStationaryStance( pSoldier );
- // Reset flag!
- AdjustNoAPToFinishMove( pSoldier, FALSE );
- }
- if ( pSoldier->bDesiredDirection != pSoldier->bDirection )
- {
- if ( gAnimControl[ usAnimState ].uiFlags & ( ANIM_BREATH | ANIM_OK_CHARGE_AP_FOR_TURN | ANIM_FIREREADY ) && !fInitalMove && !pSoldier->fDontChargeTurningAPs )
- {
- // Deduct points for initial turn!
- switch( gAnimControl[ usAnimState ].ubEndHeight )
- {
- // Now change to appropriate animation
- case ANIM_STAND:
- DeductPoints( pSoldier, AP_LOOK_STANDING, 0 );
- break;
- case ANIM_CROUCH:
- DeductPoints( pSoldier, AP_LOOK_CROUCHED, 0 );
- break;
- case ANIM_PRONE:
- DeductPoints( pSoldier, AP_LOOK_PRONE, 0 );
- break;
- }
- }
- pSoldier->fDontChargeTurningAPs = FALSE;
- if ( fInitalMove )
- {
- if ( gAnimControl[ usAnimState ].ubHeight == ANIM_PRONE )
- {
- if ( pSoldier->fTurningFromPronePosition != TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE )
- {
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_START_UP_FROM_MOVE;
- }
- }
- }
- if ( gAnimControl[ usAnimState ].uiFlags & ANIM_STATIONARY || pSoldier->fNoAPToFinishMove || fInitalMove )
- {
- if ( gAnimControl[ usAnimState ].ubHeight == ANIM_PRONE )
- {
- // Set this beasty of a flag to allow us to go back down to prone if we choose!
- // ATE: Alrighty, set flag to go back down only if we are not moving anywhere
- //if ( pSoldier->sDestination == pSoldier->sGridNo )
- if ( !fInitalMove )
- {
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_ON;
- // Set a pending animation to change stance first...
- SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH );
- }
- }
- }
- }
- // Set desired direction for the extended directions...
- pSoldier->ubHiResDesiredDirection = ubExtDirection[ pSoldier->bDesiredDirection ];
- if ( pSoldier->bDesiredDirection != pSoldier->bDirection )
- {
- if ( pSoldier->uiStatusFlags & ( SOLDIER_VEHICLE ) || CREATURE_OR_BLOODCAT( pSoldier ) )
- {
- pSoldier->uiStatusFlags |= SOLDIER_PAUSEANIMOVE;
- }
- }
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- pSoldier->bTurningIncrement = (INT8) ExtQuickestDirection( pSoldier->ubHiResDirection, pSoldier->ubHiResDesiredDirection );
- }
- else
- {
- if ( pSoldier->uiStatusFlags & SOLDIER_MULTITILE )
- {
- pSoldier->bTurningIncrement = (INT8) MultiTiledTurnDirection( pSoldier, pSoldier->bDirection, pSoldier->bDesiredDirection );
- }
- else
- {
- pSoldier->bTurningIncrement = (INT8) QuickestDirection( pSoldier->bDirection, pSoldier->bDesiredDirection );
- }
- }
- }
- void EVENT_SetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT16 usNewDirection )
- {
- EVENT_InternalSetSoldierDesiredDirection( pSoldier, usNewDirection, FALSE, pSoldier->usAnimState );
- }
- void EVENT_SetSoldierDirection( SOLDIERTYPE *pSoldier, UINT16 usNewDirection )
- {
- // Remove old location data
- HandleAnimationProfile( pSoldier, pSoldier->usAnimState, TRUE );
- pSoldier->bDirection = (INT8)usNewDirection;
- // Updated extended direction.....
- pSoldier->ubHiResDirection = ubExtDirection[ pSoldier->bDirection ];
-
- // Add new stuff
- HandleAnimationProfile( pSoldier, pSoldier->usAnimState, FALSE );
- // If we are turning, we have chaanged our aim!
- if ( !pSoldier->fDontUnsetLastTargetFromTurn )
- {
- pSoldier->sLastTarget = NOWHERE;
- }
- AdjustForFastTurnAnimation( pSoldier );
- // Update structure info!
- // if ( pSoldier->uiStatusFlags & SOLDIER_MULTITILE )
- {
- UpdateMercStructureInfo( pSoldier );
- }
- // Handle Profile data for hit locations
- HandleAnimationProfile( pSoldier, pSoldier->usAnimState, TRUE );
- HandleCrowShadowNewDirection( pSoldier );
-
- // Change values!
- SetSoldierLocatorOffsets( pSoldier );
- }
-
-
- void EVENT_BeginMercTurn( SOLDIERTYPE *pSoldier, BOOLEAN fFromRealTime, INT32 iRealTimeCounter )
- {
- // NB realtimecounter is not used, always passed in as 0 now!
- INT32 iBlood;
- if (pSoldier->bUnderFire)
- {
- // UnderFire now starts at 2 for "under fire this turn",
- // down to 1 for "under fire last turn", to 0.
- pSoldier->bUnderFire--;
- }
- // ATE: Add decay effect sfor drugs...
- if ( fFromRealTime ) //&& iRealTimeCounter % 300 )
- {
- HandleEndTurnDrugAdjustments( pSoldier );
- }
- else
- {
- HandleEndTurnDrugAdjustments( pSoldier );
- }
- // ATE: Don't bleed if in AUTO BANDAGE!
- if ( !gTacticalStatus.fAutoBandageMode )
- {
- // Blood is not for the weak of heart, or mechanical
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_ROBOT ) ) )
- {
- if ( pSoldier->bBleeding || pSoldier->bLife < OKLIFE ) // is he bleeding or dying?
- {
- iBlood = CheckBleeding( pSoldier ); // check if he might lose another life point
- // ATE: Only if in sector!
- if ( pSoldier->bInSector )
- {
- if ( iBlood != NOBLOOD )
- {
- DropBlood( pSoldier, (INT8)iBlood, pSoldier->bVisible );
- }
- }
- }
- }
- }
- // survived bleeding, but is he out of breath?
- if ( pSoldier->bLife && !pSoldier->bBreath && MercInWater( pSoldier ) )
- {
- // Drowning...
- }
- // if he is still alive (didn't bleed to death)
- if ( pSoldier->bLife )
- {
- // reduce the effects of any residual shock from past injuries by half
- pSoldier->bShock /= 2;
- // if this person has heard a noise that hasn't been investigated
- if (pSoldier->sNoiseGridno != NOWHERE)
- {
- if (pSoldier->ubNoiseVolume) // and the noise volume is still positive
- {
- pSoldier->ubNoiseVolume--; // the volume of the noise "decays" by 1 point
- if (!pSoldier->ubNoiseVolume) // if the volume has reached zero
- {
- pSoldier->sNoiseGridno = NOWHERE; // forget about the noise!
- }
- }
- }
- // save unused action points up to a maximum
- /*
- if ((savedPts = pSoldier->bActionPts) > MAX_AP_CARRIED)
- savedPts = MAX_AP_CARRIED;
- */
- if ( pSoldier->uiStatusFlags & SOLDIER_GASSED )
- {
- // then must get a gas mask or leave the gassed area to get over it
- if ( ( pSoldier->inv[ HEAD1POS ].usItem == GASMASK || pSoldier->inv[ HEAD2POS ].usItem == GASMASK ) || !( GetSmokeEffectOnTile( pSoldier->sGridNo, pSoldier->bLevel ) ) )
- {
- // Turn off gassed flag....
- pSoldier->uiStatusFlags &= (~SOLDIER_GASSED );
- }
- }
- if ( pSoldier->bBlindedCounter > 0 )
- {
- pSoldier->bBlindedCounter--;
- if (pSoldier->bBlindedCounter == 0)
- {
- // we can SEE!!!!!
- HandleSight( pSoldier, SIGHT_LOOK );
- // Dirty panel
- fInterfacePanelDirty = DIRTYLEVEL2;
- }
- }
- // ATE: To get around a problem...
- // If an AI guy, and we have 0 life, and are still at higher hieght,
- // Kill them.....
- pSoldier->sWeightCarriedAtTurnStart = (INT16) CalculateCarriedWeight( pSoldier );
- UnusedAPsToBreath( pSoldier );
-
- // Set flag back to normal, after reaching a certain statge
- if ( pSoldier->bBreath > 80 )
- {
- pSoldier->usQuoteSaidFlags &= ( ~SOLDIER_QUOTE_SAID_LOW_BREATH );
- }
- if ( pSoldier->bBreath > 50 )
- {
- pSoldier->usQuoteSaidFlags &= ( ~SOLDIER_QUOTE_SAID_DROWNING );
- }
- if ( pSoldier->ubTurnsUntilCanSayHeardNoise > 0)
- {
- pSoldier->ubTurnsUntilCanSayHeardNoise--;
- }
- if ( pSoldier->bInSector )
- {
- CheckForBreathCollapse( pSoldier );
- }
- CalcNewActionPoints( pSoldier );
- pSoldier->bTilesMoved = 0;
- if ( pSoldier->bInSector )
- {
- BeginSoldierGetup( pSoldier );
- // CJC Nov 30: handle RT opplist decaying in another function which operates less often
- if ( gTacticalStatus.uiFlags & INCOMBAT )
- {
- VerifyAndDecayOpplist( pSoldier );
- // turn off xray
- if ( pSoldier->uiXRayActivatedTime )
- {
- TurnOffXRayEffects( pSoldier );
- }
- }
- if ( (pSoldier->bTeam == gbPlayerNum) && (pSoldier->ubProfile != NO_PROFILE) )
- {
- switch( gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait )
- {
- case FEAR_OF_INSECTS:
- if ( MercSeesCreature( pSoldier ) )
- {
- HandleMoraleEvent( pSoldier, MORALE_INSECT_PHOBIC_SEES_CREATURE, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
- if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_PERSONALITY) )
- {
- TacticalCharacterDialogue( pSoldier, QUOTE_PERSONALITY_TRAIT );
- pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_PERSONALITY;
- }
- }
- break;
- case CLAUSTROPHOBIC:
- if ( gbWorldSectorZ > 0 && Random( 6 - gbWorldSectorZ ) == 0 )
- {
- // underground!
- HandleMoraleEvent( pSoldier, MORALE_CLAUSTROPHOBE_UNDERGROUND, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
- if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_PERSONALITY) )
- {
- TacticalCharacterDialogue( pSoldier, QUOTE_PERSONALITY_TRAIT );
- pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_PERSONALITY;
- }
- }
- break;
- case NERVOUS:
- if ( DistanceToClosestFriend( pSoldier ) > NERVOUS_RADIUS )
- {
- // augh!!
- if ( pSoldier->bMorale < 50 )
- {
- HandleMoraleEvent( pSoldier, MORALE_NERVOUS_ALONE, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
- if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_PERSONALITY) )
- {
- TacticalCharacterDialogue( pSoldier, QUOTE_PERSONALITY_TRAIT );
- pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_PERSONALITY;
- }
- }
- }
- else
- {
- if ( pSoldier->bMorale > 45 )
- {
- // turn flag off, so that we say it every two turns
- pSoldier->usQuoteSaidFlags &= ~SOLDIER_QUOTE_SAID_PERSONALITY;
- }
- }
- break;
- }
- }
- }
- // Reset quote flags for under heavy fire and close call!
- pSoldier->usQuoteSaidFlags &= ( ~SOLDIER_QUOTE_SAID_BEING_PUMMELED );
- pSoldier->usQuoteSaidExtFlags &= ( ~SOLDIER_QUOTE_SAID_EXT_CLOSE_CALL );
- pSoldier->bNumHitsThisTurn = 0;
- pSoldier->ubSuppressionPoints = 0;
- pSoldier->fCloseCall = FALSE;
- pSoldier->ubMovementNoiseHeard = 0;
- // If soldier has new APs, reset flags!
- if ( pSoldier->bActionPoints > 0 )
- {
- pSoldier->fUIFirstTimeNOAP = FALSE;
- pSoldier->bMoved = FALSE;
- pSoldier->bPassedLastInterrupt = FALSE;
- }
- }
- }
- // UTILITY FUNCTIONS CALLED BY OVERHEAD.H
- UINT8 gDirectionFrom8to2[ ] = { 0, 0, 1, 1, 0, 1, 1, 0 };
- BOOLEAN ConvertAniCodeToAniFrame( SOLDIERTYPE *pSoldier, UINT16 usAniFrame )
- {
- UINT16 usAnimSurface;
- UINT8 ubTempDir;
- // Given ani code, adjust for facing direction
- // get anim surface and determine # of frames
- usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
- CHECKF( usAnimSurface != INVALID_ANIMATION_SURFACE );
- // COnvert world direction into sprite direction
- ubTempDir = gOneCDirection[ pSoldier->bDirection ];
- //If we are only one frame, ignore what the script is telling us!
- if ( gAnimSurfaceDatabase[ usAnimSurface ].ubFlags & ANIM_DATA_FLAG_NOFRAMES )
- {
- usAniFrame = 0;
- }
- if ( gAnimSurfaceDatabase[ usAnimSurface ].uiNumDirections == 32 )
- {
- ubTempDir = gExtOneCDirection[ pSoldier->ubHiResDirection ];
- }
- // Check # of directions /surface, adjust if ness.
- else if ( gAnimSurfaceDatabase[ usAnimSurface ].uiNumDirections == 4 )
- {
- ubTempDir = ubTempDir / 2;
- }
- // Check # of directions /surface, adjust if ness.
- else if ( gAnimSurfaceDatabase[ usAnimSurface ].uiNumDirections == 1 )
- {
- ubTempDir = 0;
- }
- // Check # of directions /surface, adjust if ness.
- else if ( gAnimSurfaceDatabase[ usAnimSurface ].uiNumDirections == 3 )
- {
- if ( pSoldier->bDirection == NORTHWEST )
- {
- ubTempDir = 1;
- }
- if ( pSoldier->bDirection == WEST )
- {
- ubTempDir = 0;
- }
- if ( pSoldier->bDirection == EAST )
- {
- ubTempDir = 2;
- }
- }
- else if ( gAnimSurfaceDatabase[ usAnimSurface ].uiNumDirections == 2 )
- {
- ubTempDir = gDirectionFrom8to2[ pSoldier->bDirection ];
- }
- pSoldier->usAniFrame = usAniFrame + (UINT16) ( ( gAnimSurfaceDatabase[ usAnimSurface ].uiNumFramesPerDir * ubTempDir ) );
- if ( gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject == NULL )
- {
- pSoldier->usAniFrame = 0;
- return( TRUE );
- }
- if ( pSoldier->usAniFrame >= gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->usNumberOfObjects )
- {
- // Debug msg here....
- // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Soldier Animation: Wrong Number of frames per number of objects: %d vs %d, %S", gAnimSurfaceDatabase[ usAnimSurface ].uiNumFramesPerDir, gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->usNumberOfObjects, gAnimControl[ pSoldier->usAnimState ].zAnimStr );
- pSoldier->usAniFrame = 0;
- }
- return( TRUE );
- }
- void TurnSoldier( SOLDIERTYPE *pSoldier)
- {
- INT16 sDirection;
- BOOLEAN fDoDirectionChange = TRUE;
- INT32 cnt;
- // If we are a vehicle... DON'T TURN!
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- if ( pSoldier->ubBodyType != TANK_NW && pSoldier->ubBodyType != TANK_NE )
- {
- return;
- }
- }
- // We handle sight now....
- if ( pSoldier->uiStatusFlags & SOLDIER_LOOK_NEXT_TURNSOLDIER )
- {
- if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STATIONARY && pSoldier->usAnimState != CLIMBUPROOF && pSoldier->usAnimState != CLIMBDOWNROOF ) )
- {
- // HANDLE SIGHT!
- HandleSight( pSoldier,SIGHT_LOOK | SIGHT_RADIO );
- }
- // Turn off!
- pSoldier->uiStatusFlags &= (~SOLDIER_LOOK_NEXT_TURNSOLDIER );
- HandleSystemNewAISituation( pSoldier, FALSE );
- }
- if ( pSoldier->fTurningToShoot )
- {
- if ( pSoldier->bDirection == pSoldier->bDesiredDirection )
- {
- if ( ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) && !pSoldier->fTurningFromPronePosition ) || pSoldier->ubBodyType == ROBOTNOWEAPON || pSoldier->ubBodyType == TANK_NW || pSoldier->ubBodyType == TANK_NE )
- {
- EVENT_InitNewSoldierAnim( pSoldier, SelectFireAnimation( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ), 0, FALSE );
- pSoldier->fTurningToShoot = FALSE;
- // Save last target gridno!
- //pSoldier->sLastTarget = pSoldier->sTargetGridNo;
- }
- // Else check if we are trying to shoot and once was prone, but am now crouched because we needed to turn...
- else if ( pSoldier->fTurningFromPronePosition )
- {
- if ( IsValidStance( pSoldier, ANIM_PRONE ) )
- {
- SendChangeSoldierStanceEvent( pSoldier, ANIM_PRONE );
- pSoldier->usPendingAnimation = SelectFireAnimation( pSoldier, ANIM_PRONE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, SelectFireAnimation( pSoldier, ANIM_CROUCH ), 0, FALSE );
- }
- pSoldier->fTurningToShoot = FALSE;
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
- }
- }
- }
- if ( pSoldier->fTurningToFall )
- {
- if ( pSoldier->bDirection == pSoldier->bDesiredDirection )
- {
- SelectFallAnimation( pSoldier );
- pSoldier->fTurningToFall = FALSE;
- }
- }
- if ( pSoldier->fTurningUntilDone && ( pSoldier->ubPendingStanceChange != NO_PENDING_STANCE ) )
- {
- if ( pSoldier->bDirection == pSoldier->bDesiredDirection )
- {
- SendChangeSoldierStanceEvent( pSoldier, pSoldier->ubPendingStanceChange );
- pSoldier->ubPendingStanceChange = NO_PENDING_STANCE;
- pSoldier->fTurningUntilDone = FALSE;
- }
- }
- if ( pSoldier->fTurningUntilDone && ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION ) )
- {
- if ( pSoldier->bDirection == pSoldier->bDesiredDirection )
- {
- UINT16 usPendingAnimation;
- usPendingAnimation = pSoldier->usPendingAnimation;
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- EVENT_InitNewSoldierAnim( pSoldier, usPendingAnimation, 0 , FALSE );
- pSoldier->fTurningUntilDone = FALSE;
- }
- }
-
- // Don't do anything if we are at dest direction!
- if ( pSoldier->bDirection == pSoldier->bDesiredDirection )
- {
- if ( pSoldier->ubBodyType == TANK_NW || pSoldier->ubBodyType == TANK_NE )
- {
- if ( pSoldier->iTuringSoundID != NO_SAMPLE )
- {
- SoundStop( pSoldier->iTuringSoundID );
- pSoldier->iTuringSoundID = NO_SAMPLE;
- PlaySoldierJA2Sample( pSoldier->ubID, TURRET_STOP, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
- }
- }
- // Turn off!
- pSoldier->uiStatusFlags &= (~SOLDIER_LOOK_NEXT_TURNSOLDIER );
- pSoldier->fDontUnsetLastTargetFromTurn = FALSE;
- // Unset ui busy if from ui
- if ( pSoldier->bTurningFromUI && ( pSoldier->fTurningFromPronePosition != 3 ) && ( pSoldier->fTurningFromPronePosition != 1 ) )
- {
- UnSetUIBusy( pSoldier->ubID );
- pSoldier->bTurningFromUI = FALSE;
- }
- if ( pSoldier->uiStatusFlags & ( SOLDIER_VEHICLE ) || CREATURE_OR_BLOODCAT( pSoldier ) )
- {
- pSoldier->uiStatusFlags &= (~SOLDIER_PAUSEANIMOVE);
- }
- FreeUpNPCFromTurning( pSoldier, LOOK);
- // Undo our flag for prone turning...
- // Else check if we are trying to shoot and once was prone, but am now crouched because we needed to turn...
- if ( pSoldier->fTurningFromPronePosition == TURNING_FROM_PRONE_ON )
- {
- // ATE: Don't do this if we have something in our hands we are going to throw!
- if ( IsValidStance( pSoldier, ANIM_PRONE ) && pSoldier->pTempObject == NULL )
- {
- SendChangeSoldierStanceEvent( pSoldier, ANIM_PRONE );
- }
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
- }
- // If a special code, make guy crawl after stance change!
- if ( pSoldier->fTurningFromPronePosition == TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE && pSoldier->usAnimState != PRONE_UP && pSoldier->usAnimState != PRONE_DOWN )
- {
- if ( IsValidStance( pSoldier, ANIM_PRONE ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, CRAWLING, 0, FALSE );
- }
- }
- if ( pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT )
- {
- if ( pSoldier->fGettingHit == 1 )
- {
- if ( pSoldier->usPendingAnimation != FALLFORWARD_ROOF && pSoldier->usPendingAnimation != FALLOFF && pSoldier->usAnimState != FALLFORWARD_ROOF && pSoldier->usAnimState != FALLOFF )
- {
- // Go back to original direction
- EVENT_SetSoldierDesiredDirection( pSoldier, (INT8)pSoldier->uiPendingActionData1 );
- //SETUP GETTING HIT FLAG TO 2
- pSoldier->fGettingHit = 2;
- }
- else
- {
- pSoldier->uiStatusFlags &= (~SOLDIER_TURNINGFROMHIT );
- }
- }
- else if ( pSoldier->fGettingHit == 2 )
- {
- // Turn off
- pSoldier->uiStatusFlags &= (~SOLDIER_TURNINGFROMHIT );
- // Release attacker
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, turning from hit animation ended") );
- ReleaseSoldiersAttacker( pSoldier );
- //FREEUP GETTING HIT FLAG
- pSoldier->fGettingHit = FALSE;
- }
- }
- return;
- }
- // IF WE ARE HERE, WE ARE IN THE PROCESS OF TURNING
- // DOUBLE CHECK TO UNSET fNOAPs...
- if ( pSoldier->fNoAPToFinishMove )
- {
- AdjustNoAPToFinishMove( pSoldier, FALSE );
- }
- // Do something different for vehicles....
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- fDoDirectionChange = FALSE;
- // Get new direction
- /*
- sDirection = pSoldier->ubHiResDirection + ExtQuickestDirection( pSoldier->ubHiResDirection, pSoldier->ubHiResDesiredDirection );
- */
- sDirection = pSoldier->ubHiResDirection + pSoldier->bTurningIncrement;
- if (sDirection > 31)
- {
- sDirection = 0;
- }
- else
- {
- if ( sDirection < 0 )
- {
- sDirection = 31;
- }
- }
- pSoldier->ubHiResDirection = (UINT8)sDirection;
- // Are we at a multiple of a 'cardnal' direction?
- for ( cnt = 0; cnt < 8; cnt++ )
- {
- if ( sDirection == ubExtDirection[ cnt ] )
- {
- fDoDirectionChange = TRUE;
- sDirection = (INT16)cnt;
- break;
- }
- }
- if ( pSoldier->ubBodyType == TANK_NW || pSoldier->ubBodyType == TANK_NE )
- {
- if ( pSoldier->iTuringSoundID == NO_SAMPLE )
- {
- pSoldier->iTuringSoundID = PlaySoldierJA2Sample( pSoldier->ubID, TURRET_MOVE, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 100, SoundDir( pSoldier->sGridNo ), TRUE );
- }
- }
- }
- else
- {
- // Get new direction
- //sDirection = pSoldier->bDirection + QuickestDirection( pSoldier->bDirection, pSoldier->bDesiredDirection );
- sDirection = pSoldier->bDirection + pSoldier->bTurningIncrement;
- if (sDirection > 7)
- {
- sDirection = 0;
- }
- else
- {
- if ( sDirection < 0 )
- {
- sDirection = 7;
- }
- }
- }
- // CHECK FOR A VALID TURN DIRECTION
- // This is needed for prone animations as well as any multi-tiled structs
- if ( fDoDirectionChange )
- {
- if ( OKToAddMercToWorld( pSoldier, (INT8)sDirection ) )
- {
- // Don't do this if we are walkoing off screen...
- if ( gubWaitingForAllMercsToExitCode == WAIT_FOR_MERCS_TO_WALKOFF_SCREEN || gubWaitingForAllMercsToExitCode == WAIT_FOR_MERCS_TO_WALK_TO_GRIDNO )
- {
- }
- else
- {
- // ATE: We should only do this if we are STATIONARY!
- if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STATIONARY ) )
- {
- pSoldier->uiStatusFlags |= SOLDIER_LOOK_NEXT_TURNSOLDIER;
- }
- // otherwise, it's handled next tile...
- }
- EVENT_SetSoldierDirection( pSoldier, sDirection );
- if ( pSoldier->ubBodyType != LARVAE_MONSTER && !MercInWater( pSoldier ) && pSoldier->bOverTerrainType != DIRT_ROAD && pSoldier->bOverTerrainType != PAVED_ROAD )
- {
- PlaySoldierFootstepSound( pSoldier );
- }
- }
- else
- {
- // Are we prone crawling?
- if ( pSoldier->usAnimState == CRAWLING )
- {
- // OK, we want to getup, turn and go prone again....
- SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH );
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE;
- }
- // If we are a creature, or multi-tiled, cancel AI action.....?
- else if ( pSoldier->uiStatusFlags & SOLDIER_MULTITILE )
- {
- pSoldier->bDesiredDirection = pSoldier->bDirection;
- }
- }
- }
- }
- UINT8 gRedGlowR[]=
- {
- 0, // Normal shades
- 25,
- 50,
- 75,
- 100,
- 125,
- 150,
- 175,
- 200,
- 225,
- 0, // For gray palettes
- 25,
- 50,
- 75,
- 100,
- 125,
- 150,
- 175,
- 200,
- 225,
- };
- #if 0
- UINT8 gOrangeGlowR[]=
- {
- 0, // Normal shades
- 20,
- 40,
- 60,
- 80,
- 100,
- 120,
- 140,
- 160,
- 180,
- 0, // For gray palettes
- 20,
- 40,
- 60,
- 80,
- 100,
- 120,
- 140,
- 160,
- 180,
- };
- #endif
- UINT8 gOrangeGlowR[]=
- {
- 0, // Normal shades
- 25,
- 50,
- 75,
- 100,
- 125,
- 150,
- 175,
- 200,
- 225,
- 0, // For gray palettes
- 25,
- 50,
- 75,
- 100,
- 125,
- 150,
- 175,
- 200,
- 225,
- };
- #if 0
- UINT8 gOrangeGlowG[]=
- {
- 0, // Normal shades
- 5,
- 10,
- 25,
- 30,
- 35,
- 40,
- 45,
- 50,
- 55,
- 0, // For gray palettes
- 5,
- 10,
- 25,
- 30,
- 35,
- 40,
- 45,
- 50,
- 55,
- };
- #endif
- UINT8 gOrangeGlowG[]=
- {
- 0, // Normal shades
- 20,
- 40,
- 60,
- 80,
- 100,
- 120,
- 140,
- 160,
- 180,
- 0, // For gray palettes
- 20,
- 40,
- 60,
- 80,
- 100,
- 120,
- 140,
- 160,
- 180,
- };
- BOOLEAN CreateSoldierPalettes( SOLDIERTYPE *pSoldier )
- {
- UINT16 usAnimSurface, usPaletteAnimSurface;
- CHAR8 zColFilename[ 100 ];
- INT32 iWhich;
- INT32 cnt;
- INT8 bBodyTypePalette;
- SGPPaletteEntry Temp8BPPPalette[ 256 ];
- //NT32 uiCount;
- //PPaletteEntry Pal[256];
- if ( pSoldier->p8BPPPalette != NULL )
- {
- MemFree( pSoldier->p8BPPPalette );
- pSoldier->p8BPPPalette = NULL;
- }
- // Allocate mem for new palette
- pSoldier->p8BPPPalette = MemAlloc( sizeof( SGPPaletteEntry ) * 256 );
- memset( pSoldier->p8BPPPalette, 0, sizeof( SGPPaletteEntry ) * 256 );
- CHECKF( pSoldier->p8BPPPalette != NULL );
- // --- TAKE FROM CURRENT ANIMATION HVOBJECT!
- usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
- CHECKF( usAnimSurface != INVALID_ANIMATION_SURFACE );
- if ( ( bBodyTypePalette = GetBodyTypePaletteSubstitutionCode( pSoldier, pSoldier->ubBodyType, zColFilename ) ) == -1 )
- {
- // ATE: here we want to use the breath cycle for the palette.....
- usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, STANDING );
- if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
- {
- // Use palette from HVOBJECT, then use substitution for pants, etc
- memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
- // Substitute based on head, etc
- SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
- SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
- SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
- SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
- }
- }
- else if ( bBodyTypePalette == 0 )
- {
- // Use palette from hvobject
- memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
- }
- else
- {
- // Use col file
- if ( CreateSGPPaletteFromCOLFile( Temp8BPPPalette, zColFilename ) )
- {
- // Copy into palette
- memcpy( pSoldier->p8BPPPalette, Temp8BPPPalette, sizeof( pSoldier->p8BPPPalette ) * 256 );
- }
- else
- {
- // Use palette from hvobject
- memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
- }
- }
- if ( pSoldier->p16BPPPalette != NULL )
- {
- MemFree( pSoldier->p16BPPPalette );
- pSoldier->p16BPPPalette = NULL;
- }
- // -- BUILD 16BPP Palette from this
- pSoldier->p16BPPPalette = Create16BPPPalette( pSoldier->p8BPPPalette );
- for ( iWhich = 0; iWhich < NUM_SOLDIER_SHADES; iWhich++ )
- {
- if ( pSoldier->pShades[ iWhich ] != NULL )
- {
- MemFree( pSoldier->pShades[ iWhich ] );
- pSoldier->pShades[ iWhich ] = NULL;
- }
- }
- for ( iWhich = 0; iWhich < NUM_SOLDIER_EFFECTSHADES; iWhich++ )
- {
- if ( pSoldier->pEffectShades[ iWhich ] != NULL )
- {
- MemFree( pSoldier->pEffectShades[ iWhich ] );
- pSoldier->pEffectShades[ iWhich ] = NULL;
- }
- }
- for ( iWhich = 0; iWhich < 20; iWhich++ )
- {
- if ( pSoldier->pGlowShades[ iWhich ] != NULL )
- {
- MemFree( pSoldier->pGlowShades[ iWhich ] );
- pSoldier->pGlowShades[ iWhich ] = NULL;
- }
- }
- CreateSoldierPaletteTables( pSoldier, HVOBJECT_GLOW_GREEN );
-
- // Build a grayscale palette for testing grayout of mercs
- //for(uiCount=0; uiCount < 256; uiCount++)
- //{
- // Pal[uiCount].peRed=(UINT8)(uiCount%128)+128;
- // Pal[uiCount].peGreen=(UINT8)(uiCount%128)+128;
- // Pal[uiCount].peBlue=(UINT8)(uiCount%128)+128;
- //}
- pSoldier->pEffectShades[ 0 ] = Create16BPPPaletteShaded( pSoldier->p8BPPPalette, 100, 100, 100, TRUE );
- pSoldier->pEffectShades[ 1 ] = Create16BPPPaletteShaded( pSoldier->p8BPPPalette, 100, 150, 100, TRUE );
- // Build shades for glowing visible bad guy
- // First do visible guy
- pSoldier->pGlowShades[ 0 ] = Create16BPPPaletteShaded( pSoldier->p8BPPPalette, 255, 255, 255, FALSE );
- for ( cnt = 1; cnt < 10; cnt++ )
- {
- pSoldier->pGlowShades[ cnt ] = CreateEnemyGlow16BPPPalette( pSoldier->p8BPPPalette, gRedGlowR[cnt], 255, FALSE );
- }
- // Now for gray guy...
- pSoldier->pGlowShades[ 10 ] = Create16BPPPaletteShaded( pSoldier->p8BPPPalette, 100, 100, 100, TRUE );
- for ( cnt = 11; cnt < 19; cnt++ )
- {
- pSoldier->pGlowShades[ cnt ] = CreateEnemyGreyGlow16BPPPalette( pSoldier->p8BPPPalette, gRedGlowR[cnt], 0, FALSE );
- }
- pSoldier->pGlowShades[ 19 ] = CreateEnemyGreyGlow16BPPPalette( pSoldier->p8BPPPalette, gRedGlowR[18], 0, FALSE );
- // ATE: OK, piggyback on the shades we are not using for 2 colored lighting....
- // ORANGE, VISIBLE GUY
- pSoldier->pShades[ 20 ] = Create16BPPPaletteShaded( pSoldier->p8BPPPalette, 255, 255, 255, FALSE );
- for ( cnt = 21; cnt < 30; cnt++ )
- {
- pSoldier->pShades[ cnt ] = CreateEnemyGlow16BPPPalette( pSoldier->p8BPPPalette, gOrangeGlowR[ ( cnt - 20 )], gOrangeGlowG[ ( cnt - 20 ) ], TRUE );
- }
- // ORANGE, GREY GUY
- pSoldier->pShades[ 30 ] = Create16BPPPaletteShaded( pSoldier->p8BPPPalette, 100, 100, 100, TRUE );
- for ( cnt = 31; cnt < 39; cnt++ )
- {
- pSoldier->pShades[ cnt ] = CreateEnemyGreyGlow16BPPPalette( pSoldier->p8BPPPalette, gOrangeGlowR[ ( cnt - 20 ) ], gOrangeGlowG[ ( cnt - 20 ) ], TRUE );
- }
- pSoldier->pShades[ 39 ] = CreateEnemyGreyGlow16BPPPalette( pSoldier->p8BPPPalette, gOrangeGlowR[18], gOrangeGlowG[18], TRUE );
- return( TRUE );
- }
- void AdjustAniSpeed( SOLDIERTYPE *pSoldier )
- {
- if ( ( gTacticalStatus.uiFlags & SLOW_ANIMATION ) )
- {
- if ( gTacticalStatus.bRealtimeSpeed == -1 )
- {
- pSoldier->sAniDelay = 10000;
- }
- else
- {
- pSoldier->sAniDelay = pSoldier->sAniDelay * ( 1 * gTacticalStatus.bRealtimeSpeed / 2 );
- }
- }
- RESETTIMECOUNTER( pSoldier->UpdateCounter, pSoldier->sAniDelay );
- }
- void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier )
- {
- UINT32 uiTerrainDelay;
- UINT32 uiSpeed = 0;
-
- INT8 bBreathDef, bLifeDef, bAgilDef;
- INT8 bAdditional = 0;
-
- // for those animations which have a speed of zero, we have to calculate it
- // here. Some animation, such as water-movement, have an ADDITIONAL speed
- switch( pSoldier->usAnimState )
- {
- case PRONE:
- case STANDING:
- pSoldier->sAniDelay = ( pStatsSoldier->bBreath * 2 ) + (100 - pStatsSoldier->bLife );
- // Limit it!
- if ( pSoldier->sAniDelay < 40 )
- {
- pSoldier->sAniDelay = 40;
- }
- AdjustAniSpeed( pSoldier );
- return;
- case CROUCHING:
- pSoldier->sAniDelay = ( pStatsSoldier->bBreath * 2 ) + ( (100 - pStatsSoldier->bLife ) );
- // Limit it!
- if ( pSoldier->sAniDelay < 40 )
- {
- pSoldier->sAniDelay = 40;
- }
- AdjustAniSpeed( pSoldier );
- return;
- case WALKING:
- // Adjust based on body type
- bAdditional = (UINT8)( gubAnimWalkSpeeds[ pStatsSoldier->ubBodyType ].sSpeed );
- if ( bAdditional < 0 )
- bAdditional = 0;
- break;
- case RUNNING:
- // Adjust based on body type
- bAdditional = (UINT8)gubAnimRunSpeeds[ pStatsSoldier->ubBodyType ].sSpeed;
- if ( bAdditional < 0 )
- bAdditional = 0;
- break;
- case SWATTING:
- // Adjust based on body type
- if ( pStatsSoldier->ubBodyType <= REGFEMALE )
- {
- bAdditional = (UINT8)gubAnimSwatSpeeds[ pStatsSoldier->ubBodyType ].sSpeed;
- if ( bAdditional < 0 )
- bAdditional = 0;
- }
- break;
- case CRAWLING:
- // Adjust based on body type
- if ( pStatsSoldier->ubBodyType <= REGFEMALE )
- {
- bAdditional = (UINT8)gubAnimCrawlSpeeds[ pStatsSoldier->ubBodyType ].sSpeed;
- if ( bAdditional < 0 )
- bAdditional = 0;
- }
- break;
- case READY_RIFLE_STAND:
- // Raise rifle based on aim vs non-aim.
- if ( pSoldier->bAimTime == 0 )
- {
- // Quick shot
- pSoldier->sAniDelay = 70;
- }
- else
- {
- pSoldier->sAniDelay = 150;
- }
- AdjustAniSpeed( pSoldier );
- return;
- }
- // figure out movement speed (terrspeed)
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING )
- {
- uiSpeed = gsTerrainTypeSpeedModifiers[ pStatsSoldier->bOverTerrainType ];
- uiTerrainDelay = uiSpeed;
- }
- else
- {
- uiTerrainDelay = 40; // standing still
- }
- bBreathDef = 50 - ( pStatsSoldier->bBreath / 2 );
- if ( bBreathDef > 30 )
- bBreathDef = 30;
- bAgilDef = 50 - ( EffectiveAgility( pStatsSoldier ) / 4 );
- bLifeDef = 50 - ( pStatsSoldier->bLife / 2 );
- uiTerrainDelay += ( bLifeDef + bBreathDef + bAgilDef + bAdditional );
- pSoldier->sAniDelay = (INT16)uiTerrainDelay;
- // If a moving animation and w/re on drugs, increase speed....
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING )
- {
- if ( GetDrugEffect( pSoldier, DRUG_TYPE_ADRENALINE ) )
- {
- pSoldier->sAniDelay = pSoldier->sAniDelay / 2;
- }
- }
- // MODIFTY NOW BASED ON REAL-TIME, ETC
- // Adjust speed, make twice as fast if in turn-based!
- if ( gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) )
- {
- pSoldier->sAniDelay = pSoldier->sAniDelay / 2;
- }
- // MODIFY IF REALTIME COMBAT
- if ( !( gTacticalStatus.uiFlags & INCOMBAT ) )
- {
- // ATE: If realtime, and stealth mode...
- if ( pStatsSoldier->bStealthMode )
- {
- pSoldier->sAniDelay = (INT16)( pSoldier->sAniDelay * 2 );
- }
- //pSoldier->sAniDelay = pSoldier->sAniDelay * ( 1 * gTacticalStatus.bRealtimeSpeed / 2 );
- }
- }
- void SetSoldierAniSpeed( SOLDIERTYPE *pSoldier )
- {
- SOLDIERTYPE *pStatsSoldier;
-
- // ATE: If we are an enemy and are not visible......
- // Set speed to 0
- if ( ( gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) ) || gTacticalStatus.fAutoBandageMode )
- {
- if ( ( ( pSoldier->bVisible == -1 && pSoldier->bVisible == pSoldier->bLastRenderVisibleValue ) || gTacticalStatus.fAutoBandageMode ) && pSoldier->usAnimState != MONSTER_UP )
- {
- pSoldier->sAniDelay = 0;
- RESETTIMECOUNTER( pSoldier->UpdateCounter, pSoldier->sAniDelay );
- return;
- }
- }
- // Default stats soldier to same as normal soldier.....
- pStatsSoldier = pSoldier;
- if ( pSoldier->fUseMoverrideMoveSpeed )
- {
- pStatsSoldier = MercPtrs[ pSoldier->bOverrideMoveSpeed ];
- }
- // Only calculate if set to zero
- if ( ( pSoldier->sAniDelay = gAnimControl[ pSoldier->usAnimState ].sSpeed ) == 0 )
- {
- CalculateSoldierAniSpeed( pSoldier, pStatsSoldier );
- }
- AdjustAniSpeed( pSoldier );
- if ( _KeyDown( SPACE ) )
- {
- //pSoldier->sAniDelay = 1000;
- }
- }
- ///////////////////////////////////////////////////////
- //PALETTE REPLACEMENT FUNCTIONS
- ///////////////////////////////////////////////////////
- BOOLEAN LoadPaletteData( )
- {
- HWFILE hFile;
- UINT32 cnt, cnt2;
- hFile = FileOpen( PALETTEFILENAME, FILE_ACCESS_READ, FALSE );
- // Read # of types
- if ( !FileRead( hFile, &guiNumPaletteSubRanges, sizeof( guiNumPaletteSubRanges ), NULL ) )
- {
- return( FALSE );
- }
- // Malloc!
- gpPaletteSubRanges = MemAlloc( sizeof( PaletteSubRangeType ) * guiNumPaletteSubRanges );
- gubpNumReplacementsPerRange = MemAlloc( sizeof( UINT8 ) * guiNumPaletteSubRanges );
- // Read # of types for each!
- for ( cnt = 0; cnt < guiNumPaletteSubRanges; cnt++ )
- {
- if ( !FileRead( hFile, &gubpNumReplacementsPerRange[ cnt ], sizeof( UINT8 ), NULL ) )
- {
- return( FALSE );
- }
- }
- // Loop for each one, read in data
- for ( cnt = 0; cnt < guiNumPaletteSubRanges; cnt++ )
- {
- if ( !FileRead( hFile, &gpPaletteSubRanges[ cnt ].ubStart, sizeof( UINT8 ), NULL ) )
- {
- return( FALSE );
- }
- if ( !FileRead( hFile, &gpPaletteSubRanges[ cnt ].ubEnd, sizeof( UINT8 ), NULL ) )
- {
- return( FALSE );
- }
- }
- // Read # of palettes
- if ( !FileRead( hFile, &guiNumReplacements, sizeof( guiNumReplacements ), NULL ) )
- {
- return( FALSE );
- }
- // Malloc!
- gpPalRep = MemAlloc( sizeof( PaletteReplacementType ) * guiNumReplacements );
- // Read!
- for ( cnt = 0; cnt < guiNumReplacements; cnt++ )
- {
- // type
- if ( !FileRead( hFile, &gpPalRep[ cnt ].ubType, sizeof( gpPalRep[ cnt ].ubType ), NULL ) )
- {
- return( FALSE );
- }
- if ( !FileRead( hFile, &gpPalRep[ cnt ].ID, sizeof( gpPalRep[ cnt ].ID ), NULL ) )
- {
- return( FALSE );
- }
-
- // # entries
- if ( !FileRead( hFile, &gpPalRep[ cnt ].ubPaletteSize, sizeof( gpPalRep[ cnt ].ubPaletteSize ), NULL ) )
- {
- return( FALSE );
- }
- // Malloc
- gpPalRep[ cnt ].r = MemAlloc( gpPalRep[ cnt ].ubPaletteSize );
- CHECKF( gpPalRep[ cnt ].r != NULL );
- gpPalRep[ cnt ].g = MemAlloc( gpPalRep[ cnt ].ubPaletteSize );
- CHECKF( gpPalRep[ cnt ].g != NULL );
- gpPalRep[ cnt ].b = MemAlloc( gpPalRep[ cnt ].ubPaletteSize );
- CHECKF( gpPalRep[ cnt ].b != NULL );
- for( cnt2 = 0; cnt2 < gpPalRep[ cnt ].ubPaletteSize; cnt2++ )
- {
- if ( !FileRead( hFile, &gpPalRep[ cnt ].r[ cnt2 ], sizeof( UINT8 ), NULL ) )
- {
- return( FALSE );
- }
- if ( !FileRead( hFile, &gpPalRep[ cnt ].g[ cnt2 ], sizeof( UINT8 ), NULL ) )
- {
- return( FALSE );
- }
- if ( !FileRead( hFile, &gpPalRep[ cnt ].b[ cnt2 ], sizeof( UINT8 ), NULL ) )
- {
- return( FALSE );
- }
- }
- }
- FileClose( hFile );
-
- return( TRUE );
- }
- BOOLEAN SetPaletteReplacement( SGPPaletteEntry *p8BPPPalette, PaletteRepID aPalRep )
- {
- UINT32 cnt2;
- UINT8 ubType;
- UINT8 ubPalIndex;
- CHECKF( GetPaletteRepIndexFromID( aPalRep, &ubPalIndex ) );
- // Get range type
- ubType = gpPalRep[ ubPalIndex ].ubType;
- for ( cnt2 = gpPaletteSubRanges[ ubType ].ubStart; cnt2 <= gpPaletteSubRanges[ ubType ].ubEnd; cnt2++ )
- {
- p8BPPPalette[ cnt2 ].peRed = gpPalRep[ ubPalIndex ].r[ cnt2 - gpPaletteSubRanges[ ubType ].ubStart ];
- p8BPPPalette[ cnt2 ].peGreen = gpPalRep[ ubPalIndex ].g[ cnt2 - gpPaletteSubRanges[ ubType ].ubStart ];
- p8BPPPalette[ cnt2 ].peBlue = gpPalRep[ ubPalIndex ].b[ cnt2 - gpPaletteSubRanges[ ubType ].ubStart ];
- }
- return( TRUE );
- }
- BOOLEAN DeletePaletteData( )
- {
- UINT32 cnt;
- // Free!
- if ( gpPaletteSubRanges != NULL )
- {
- MemFree( gpPaletteSubRanges );
- gpPaletteSubRanges = NULL;
- }
- if ( gubpNumReplacementsPerRange != NULL )
- {
- MemFree( gubpNumReplacementsPerRange );
- gubpNumReplacementsPerRange = NULL;
- }
- for ( cnt = 0; cnt < guiNumReplacements; cnt++ )
- {
- // Free
- if ( gpPalRep[ cnt ].r != NULL )
- {
- MemFree( gpPalRep[ cnt ].r );
- gpPalRep[ cnt ].r = NULL;
- }
- if ( gpPalRep[ cnt ].g != NULL )
- {
- MemFree( gpPalRep[ cnt ].g );
- gpPalRep[ cnt ].g = NULL;
- }
- if ( gpPalRep[ cnt ].b != NULL )
- {
- MemFree( gpPalRep[ cnt ].b );
- gpPalRep[ cnt ].b = NULL;
- }
- }
- // Free
- if ( gpPalRep != NULL )
- {
- MemFree( gpPalRep );
- gpPalRep = NULL;
- }
-
- return( TRUE );
- }
- BOOLEAN GetPaletteRepIndexFromID( PaletteRepID aPalRep, UINT8 *pubPalIndex )
- {
- UINT32 cnt;
- // Check if type exists
- for ( cnt = 0; cnt < guiNumReplacements; cnt++ )
- {
- if ( COMPARE_PALETTEREP_ID( aPalRep, gpPalRep[ cnt ].ID ) )
- {
- *pubPalIndex = ( UINT8 )cnt;
- return( TRUE );
- }
- }
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Invalid Palette Replacement ID given");
- return( FALSE );
- }
- UINT16 GetNewSoldierStateFromNewStance( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance )
- {
- UINT16 usNewState;
- INT8 bCurrentHeight;
- bCurrentHeight = ( ubDesiredStance - gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
- // Now change to appropriate animation
- switch( bCurrentHeight )
- {
- case ANIM_STAND - ANIM_CROUCH:
- usNewState = KNEEL_UP;
- break;
- case ANIM_CROUCH - ANIM_STAND:
- usNewState = KNEEL_DOWN;
- break;
- case ANIM_STAND - ANIM_PRONE:
- usNewState = PRONE_UP;
- break;
- case ANIM_PRONE - ANIM_STAND:
- usNewState = KNEEL_DOWN;
- break;
- case ANIM_CROUCH - ANIM_PRONE:
- usNewState = PRONE_UP;
- break;
- case ANIM_PRONE - ANIM_CROUCH:
- usNewState = PRONE_DOWN;
- break;
- default:
- // Cannot get here unless ub desired stance is bogus
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "GetNewSoldierStateFromNewStance bogus ubDesiredStance value %d", ubDesiredStance ) );
- usNewState = pSoldier->usAnimState;
- }
-
- return( usNewState );
- }
- void MoveMercFacingDirection( SOLDIERTYPE *pSoldier, BOOLEAN fReverse, FLOAT dMovementDist )
- {
- FLOAT dAngle = (FLOAT)0;
- // Determine which direction we are in
- switch( pSoldier->bDirection )
- {
- case NORTH:
- dAngle = (FLOAT)( -1 * PI );
- break;
- case NORTHEAST:
- dAngle = (FLOAT)( PI * .75 );
- break;
- case EAST:
- dAngle = (FLOAT)( PI / 2 );
- break;
- case SOUTHEAST:
- dAngle = (FLOAT)( PI / 4 );
- break;
- case SOUTH:
- dAngle = (FLOAT)0;
- break;
- case SOUTHWEST:
- //dAngle = (FLOAT)( PI * -.25 );
- dAngle = (FLOAT)-0.786;
- break;
- case WEST:
- dAngle = (FLOAT) ( PI *-.5 );
- break;
- case NORTHWEST:
- dAngle = (FLOAT) ( PI * -.75 );
- break;
- }
- if ( fReverse )
- {
- dMovementDist = dMovementDist * -1;
- }
- MoveMerc( pSoldier, dMovementDist, dAngle, FALSE );
- }
- void BeginSoldierClimbUpRoof( SOLDIERTYPE *pSoldier )
- {
- INT8 bNewDirection;
- if ( FindHeigherLevel( pSoldier, pSoldier->sGridNo, pSoldier->bDirection, &bNewDirection ) && ( pSoldier->bLevel == 0 ) )
- {
- if ( EnoughPoints( pSoldier, GetAPsToClimbRoof( pSoldier, FALSE ), 0, TRUE ) )
- {
- if (pSoldier->bTeam == gbPlayerNum)
- {
- // OK, SET INTERFACE FIRST
- SetUIBusy( pSoldier->ubID );
- }
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)DirectionInc(bNewDirection ) );
- pSoldier->ubPendingDirection = bNewDirection;
- //pSoldier->usPendingAnimation = CLIMBUPROOF;
- EVENT_InitNewSoldierAnim( pSoldier, CLIMBUPROOF, 0 , FALSE );
- InternalReceivingSoldierCancelServices( pSoldier, FALSE );
- InternalGivingSoldierCancelServices( pSoldier, FALSE );
- }
- }
- }
- void BeginSoldierClimbFence( SOLDIERTYPE *pSoldier )
- {
- INT8 bDirection;
- if ( FindFenceJumpDirection( pSoldier, pSoldier->sGridNo, pSoldier->bDirection, &bDirection ) )
- {
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)DirectionInc(bDirection ) );
- pSoldier->fDontChargeTurningAPs = TRUE;
- EVENT_InternalSetSoldierDesiredDirection( pSoldier, bDirection, FALSE, pSoldier->usAnimState );
- pSoldier->fTurningUntilDone = TRUE;
- // ATE: Reset flag to go back to prone...
- pSoldier->fTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
- pSoldier->usPendingAnimation = HOPFENCE;
- }
- }
- UINT32 SleepDartSuccumbChance( SOLDIERTYPE * pSoldier )
- {
- UINT32 uiChance;
- INT8 bEffectiveStrength;
- // figure out base chance of succumbing,
- bEffectiveStrength = EffectiveStrength( pSoldier );
- if (bEffectiveStrength > 90)
- {
- uiChance = 110 - bEffectiveStrength;
- }
- else if (bEffectiveStrength > 80)
- {
- uiChance = 120 - bEffectiveStrength;
- }
- else if (bEffectiveStrength > 70)
- {
- uiChance = 130 - bEffectiveStrength;
- }
- else
- {
- uiChance = 140 - bEffectiveStrength;
- }
- // add in a bonus based on how long it's been since shot... highest chance at the beginning
- uiChance += (10 - pSoldier->bSleepDrugCounter);
- return( uiChance );
- }
- void BeginSoldierGetup( SOLDIERTYPE *pSoldier )
- {
- // RETURN IF WE ARE BEING SERVICED
- if ( pSoldier->ubServiceCount > 0 )
- {
- return;
- }
- // ATE: Don't getup if we are in a meanwhile
- if ( AreInMeanwhile( ) )
- {
- return;
- }
- if ( pSoldier->bCollapsed )
- {
- if ( pSoldier->bLife >= OKLIFE && pSoldier->bBreath >= OKBREATH && (pSoldier->bSleepDrugCounter == 0) )
- {
- // get up you hoser!
- pSoldier->bCollapsed = FALSE;
- pSoldier->bTurnsCollapsed = 0;
- if ( IS_MERC_BODY_TYPE( pSoldier ) )
- {
- switch( pSoldier->usAnimState )
- {
- case FALLOFF_FORWARD_STOP:
- case PRONE_LAYFROMHIT_STOP:
- case STAND_FALLFORWARD_STOP:
- ChangeSoldierStance( pSoldier, ANIM_CROUCH );
- break;
- case FALLBACKHIT_STOP:
- case FALLOFF_STOP:
- case FLYBACKHIT_STOP:
- case FALLBACK_HIT_STAND:
- case FALLOFF:
- case FLYBACK_HIT:
- // ROLL OVER
- EVENT_InitNewSoldierAnim( pSoldier, ROLLOVER, 0 , FALSE );
- break;
-
- default:
- ChangeSoldierStance( pSoldier, ANIM_CROUCH );
- break;
- }
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, END_COWER, 0 , FALSE );
- }
- }
- else
- {
- pSoldier->bTurnsCollapsed++;
- if ( (gTacticalStatus.bBoxingState == BOXING) && (pSoldier->uiStatusFlags & SOLDIER_BOXER) )
- {
- if (pSoldier->bTurnsCollapsed > 1)
- {
- // We have a winnah! But it isn't this boxer!
- EndBoxingMatch( pSoldier );
- }
- }
- }
- }
- else if ( pSoldier->bSleepDrugCounter > 0 )
- {
- UINT32 uiChance;
- uiChance = SleepDartSuccumbChance( pSoldier );
- if ( PreRandom( 100 ) < uiChance )
- {
- // succumb to the drug!
- DeductPoints( pSoldier, 0, (INT16)( pSoldier->bBreathMax * 100 ) );
- SoldierCollapse( pSoldier );
- }
- }
- if ( pSoldier->bSleepDrugCounter > 0 )
- {
- pSoldier->bSleepDrugCounter--;
- }
- }
- void HandleTakeDamageDeath( SOLDIERTYPE *pSoldier, UINT8 bOldLife, UINT8 ubReason )
- {
- switch( ubReason )
- {
- case TAKE_DAMAGE_BLOODLOSS:
- case TAKE_DAMAGE_ELECTRICITY:
- case TAKE_DAMAGE_GAS:
-
- if ( pSoldier->bInSector )
- {
- if ( pSoldier->bVisible != -1 )
- {
- if ( ubReason != TAKE_DAMAGE_BLOODLOSS )
- {
- DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 );
- pSoldier->fDeadSoundPlayed = TRUE;
- }
- }
- if ( ( ubReason == TAKE_DAMAGE_ELECTRICITY ) && pSoldier->bLife < OKLIFE )
- {
- pSoldier->fInNonintAnim = FALSE;
- }
- // Check for < OKLIFE
- if ( pSoldier->bLife < OKLIFE && pSoldier->bLife != 0 && !pSoldier->bCollapsed)
- {
- SoldierCollapse( pSoldier );
- }
- // THis is for the die animation that will be happening....
- if ( pSoldier->bLife == 0 )
- {
- pSoldier->fDoingExternalDeath = TRUE;
- }
- // Check if he is dead....
- CheckForAndHandleSoldierDyingNotFromHit( pSoldier );
- }
- //if( !( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
- {
- HandleSoldierTakeDamageFeedback( pSoldier );
- }
- if(( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) || !pSoldier->bInSector )
- {
- if ( pSoldier->bLife == 0 && !( pSoldier->uiStatusFlags & SOLDIER_DEAD ) )
- {
- StrategicHandlePlayerTeamMercDeath( pSoldier );
- // ATE: Here, force always to use die sound...
- pSoldier->fDieSoundUsed = FALSE;
- DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 );
- pSoldier->fDeadSoundPlayed = TRUE;
- // ATE: DO death sound
- PlayJA2Sample( (UINT8)DOORCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
- PlayJA2Sample( (UINT8)HEADCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
- }
- }
- break;
- }
- if ( ubReason == TAKE_DAMAGE_ELECTRICITY )
- {
- if ( pSoldier->bLife >= OKLIFE )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Freeing up attacker from electricity damage") );
- ReleaseSoldiersAttacker( pSoldier );
- }
- }
- }
- UINT8 SoldierTakeDamage( SOLDIERTYPE *pSoldier, INT8 bHeight, INT16 sLifeDeduct, INT16 sBreathLoss, UINT8 ubReason, UINT8 ubAttacker, INT16 sSourceGrid, INT16 sSubsequent, BOOLEAN fShowDamage )
- {
- INT8 bOldLife;
- UINT8 ubCombinedLoss;
- INT8 bBandage;
- INT16 sAPCost;
- UINT8 ubBlood;
-
- pSoldier->ubLastDamageReason = ubReason;
- // CJC Jan 21 99: add check to see if we are hurting an enemy in an enemy-controlled
- // sector; if so, this is a sign of player activity
- switch ( pSoldier->bTeam )
- {
- case ENEMY_TEAM:
- // if we're in the wilderness this always counts
- if ( StrategicMap[ CALCULATE_STRATEGIC_INDEX( gWorldSectorX, gWorldSectorY ) ].fEnemyControlled || SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] != TOWN )
- {
- // update current day of activity!
- UpdateLastDayOfPlayerActivity( (UINT16) GetWorldDay() );
- }
- break;
- case CREATURE_TEAM:
- // always a sign of activity?
- UpdateLastDayOfPlayerActivity( (UINT16) GetWorldDay() );
- break;
- case CIV_TEAM:
- if ( pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP && gubQuest[ QUEST_RESCUE_MARIA ] == QUESTINPROGRESS && gTacticalStatus.bBoxingState == NOT_BOXING )
- {
- SOLDIERTYPE * pMaria = FindSoldierByProfileID( MARIA, FALSE );
- if ( pMaria && pMaria->bActive && pMaria->bInSector )
- {
- SetFactTrue( FACT_MARIA_ESCAPE_NOTICED );
- }
- }
- break;
- default:
- break;
- }
- // Deduct life!, Show damage if we want!
- bOldLife = pSoldier->bLife;
- // OK, If we are a vehicle.... damage vehicle...( people inside... )
- if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
- {
- if ( TANK( pSoldier ) )
- {
- //sLifeDeduct = (sLifeDeduct * 2) / 3;
- }
- else
- {
- if ( ubReason == TAKE_DAMAGE_GUNFIRE )
- {
- sLifeDeduct /= 3;
- }
- else if ( ubReason == TAKE_DAMAGE_EXPLOSION && sLifeDeduct > 50 )
- {
- // boom!
- sLifeDeduct *= 2;
- }
- }
- VehicleTakeDamage( pSoldier->bVehicleID, ubReason, sLifeDeduct, pSoldier->sGridNo, ubAttacker );
- HandleTakeDamageDeath( pSoldier, bOldLife, ubReason );
- return( 0 );
- }
- // ATE: If we are elloit being attacked in a meanwhile...
- if ( pSoldier->uiStatusFlags & SOLDIER_NPC_SHOOTING )
- {
- // Almost kill but not quite.....
- sLifeDeduct = ( pSoldier->bLife - 1 );
- // Turn off
- pSoldier->uiStatusFlags &= ( ~SOLDIER_NPC_SHOOTING );
- }
- // CJC: make sure Elliot doesn't bleed to death!
- if ( ubReason == TAKE_DAMAGE_BLOODLOSS && AreInMeanwhile() )
- {
- return( 0 );
- }
- // Calculate bandage
- bBandage = pSoldier->bLifeMax - pSoldier->bLife - pSoldier->bBleeding;
- if( guiCurrentScreen == MAP_SCREEN )
- {
- fReDrawFace = TRUE;
- }
- if ( CREATURE_OR_BLOODCAT( pSoldier ) )
- {
- INT16 sReductionFactor = 0;
-
- if ( pSoldier->ubBodyType == BLOODCAT )
- {
- sReductionFactor = 2;
- }
- else if (pSoldier->uiStatusFlags & SOLDIER_MONSTER)
- {
- switch( pSoldier->ubBodyType )
- {
- case LARVAE_MONSTER:
- case INFANT_MONSTER:
- sReductionFactor = 1;
- break;
- case YAF_MONSTER:
- case YAM_MONSTER:
- sReductionFactor = 4;
- break;
- case ADULTFEMALEMONSTER:
- case AM_MONSTER:
- sReductionFactor = 6;
- break;
- case QUEENMONSTER:
- // increase with range!
- if ( ubAttacker == NOBODY )
- {
- sReductionFactor = 8;
- }
- else
- {
- sReductionFactor = 4 + PythSpacesAway( MercPtrs[ ubAttacker ]->sGridNo, pSoldier->sGridNo ) / 2;
- }
- break;
- }
- }
- if ( ubReason == TAKE_DAMAGE_EXPLOSION )
- {
- sReductionFactor /= 4;
- }
- if ( sReductionFactor > 1 )
- {
- sLifeDeduct = (sLifeDeduct + (sReductionFactor / 2 ) ) / sReductionFactor;
- }
- else if ( ubReason == TAKE_DAMAGE_EXPLOSION )
- {
- // take at most 2/3rds
- sLifeDeduct = (sLifeDeduct * 2) / 3;
- }
-
- // reduce breath loss to a smaller degree, except for the queen...
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- // in fact, reduce breath loss by MORE!
- sReductionFactor = __min( sReductionFactor, 8 );
- sReductionFactor *= 2;
- }
- else
- {
- sReductionFactor /= 2;
- }
- if ( sReductionFactor > 1 )
- {
- sBreathLoss = (sBreathLoss + (sReductionFactor / 2 ) ) / sReductionFactor;
- }
- }
- if (sLifeDeduct > pSoldier->bLife)
- {
- pSoldier->bLife = 0;
- }
- else
- {
- // Decrease Health
- pSoldier->bLife -= sLifeDeduct;
- }
- // ATE: Put some logic in here to allow enemies to die quicker.....
- // Are we an enemy?
- if ( pSoldier->bSide != gbPlayerNum && !pSoldier->bNeutral && pSoldier->ubProfile == NO_PROFILE )
- {
- // ATE: Give them a chance to fall down...
- if ( pSoldier->bLife > 0 && pSoldier->bLife < ( OKLIFE - 1 ) )
- {
- // Are we taking damage from bleeding?
- if ( ubReason == TAKE_DAMAGE_BLOODLOSS )
- {
- // Fifty-fifty chance to die now!
- if ( Random( 2 ) == 0 || gTacticalStatus.Team[ pSoldier->bTeam ].bMenInSector == 1 )
- {
- // Kill!
- pSoldier->bLife = 0;
- }
- }
- else
- {
- // OK, see how far we are..
- if ( pSoldier->bLife < ( OKLIFE - 3 ) )
- {
- // Kill!
- pSoldier->bLife = 0;
- }
- }
- }
- }
- if ( fShowDamage )
- {
- pSoldier->sDamage += sLifeDeduct;
- }
- // Truncate life
- if ( pSoldier->bLife < 0 )
- {
- pSoldier->bLife = 0;
- }
- // Calculate damage to our items if from an explosion!
- if ( ubReason == TAKE_DAMAGE_EXPLOSION || ubReason == TAKE_DAMAGE_STRUCTURE_EXPLOSION)
- {
- CheckEquipmentForDamage( pSoldier, sLifeDeduct );
- }
- // Calculate bleeding
- if ( ubReason != TAKE_DAMAGE_GAS && !AM_A_ROBOT( pSoldier ) )
- {
- if ( ubReason == TAKE_DAMAGE_HANDTOHAND )
- {
- if ( sLifeDeduct > 0 )
- {
- // HTH does 1 pt bleeding per hit
- pSoldier->bBleeding = pSoldier->bBleeding + 1;
- }
- }
- else
- {
- pSoldier->bBleeding = pSoldier->bLifeMax - ( pSoldier->bLife + bBandage );
- }
- }
- // Deduct breath AND APs!
- sAPCost = (sLifeDeduct / AP_GET_WOUNDED_DIVISOR); // + fallCost;
- // ATE: if the robot, do not deduct
- if ( !AM_A_ROBOT( pSoldier ) )
- {
- DeductPoints( pSoldier, sAPCost, sBreathLoss );
- }
- ubCombinedLoss = (UINT8) sLifeDeduct / 10 + sBreathLoss / 2000;
- // Add shock
- if ( !AM_A_ROBOT( pSoldier ) )
- {
- pSoldier->bShock += ubCombinedLoss;
- }
- // start the stopwatch - the blood is gushing!
- pSoldier->dNextBleed = CalcSoldierNextBleed( pSoldier );
- if ( pSoldier->bInSector && pSoldier->bVisible != -1 )
- {
- // If we are already dead, don't show damage!
- if ( bOldLife != 0 && fShowDamage && sLifeDeduct != 0 && sLifeDeduct < 1000 )
- {
- // Display damage
- INT16 sOffsetX, sOffsetY;
- // Set Damage display counter
- pSoldier->fDisplayDamage = TRUE;
- pSoldier->bDisplayDamageCount = 0;
- if ( pSoldier->ubBodyType == QUEENMONSTER )
- {
- pSoldier->sDamageX = 0;
- pSoldier->sDamageY = 0;
- }
- else
- {
- GetSoldierAnimOffsets( pSoldier, &sOffsetX, &sOffsetY );
- pSoldier->sDamageX = sOffsetX;
- pSoldier->sDamageY = sOffsetY;
- }
- }
- }
- // OK, if here, let's see if we should drop our weapon....
- if ( ubReason != TAKE_DAMAGE_BLOODLOSS && !(AM_A_ROBOT( pSoldier )) )
- {
- INT16 sTestOne, sTestTwo, sChanceToDrop;
- INT8 bVisible = -1;
- sTestOne = EffectiveStrength( pSoldier );
- sTestTwo = ( 2 * ( __max( sLifeDeduct, ( sBreathLoss / 100 ) ) ) );
- if (pSoldier->ubAttackerID != NOBODY && MercPtrs[ pSoldier->ubAttackerID ]->ubBodyType == BLOODCAT )
- {
- // bloodcat boost, let them make people drop items more
- sTestTwo += 20;
- }
- // If damage > effective strength....
- sChanceToDrop = ( __max( 0, ( sTestTwo - sTestOne ) ) );
- // ATE: Increase odds of NOT dropping an UNDROPPABLE OBJECT
- if ( ( pSoldier->inv[ HANDPOS ].fFlags & OBJECT_UNDROPPABLE ) )
- {
- sChanceToDrop -= 30;
- }
- #ifdef JA2TESTVERSION
- //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Chance To Drop Weapon: str: %d Dam: %d Chance: %d", sTestOne, sTestTwo, sChanceToDrop );
- #endif
- if ( Random( 100 ) < (UINT16) sChanceToDrop )
- {
- // OK, drop item in main hand...
- if ( pSoldier->inv[ HANDPOS ].usItem != NOTHING )
- {
- if ( !( pSoldier->inv[ HANDPOS ].fFlags & OBJECT_UNDROPPABLE ) )
- {
- // ATE: if our guy, make visible....
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- bVisible = 1;
- }
- AddItemToPool( pSoldier->sGridNo, &(pSoldier->inv[ HANDPOS ]), bVisible, pSoldier->bLevel, 0, -1 );
- DeleteObj( &(pSoldier->inv[HANDPOS]) );
- }
- }
- }
- }
- // Drop some blood!
- // decide blood amt, if any
- ubBlood = ( sLifeDeduct / BLOODDIVISOR);
- if ( ubBlood > MAXBLOODQUANTITY )
- {
- ubBlood = MAXBLOODQUANTITY;
- }
- if ( !( pSoldier->uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_ROBOT ) ) )
- {
- if ( ubBlood != 0 )
- {
- if ( pSoldier->bInSector )
- {
- DropBlood( pSoldier, ubBlood, pSoldier->bVisible );
- }
- }
- }
- //Set UI Flag for unconscious, if it's our own guy!
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- if ( pSoldier->bLife < OKLIFE && pSoldier->bLife > 0 && bOldLife >= OKLIFE )
- {
- pSoldier->fUIFirstTimeUNCON = TRUE;
- fInterfacePanelDirty = DIRTYLEVEL2;
- }
- }
- if ( pSoldier->bInSector )
- {
- CheckForBreathCollapse( pSoldier );
- }
- // EXPERIENCE CLASS GAIN (combLoss): Getting wounded in battle
- DirtyMercPanelInterface( pSoldier, DIRTYLEVEL1 );
- if ( ubAttacker != NOBODY )
- {
- // don't give exp for hitting friends!
- if ( (MercPtrs[ ubAttacker ]->bTeam == gbPlayerNum) && (pSoldier->bTeam != gbPlayerNum) )
- {
- if ( ubReason == TAKE_DAMAGE_EXPLOSION )
- {
- // EXPLOSIVES GAIN (combLoss): Causing wounds in battle
- StatChange( MercPtrs[ ubAttacker ], EXPLODEAMT, (UINT16)( 10 * ubCombinedLoss ), FROM_FAILURE );
- }
- /*
- else if ( ubReason == TAKE_DAMAGE_GUNFIRE )
- {
- // MARKSMANSHIP GAIN (combLoss): Causing wounds in battle
- StatChange( MercPtrs[ ubAttacker ], MARKAMT, (UINT16)( 5 * ubCombinedLoss ), FALSE );
- }
- */
- }
- }
- if (PTR_OURTEAM)
- {
- // EXPERIENCE GAIN: Took some damage
- StatChange( pSoldier, EXPERAMT, ( UINT16 )( 5 * ubCombinedLoss ), FROM_FAILURE );
- // Check for quote
- if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_BEING_PUMMELED ) )
- {
- // Check attacker!
- if ( ubAttacker != NOBODY && ubAttacker != pSoldier->ubID )
- {
- pSoldier->bNumHitsThisTurn++;
- if ( (pSoldier->bNumHitsThisTurn >= 3) && ( pSoldier->bLife - pSoldier->bOldLife > 20 ) )
- {
- if ( Random(100) < (UINT16)((40 * ( pSoldier->bNumHitsThisTurn - 2))))
- {
- DelayedTacticalCharacterDialogue( pSoldier, QUOTE_TAKEN_A_BREATING );
- pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_BEING_PUMMELED;
- pSoldier->bNumHitsThisTurn = 0;
- }
- }
- }
- }
- }
- if ((ubAttacker != NOBODY) && (Menptr[ubAttacker].bTeam == OUR_TEAM) && (pSoldier->ubProfile != NO_PROFILE) && (pSoldier->ubProfile >= FIRST_RPC))
- {
- gMercProfiles[pSoldier->ubProfile].ubMiscFlags |= PROFILE_MISC_FLAG_WOUNDEDBYPLAYER;
- if (pSoldier->ubProfile == 114)
- {
- SetFactTrue( FACT_PACOS_KILLED );
- }
- }
- HandleTakeDamageDeath( pSoldier, bOldLife, ubReason );
- // Check if we are < unconscious, and shutup if so! also wipe sight
- if ( pSoldier->bLife < CONSCIOUSNESS )
- {
- ShutupaYoFace( pSoldier->iFaceIndex );
- }
-
- if ( pSoldier->bLife < OKLIFE )
- {
- DecayIndividualOpplist( pSoldier );
- }
- return( ubCombinedLoss );
- }
- extern BOOLEAN IsMercSayingDialogue( UINT8 ubProfileID );
- BOOLEAN InternalDoMercBattleSound( SOLDIERTYPE *pSoldier, UINT8 ubBattleSoundID, INT8 bSpecialCode )
- {
- SGPFILENAME zFilename;
- SOUNDPARMS spParms;
- UINT8 ubSoundID;
- UINT32 uiSoundID;
- UINT32 iFaceIndex;
- BOOLEAN fDoSub = FALSE;
- INT32 uiSubSoundID = 0;
- BOOLEAN fSpeechSound = FALSE;
- // DOUBLECHECK RANGE
- CHECKF ( ubBattleSoundID < NUM_MERC_BATTLE_SOUNDS );
- if ( ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
- {
- // Pick a passenger from vehicle....
- pSoldier = PickRandomPassengerFromVehicle( pSoldier );
- if ( pSoldier == NULL )
- {
- return( FALSE );
- }
- }
- // If a death sound, and we have already done ours...
- if ( ubBattleSoundID == BATTLE_SOUND_DIE1 )
- {
- if ( pSoldier->fDieSoundUsed )
- {
- return( TRUE );
- }
- }
-
- // Are we mute?
- if ( pSoldier->uiStatusFlags & SOLDIER_MUTE )
- {
- return( FALSE );
- }
- // uiTimeSameBattleSndDone
- // If we are a creature, etc, pick a better sound...
- if ( ubBattleSoundID == BATTLE_SOUND_HIT1 || ubBattleSoundID == BATTLE_SOUND_HIT2 )
- {
- switch ( pSoldier->ubBodyType )
- {
- case COW:
- fDoSub = TRUE;
- uiSubSoundID = COW_HIT_SND;
- break;
- case YAF_MONSTER:
- case YAM_MONSTER:
- case ADULTFEMALEMONSTER:
- case AM_MONSTER:
- fDoSub = TRUE;
- if ( Random( 2 ) == 0 )
- {
- uiSubSoundID = ACR_DIE_PART1;
- }
- else
- {
- uiSubSoundID = ACR_LUNGE;
- }
- break;
- case INFANT_MONSTER:
- fDoSub = TRUE;
- uiSubSoundID = BCR_SHRIEK;
- break;
- case QUEENMONSTER:
- fDoSub = TRUE;
- uiSubSoundID = LQ_SHRIEK;
- break;
- case LARVAE_MONSTER:
- fDoSub = TRUE;
- uiSubSoundID = BCR_SHRIEK;
- break;
- case BLOODCAT:
- fDoSub = TRUE;
- uiSubSoundID = BLOODCAT_HIT_1;
- break;
- case ROBOTNOWEAPON:
- fDoSub = TRUE;
- uiSubSoundID = (UINT32)( S_METAL_IMPACT1 + Random( 2 ) );
- break;
- }
- }
- if ( ubBattleSoundID == BATTLE_SOUND_DIE1 )
- {
- switch ( pSoldier->ubBodyType )
- {
- case COW:
- fDoSub = TRUE;
- uiSubSoundID = COW_DIE_SND;
- break;
- case YAF_MONSTER:
- case YAM_MONSTER:
- case ADULTFEMALEMONSTER:
- case AM_MONSTER:
- fDoSub = TRUE;
- uiSubSoundID = CREATURE_FALL_PART_2;
- break;
- case INFANT_MONSTER:
- fDoSub = TRUE;
- uiSubSoundID = BCR_DYING;
- break;
- case LARVAE_MONSTER:
- fDoSub = TRUE;
- uiSubSoundID = LCR_RUPTURE;
- break;
- case QUEENMONSTER:
- fDoSub = TRUE;
- uiSubSoundID = LQ_DYING;
- break;
- case BLOODCAT:
- fDoSub = TRUE;
- uiSubSoundID = BLOODCAT_DIE_1;
- break;
- case ROBOTNOWEAPON:
- fDoSub = TRUE;
- uiSubSoundID = (UINT32)( EXPLOSION_1 );
- PlayJA2Sample( ROBOT_DEATH, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
- break;
- }
- }
- // OK. any other sound, not hits, robot makes a beep
- if ( pSoldier->ubBodyType == ROBOTNOWEAPON && !fDoSub )
- {
- fDoSub = TRUE;
- if ( ubBattleSoundID == BATTLE_SOUND_ATTN1 )
- {
- uiSubSoundID = ROBOT_GREETING;
- }
- else
- {
- uiSubSoundID = ROBOT_BEEP;
- }
- }
- if ( fDoSub )
- {
- if( guiCurrentScreen != GAME_SCREEN )
- {
- PlayJA2Sample( uiSubSoundID, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
- }
- else
- {
- PlayJA2Sample( uiSubSoundID, RATE_11025, SoundVolume( (UINT8)CalculateSpeechVolume( HIGHVOLUME ), pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
- }
- return( TRUE );
- }
- // Check if this is the same one we just played...
- if ( pSoldier->bOldBattleSnd == ubBattleSoundID && gBattleSndsData[ ubBattleSoundID ].fDontAllowTwoInRow )
- {
- // Are we below the min delay?
- if ( ( GetJA2Clock( ) - pSoldier->uiTimeSameBattleSndDone ) < MIN_SUBSEQUENT_SNDS_DELAY )
- {
- return( TRUE );
- }
- }
- // If a battle snd is STILL playing....
- if ( SoundIsPlaying( pSoldier->uiBattleSoundID ) )
- {
- // We can do a few things here....
- // Is this a crutial one...?
- if ( gBattleSndsData[ ubBattleSoundID ].fStopDialogue == 1 )
- {
- // Stop playing origonal
- SoundStop( pSoldier->uiBattleSoundID );
- }
- else
- {
- // Skip this one...
- return( TRUE );
- }
- }
- // If we are talking now....
- if ( IsMercSayingDialogue( pSoldier->ubProfile ) )
- {
- // We can do a couple of things now...
- if ( gBattleSndsData[ ubBattleSoundID ].fStopDialogue == 1 )
- {
- // Stop dialigue...
- DialogueAdvanceSpeech( );
- }
- else if ( gBattleSndsData[ ubBattleSoundID ].fStopDialogue == 2 )
- {
- // Skip battle snd...
- return( TRUE );
- }
- }
- // Save this one we're doing...
- pSoldier->bOldBattleSnd = ubBattleSoundID;
- pSoldier->uiTimeSameBattleSndDone = GetJA2Clock( );
-
-
- // Adjust based on morale...
- if ( ubBattleSoundID == BATTLE_SOUND_OK1 && pSoldier->bMorale < LOW_MORALE_BATTLE_SND_THREASHOLD )
- {
- ubBattleSoundID = BATTLE_SOUND_LOWMARALE_OK1;
- }
- if ( ubBattleSoundID == BATTLE_SOUND_ATTN1 && pSoldier->bMorale < LOW_MORALE_BATTLE_SND_THREASHOLD )
- {
- ubBattleSoundID = BATTLE_SOUND_LOWMARALE_ATTN1;
- }
- ubSoundID = ubBattleSoundID;
- //if the sound to be played is a confirmation, check to see if we are to play it
- if( ubSoundID == BATTLE_SOUND_OK1 )
- {
- if( gGameSettings.fOptions[ TOPTION_MUTE_CONFIRMATIONS ] )
- return( TRUE );
- //else a speech sound is to be played
- else
- fSpeechSound = TRUE;
- }
- // Randomize between sounds, if appropriate
- if ( gBattleSndsData[ ubSoundID ].ubRandomVal != 0 )
- {
- ubSoundID = ubSoundID + (UINT8)Random( gBattleSndsData[ ubSoundID ].ubRandomVal );
- }
- // OK, build file and play!
- if ( pSoldier->ubProfile != NO_PROFILE )
- {
- sprintf( zFilename, "BATTLESNDS\\%03d_%s.wav", pSoldier->ubProfile, gBattleSndsData[ ubSoundID ].zName );
-
- if ( !FileExists( zFilename ) )
- {
- // OK, temp build file...
- if ( pSoldier->ubBodyType == REGFEMALE )
- {
- sprintf( zFilename, "BATTLESNDS\\f_%s.wav", gBattleSndsData[ ubSoundID ].zName );
- }
- else
- {
- sprintf( zFilename, "BATTLESNDS\\m_%s.wav", gBattleSndsData[ ubSoundID ].zName );
- }
- }
- }
- else
- {
- // Check if we can play this!
- if ( !gBattleSndsData[ ubSoundID ].fBadGuy )
- {
- return( FALSE );
- }
- if ( pSoldier->ubBodyType == HATKIDCIV || pSoldier->ubBodyType == KIDCIV )
- {
- if ( ubSoundID == BATTLE_SOUND_DIE1 )
- {
- sprintf( zFilename, "BATTLESNDS\\kid%d_dying.wav", pSoldier->ubBattleSoundID );
- }
- else
- {
- sprintf( zFilename, "BATTLESNDS\\kid%d_%s.wav", pSoldier->ubBattleSoundID, gBattleSndsData[ ubSoundID ].zName );
- }
- }
- else
- {
- if ( ubSoundID == BATTLE_SOUND_DIE1 )
- {
- sprintf( zFilename, "BATTLESNDS\\bad%d_die.wav", pSoldier->ubBattleSoundID );
- }
- else
- {
- sprintf( zFilename, "BATTLESNDS\\bad%d_%s.wav", pSoldier->ubBattleSoundID, gBattleSndsData[ ubSoundID ].zName );
- }
- }
- }
- // Play sound!
- memset(&spParms, 0xff, sizeof(SOUNDPARMS));
- spParms.uiSpeed = RATE_11025;
- //spParms.uiVolume = CalculateSpeechVolume( pSoldier->bVocalVolume );
- spParms.uiVolume = (INT8)CalculateSpeechVolume( HIGHVOLUME );
- // ATE: Reduce volume for OK sounds...
- // ( Only for all-moves or multi-selection cases... )
- if ( bSpecialCode == BATTLE_SND_LOWER_VOLUME )
- {
- spParms.uiVolume = (INT8)CalculateSpeechVolume( MIDVOLUME );
- }
- // If we are an enemy.....reduce due to volume
- if ( pSoldier->bTeam != gbPlayerNum )
- {
- spParms.uiVolume = SoundVolume( (UINT8)spParms.uiVolume, pSoldier->sGridNo );
- }
- spParms.uiLoop = 1;
- spParms.uiPan = SoundDir( pSoldier->sGridNo );
- spParms.uiPriority=GROUP_PLAYER;
- if ( ( uiSoundID = SoundPlay( zFilename, &spParms ) ) == SOUND_ERROR )
- {
- return( FALSE );
- }
- else
- {
- pSoldier->uiBattleSoundID = uiSoundID;
- if ( pSoldier->ubProfile != NO_PROFILE )
- {
- // Get soldier's face ID
- iFaceIndex = pSoldier->iFaceIndex;
- // Check face index
- if ( iFaceIndex != -1 )
- {
- ExternSetFaceTalking( iFaceIndex, uiSoundID );
- }
- }
- return( TRUE );
- }
- }
- BOOLEAN DoMercBattleSound( SOLDIERTYPE *pSoldier, UINT8 ubBattleSoundID )
- {
- // We WANT to play some RIGHT AWAY.....
- if ( gBattleSndsData[ ubBattleSoundID ].fStopDialogue == 1 || ( pSoldier->ubProfile == NO_PROFILE ) || InOverheadMap( ) )
- {
- return( InternalDoMercBattleSound( pSoldier, ubBattleSoundID, 0 ) );
- }
- // So here, only if we were currently saying dialogue.....
- if ( !IsMercSayingDialogue( pSoldier->ubProfile ) )
- {
- return( InternalDoMercBattleSound( pSoldier, ubBattleSoundID, 0 ) );
- }
- // OK, queue it up otherwise!
- TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_DO_BATTLE_SND, ubBattleSoundID,0 );
- return( TRUE );
- }
- BOOLEAN PreloadSoldierBattleSounds( SOLDIERTYPE *pSoldier, BOOLEAN fRemove )
- {
- UINT32 cnt;
- CHECKF( pSoldier->bActive != FALSE );
- for ( cnt = 0; cnt < NUM_MERC_BATTLE_SOUNDS; cnt++ )
- {
- // OK, build file and play!
- if ( pSoldier->ubProfile != NO_PROFILE )
- {
- if ( gBattleSndsData[ cnt ].fPreload )
- {
- if ( fRemove )
- {
- SoundUnlockSample( gBattleSndsData[ cnt ].zName );
- }
- else
- {
- SoundLockSample( gBattleSndsData[ cnt ].zName );
- }
- }
- }
- else
- {
- if ( gBattleSndsData[ cnt ].fPreload && gBattleSndsData[ cnt ].fBadGuy )
- {
- if ( fRemove )
- {
- SoundUnlockSample( gBattleSndsData[ cnt ].zName );
- }
- else
- {
- SoundLockSample( gBattleSndsData[ cnt ].zName );
- }
- }
- }
- }
- return( TRUE );
- }
- BOOLEAN CheckSoldierHitRoof( SOLDIERTYPE *pSoldier )
- {
- // Check if we are near a lower level
- INT8 bNewDirection;
- BOOLEAN fReturnVal = FALSE;
- INT16 sNewGridNo;
- // Default to true
- BOOLEAN fDoForwards = TRUE;
- if ( pSoldier->bLife >= OKLIFE )
- {
- return( FALSE );
- }
- if ( FindLowerLevel( pSoldier, pSoldier->sGridNo, pSoldier->bDirection, &bNewDirection ) && ( pSoldier->bLevel > 0 ) )
- {
- // ONly if standing!
- if ( gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_STAND )
- {
- // We are near a lower level.
- // Use opposite direction
- bNewDirection = gOppositeDirection[ bNewDirection ];
- // Alrighty, let's not blindly change here, look at whether the dest gridno is good!
- sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bNewDirection ] ) );
- if ( !NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) )
- {
- return( FALSE );
- }
- sNewGridNo = NewGridNo( (UINT16)sNewGridNo, DirectionInc( gOppositeDirection[ bNewDirection ] ) );
- if ( !NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) )
- {
- return( FALSE );
- }
-
- // Are wee near enough to fall forwards....
- if ( pSoldier->bDirection == gOneCDirection[ bNewDirection ] ||
- pSoldier->bDirection == gTwoCDirection[ bNewDirection ] ||
- pSoldier->bDirection == bNewDirection ||
- pSoldier->bDirection == gOneCCDirection[ bNewDirection ] ||
- pSoldier->bDirection == gTwoCCDirection[ bNewDirection ] )
- {
- // Do backwards...
- fDoForwards = FALSE;
- }
- // If we are facing the opposite direction, fall backwards
- // ATE: Make this more usefull...
- if ( fDoForwards )
- {
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (INT16)( -1 * DirectionInc(bNewDirection ) ) );
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sTempNewGridNo, (INT16)( -1 * DirectionInc( bNewDirection ) ) );
- EVENT_SetSoldierDesiredDirection( pSoldier, gOppositeDirection[ bNewDirection ] );
- pSoldier->fTurningUntilDone = TRUE;
- pSoldier->usPendingAnimation = FALLFORWARD_ROOF;
- //EVENT_InitNewSoldierAnim( pSoldier, FALLFORWARD_ROOF, 0 , FALSE );
- // Deduct hitpoints/breath for falling!
- SoldierTakeDamage( pSoldier, ANIM_CROUCH, 100, 5000, TAKE_DAMAGE_FALLROOF, NOBODY, NOWHERE, 0, TRUE );
- fReturnVal = TRUE;
- }
- else
- {
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (INT16)( -1 * DirectionInc( bNewDirection ) ) );
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sTempNewGridNo, (INT16)( -1 * DirectionInc( bNewDirection ) ) );
- EVENT_SetSoldierDesiredDirection( pSoldier, bNewDirection );
- pSoldier->fTurningUntilDone = TRUE;
- pSoldier->usPendingAnimation = FALLOFF;
- // Deduct hitpoints/breath for falling!
- SoldierTakeDamage( pSoldier, ANIM_CROUCH, 100, 5000, TAKE_DAMAGE_FALLROOF, NOBODY, NOWHERE, 0, TRUE );
- fReturnVal = TRUE;
- }
- }
- }
- return( fReturnVal );
- }
- void BeginSoldierClimbDownRoof( SOLDIERTYPE *pSoldier )
- {
- INT8 bNewDirection;
- if ( FindLowerLevel( pSoldier, pSoldier->sGridNo, pSoldier->bDirection, &bNewDirection ) && ( pSoldier->bLevel > 0 ) )
- {
- if ( EnoughPoints( pSoldier, GetAPsToClimbRoof( pSoldier, TRUE ), 0, TRUE ) )
- {
- if (pSoldier->bTeam == gbPlayerNum)
- {
- // OK, SET INTERFACE FIRST
- SetUIBusy( pSoldier->ubID );
- }
- pSoldier->sTempNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)DirectionInc(bNewDirection ) );
- bNewDirection = gTwoCDirection[ bNewDirection ];
- pSoldier->ubPendingDirection = bNewDirection;
- EVENT_InitNewSoldierAnim( pSoldier, CLIMBDOWNROOF, 0 , FALSE );
- InternalReceivingSoldierCancelServices( pSoldier, FALSE );
- InternalGivingSoldierCancelServices( pSoldier, FALSE );
- }
- }
- }
- void MoveMerc( SOLDIERTYPE *pSoldier, FLOAT dMovementChange, FLOAT dAngle, BOOLEAN fCheckRange )
- {
- INT16 dDegAngle;
- FLOAT dDeltaPos;
- FLOAT dXPos , dYPos;
- BOOLEAN fStop = FALSE;
- dDegAngle = (INT16)( dAngle * 180 / PI );
- //sprintf( gDebugStr, "Move Angle: %d", (int)dDegAngle );
- // Find delta Movement for X pos
- dDeltaPos = (FLOAT) (dMovementChange * sin( dAngle ));
- // Find new position
- dXPos = pSoldier->dXPos + dDeltaPos;
- if ( fCheckRange )
- {
- fStop = FALSE;
- switch( pSoldier->bMovementDirection )
- {
- case NORTHEAST:
- case EAST:
- case SOUTHEAST:
- if ( dXPos >= pSoldier->sDestXPos )
- {
- fStop = TRUE;
- }
- break;
- case NORTHWEST:
- case WEST:
- case SOUTHWEST:
- if ( dXPos <= pSoldier->sDestXPos )
- {
- fStop = TRUE;
- }
- break;
- case NORTH:
- case SOUTH:
- fStop = TRUE;
- break;
- }
- if ( fStop )
- {
- //dXPos = pSoldier->sDestXPos;
- pSoldier->fPastXDest = TRUE;
- if ( pSoldier->sGridNo == pSoldier->sFinalDestination )
- {
- dXPos = pSoldier->sDestXPos;
- }
- }
- }
- // Find delta Movement for Y pos
- dDeltaPos = (FLOAT) (dMovementChange * cos( dAngle ));
- // Find new pos
- dYPos = pSoldier->dYPos + dDeltaPos;
- if ( fCheckRange )
- {
- fStop = FALSE;
- switch( pSoldier->bMovementDirection )
- {
- case NORTH:
- case NORTHEAST:
- case NORTHWEST:
- if ( dYPos <= pSoldier->sDestYPos )
- {
- fStop = TRUE;
- }
- break;
- case SOUTH:
- case SOUTHWEST:
- case SOUTHEAST:
- if ( dYPos >= pSoldier->sDestYPos )
- {
- fStop = TRUE;
- }
- break;
- case EAST:
- case WEST:
- fStop = TRUE;
- break;
- }
- if ( fStop )
- {
- //dYPos = pSoldier->sDestYPos;
- pSoldier->fPastYDest = TRUE;
- if ( pSoldier->sGridNo == pSoldier->sFinalDestination )
- {
- dYPos = pSoldier->sDestYPos;
- }
- }
- }
- // OK, set new position
- EVENT_InternalSetSoldierPosition( pSoldier, dXPos, dYPos, FALSE, FALSE, FALSE );
- // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("X: %f Y: %f", dXPos, dYPos ) );
- }
- INT16 GetDirectionFromGridNo( INT16 sGridNo, SOLDIERTYPE *pSoldier )
- {
- INT16 sXPos, sYPos;
- ConvertGridNoToXY( sGridNo, &sXPos, &sYPos );
- return( GetDirectionFromXY( sXPos, sYPos, pSoldier ) );
- }
- INT16 GetDirectionToGridNoFromGridNo( INT16 sGridNoDest, INT16 sGridNoSrc )
- {
- INT16 sXPos2, sYPos2;
- INT16 sXPos, sYPos;
- ConvertGridNoToXY( sGridNoSrc, &sXPos, &sYPos );
- ConvertGridNoToXY( sGridNoDest, &sXPos2, &sYPos2 );
- return( atan8( sXPos2, sYPos2, sXPos, sYPos ) );
- }
- INT16 GetDirectionFromXY( INT16 sXPos, INT16 sYPos, SOLDIERTYPE *pSoldier )
- {
- INT16 sXPos2, sYPos2;
- ConvertGridNoToXY( pSoldier->sGridNo, &sXPos2, &sYPos2 );
- return( atan8( sXPos2, sYPos2, sXPos, sYPos ) );
- }
- #if 0
- UINT8 atan8( INT16 x1, INT16 y1, INT16 x2, INT16 y2 )
- {
- static int trig[8] = { 2, 3, 4, 5, 6, 7, 8, 1 };
- // returned values are N=1, NE=2, E=3, SE=4, S=5, SW=6, W=7, NW=8
- double dx=(x2-x1);
- double dy=(y2-y1);
- double a;
- int i,k;
- if (dx==0)
- dx=0.00390625; // 1/256th
- #define PISLICES (8)
- a=(atan2(dy,dx) + PI/PISLICES)/(PI/(PISLICES/2));
- i=(int)a;
- if (a>0)
- k=i; else
- if (a<0)
- k=i+(PISLICES-1); else
- k=0;
- return(trig[k]);
- }
- #endif
- //#if 0
- UINT8 atan8( INT16 sXPos, INT16 sYPos, INT16 sXPos2, INT16 sYPos2 )
- {
- DOUBLE test_x = sXPos2 - sXPos;
- DOUBLE test_y = sYPos2 - sYPos;
- UINT8 mFacing = WEST;
- INT16 dDegAngle;
- DOUBLE angle;
- if ( test_x == 0 )
- {
- test_x = 0.04;
- }
-
- angle = atan2( test_x, test_y );
- dDegAngle = (INT16)( angle * 180 / PI );
- //sprintf( gDebugStr, "Move Angle: %d", (int)dDegAngle );
- do
- {
- if ( angle >=-PI*.375 && angle <= -PI*.125 )
- {
- mFacing = SOUTHWEST;
- break;
- }
- if ( angle <= PI*.375 && angle >= PI*.125 )
- {
- mFacing = SOUTHEAST;
- break;
- }
- if ( angle >=PI*.623 && angle <= PI*.875 )
- {
- mFacing = NORTHEAST;
- break;
- }
- if ( angle <=-PI*.623 && angle >= -PI*.875 )
- {
- mFacing = NORTHWEST;
- break;
- }
- if ( angle >-PI*0.125 && angle < PI*0.125 )
- {
- mFacing = SOUTH;
- }
- if ( angle > PI*0.375 && angle < PI*0.623 )
- {
- mFacing = EAST;
- }
- if ( ( angle > PI*0.875 && angle <= PI ) || ( angle > -PI && angle < -PI*0.875 ) )
- {
- mFacing = NORTH;
- }
- if ( angle > -PI*0.623 && angle < -PI*0.375 )
- {
- mFacing = WEST;
- }
- } while( FALSE );
- return( mFacing );
- }
- UINT8 atan8FromAngle( DOUBLE angle )
- {
- UINT8 mFacing = WEST;
- if ( angle > PI )
- {
- angle = ( angle - PI ) - PI;
- }
- if ( angle < -PI )
- {
- angle = ( PI - ( fabs( angle ) - PI ) );
- }
- do
- {
- if ( angle >=-PI*.375 && angle <= -PI*.125 )
- {
- mFacing = SOUTHWEST;
- break;
- }
- if ( angle <= PI*.375 && angle >= PI*.125 )
- {
- mFacing = SOUTHEAST;
- break;
- }
- if ( angle >=PI*.623 && angle <= PI*.875 )
- {
- mFacing = NORTHEAST;
- break;
- }
- if ( angle <=-PI*.623 && angle >= -PI*.875 )
- {
- mFacing = NORTHWEST;
- break;
- }
- if ( angle >-PI*0.125 && angle < PI*0.125 )
- {
- mFacing = SOUTH;
- }
- if ( angle > PI*0.375 && angle < PI*0.623 )
- {
- mFacing = EAST;
- }
- if ( ( angle > PI*0.875 && angle <= PI ) || ( angle > -PI && angle < -PI*0.875 ) )
- {
- mFacing = NORTH;
- }
- if ( angle > -PI*0.623 && angle < -PI*0.375 )
- {
- mFacing = WEST;
- }
- } while( FALSE );
- return( mFacing );
- }
- void CheckForFullStructures( SOLDIERTYPE *pSoldier )
- {
- // This function checks to see if we are near a specific structure type which requires us to blit a
- // small obscuring peice
- INT16 sGridNo;
- UINT16 usFullTileIndex;
- INT32 cnt;
- // Check in all 'Above' directions
- for ( cnt = 0; cnt < MAX_FULLTILE_DIRECTIONS; cnt++ )
- {
- sGridNo = pSoldier->sGridNo + gsFullTileDirections[ cnt ];
- if ( CheckForFullStruct( sGridNo, &usFullTileIndex ) )
- {
- // Add one for the item's obsuring part
- pSoldier->usFrontArcFullTileList[ cnt ] = usFullTileIndex + 1;
- pSoldier->usFrontArcFullTileGridNos[ cnt ] = sGridNo;
- AddTopmostToHead( sGridNo, pSoldier->usFrontArcFullTileList[ cnt ] );
- }
- else
- {
- if ( pSoldier->usFrontArcFullTileList[ cnt ] != 0 )
- {
- RemoveTopmost( pSoldier->usFrontArcFullTileGridNos[ cnt ], pSoldier->usFrontArcFullTileList[ cnt ] );
- }
- pSoldier->usFrontArcFullTileList[ cnt ] = 0;
- pSoldier->usFrontArcFullTileGridNos[ cnt ] = 0;
- }
- }
- }
- BOOLEAN CheckForFullStruct( INT16 sGridNo, UINT16 *pusIndex )
- {
- LEVELNODE *pStruct = NULL;
- LEVELNODE *pOldStruct = NULL;
- UINT32 fTileFlags;
- pStruct = gpWorldLevelData[ sGridNo ].pStructHead;
- // Look through all structs and Search for type
- while( pStruct != NULL )
- {
- if ( pStruct->usIndex != NO_TILE && pStruct->usIndex < NUMBEROFTILES )
- {
- GetTileFlags( pStruct->usIndex, &fTileFlags );
- // Advance to next
- pOldStruct = pStruct;
- pStruct = pStruct->pNext;
- //if( (pOldStruct->pStructureData!=NULL) && ( pOldStruct->pStructureData->fFlags&STRUCTURE_TREE ) )
- if ( fTileFlags & FULL3D_TILE )
- {
- // CHECK IF THIS TREE IS FAIRLY ALONE!
- if ( FullStructAlone( sGridNo, 2 ) )
- {
- // Return true and return index
- *pusIndex = pOldStruct->usIndex;
- return( TRUE );
- }
- else
- {
- return( FALSE );
- }
- }
- }
- else
- {
- // Advance to next
- pOldStruct = pStruct;
- pStruct = pStruct->pNext;
- }
- }
- // Could not find it, return FALSE
- return( FALSE );
- }
- BOOLEAN FullStructAlone( INT16 sGridNo, UINT8 ubRadius )
- {
- INT16 sTop, sBottom;
- INT16 sLeft, sRight;
- INT16 cnt1, cnt2;
- INT16 iNewIndex;
- INT32 leftmost;
- // Determine start end end indicies and num rows
- sTop = ubRadius;
- sBottom = -ubRadius;
- sLeft = - ubRadius;
- sRight = ubRadius;
- for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
- {
- leftmost = ( ( sGridNo + ( WORLD_COLS * cnt1 ) )/ WORLD_COLS ) * WORLD_COLS;
- for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ )
- {
- iNewIndex = sGridNo + ( WORLD_COLS * cnt1 ) + cnt2;
- if ( iNewIndex >=0 && iNewIndex < WORLD_MAX &&
- iNewIndex >= leftmost && iNewIndex < ( leftmost + WORLD_COLS ) )
- {
- if ( iNewIndex != sGridNo )
- {
- if ( FindStructure( iNewIndex, STRUCTURE_TREE ) != NULL )
- {
- return( FALSE );
- }
- }
- }
- }
- }
- return( TRUE );
- }
- void AdjustForFastTurnAnimation( SOLDIERTYPE *pSoldier )
- {
- // CHECK FOR FASTTURN ANIMATIONS
- // ATE: Mod: Only fastturn for OUR guys!
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FASTTURN && pSoldier->bTeam == gbPlayerNum && !( pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT ) )
- {
- if ( pSoldier->bDirection != pSoldier->bDesiredDirection )
- {
- pSoldier->sAniDelay = FAST_TURN_ANIM_SPEED;
- }
- else
- {
- SetSoldierAniSpeed( pSoldier );
- // FreeUpNPCFromTurning( pSoldier, LOOK);
- }
- }
- }
- BOOLEAN IsActionInterruptable( SOLDIERTYPE *pSoldier )
- {
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_NONINTERRUPT )
- {
- return( FALSE );
- }
- return( TRUE );
- }
- // WRAPPER FUNCTIONS FOR SOLDIER EVENTS
- void SendSoldierPositionEvent( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos )
- {
- // Sent event for position update
- EV_S_SETPOSITION SSetPosition;
- SSetPosition.usSoldierID = pSoldier->ubID;
- SSetPosition.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- SSetPosition.dNewXPos = dNewXPos;
- SSetPosition.dNewYPos = dNewYPos;
- AddGameEvent( S_SETPOSITION, 0, &SSetPosition );
- }
- void SendSoldierDestinationEvent( SOLDIERTYPE *pSoldier, UINT16 usNewDestination )
- {
- // Sent event for position update
- EV_S_CHANGEDEST SChangeDest;
- SChangeDest.usSoldierID = pSoldier->ubID;
- SChangeDest.usNewDestination = usNewDestination;
- SChangeDest.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- AddGameEvent( S_CHANGEDEST, 0, &SChangeDest );
- }
- void SendSoldierSetDirectionEvent( SOLDIERTYPE *pSoldier, UINT16 usNewDirection )
- {
- // Sent event for position update
- EV_S_SETDIRECTION SSetDirection;
- SSetDirection.usSoldierID = pSoldier->ubID;
- SSetDirection.usNewDirection = usNewDirection;
- SSetDirection.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- AddGameEvent( S_SETDIRECTION, 0, &SSetDirection );
- }
- void SendSoldierSetDesiredDirectionEvent( SOLDIERTYPE *pSoldier, UINT16 usDesiredDirection )
- {
- // Sent event for position update
- EV_S_SETDESIREDDIRECTION SSetDesiredDirection;
- SSetDesiredDirection.usSoldierID = pSoldier->ubID;
- SSetDesiredDirection.usDesiredDirection = usDesiredDirection;
- SSetDesiredDirection.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- AddGameEvent( S_SETDESIREDDIRECTION, 0, &SSetDesiredDirection );
- }
- void SendGetNewSoldierPathEvent( SOLDIERTYPE *pSoldier, UINT16 sDestGridNo, UINT16 usMovementAnim )
- {
- EV_S_GETNEWPATH SGetNewPath;
- SGetNewPath.usSoldierID = pSoldier->ubID;
- SGetNewPath.sDestGridNo = sDestGridNo;
- SGetNewPath.usMovementAnim = usMovementAnim;
- SGetNewPath.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- AddGameEvent( S_GETNEWPATH, 0, &SGetNewPath );
- }
- void SendChangeSoldierStanceEvent( SOLDIERTYPE *pSoldier, UINT8 ubNewStance )
- {
- #if 0
- EV_S_CHANGESTANCE SChangeStance;
- #ifdef NETWORKED
- if( !IsTheSolderUnderMyControl( pSoldier->ubID) )
- return;
- #endif
- SChangeStance.ubNewStance = ubNewStance;
- SChangeStance.usSoldierID = pSoldier->ubID;
- SChangeStance.sXPos = pSoldier->sX;
- SChangeStance.sYPos = pSoldier->sY;
- SChangeStance.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- AddGameEvent( S_CHANGESTANCE, 0, &SChangeStance );
- #endif
- ChangeSoldierStance( pSoldier, ubNewStance );
- }
- void SendBeginFireWeaponEvent( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo )
- {
- EV_S_BEGINFIREWEAPON SBeginFireWeapon;
- SBeginFireWeapon.usSoldierID = pSoldier->ubID;
- SBeginFireWeapon.sTargetGridNo = sTargetGridNo;
- SBeginFireWeapon.bTargetLevel = pSoldier->bTargetLevel;
- SBeginFireWeapon.bTargetCubeLevel = pSoldier->bTargetCubeLevel;
- SBeginFireWeapon.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue;
- AddGameEvent( S_BEGINFIREWEAPON, 0, &SBeginFireWeapon );
- }
- // This function just encapolates the check for turnbased and having an attacker in the first place
- void ReleaseSoldiersAttacker( SOLDIERTYPE *pSoldier )
- {
- INT32 cnt;
- UINT8 ubNumToFree;
- //if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT) )
- {
- // ATE: Removed...
- //if ( pSoldier->ubAttackerID != NOBODY )
- {
- // JA2 Gold
- // set next-to-previous attacker, so long as this isn't a repeat attack
- if (pSoldier->ubPreviousAttackerID != pSoldier->ubAttackerID)
- {
- pSoldier->ubNextToPreviousAttackerID = pSoldier->ubPreviousAttackerID;
- }
- // get previous attacker id
- pSoldier->ubPreviousAttackerID = pSoldier->ubAttackerID;
- // Copy BeingAttackedCount here....
- ubNumToFree = pSoldier->bBeingAttackedCount;
- // Zero it out BEFORE, as supression may increase it again...
- pSoldier->bBeingAttackedCount = 0;
-
- for ( cnt = 0; cnt < ubNumToFree; cnt++ )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker of %d (attacker is %d) - releasesoldierattacker num to free is %d", pSoldier->ubID, pSoldier->ubAttackerID, ubNumToFree ) );
- ReduceAttackBusyCount( pSoldier->ubAttackerID, FALSE );
- }
- // ATE: Set to NOBODY if this person is NOT dead
- // otherise, we keep it so the kill can be awarded!
- if ( pSoldier->bLife != 0 && pSoldier->ubBodyType != QUEENMONSTER )
- {
- pSoldier->ubAttackerID = NOBODY;
- }
- }
- }
- }
- BOOLEAN MercInWater( SOLDIERTYPE *pSoldier )
- {
- // Our water texture , for now is of a given type
- if ( pSoldier->bOverTerrainType == LOW_WATER || pSoldier->bOverTerrainType == MED_WATER || pSoldier->bOverTerrainType == DEEP_WATER )
- {
- return( TRUE );
- }
- else
- {
- return( FALSE );
- }
- }
- void RevivePlayerTeam( )
- {
- INT32 cnt;
- SOLDIERTYPE *pSoldier;
- // End the turn of player charactors
- cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
- // look for all mercs on the same team,
- for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pSoldier++)
- {
- ReviveSoldier( pSoldier );
- }
- }
- void ReviveSoldier( SOLDIERTYPE *pSoldier )
- {
- INT16 sX, sY;
- if ( pSoldier->bLife < OKLIFE && pSoldier->bActive )
- {
- // If dead or unconscious, revive!
- pSoldier->uiStatusFlags &= ( ~SOLDIER_DEAD );
- pSoldier->bLife = pSoldier->bLifeMax;
- pSoldier->bBleeding = 0;
- pSoldier->ubDesiredHeight = ANIM_STAND;
- AddManToTeam( pSoldier->bTeam );
- // Set to standing
- pSoldier->fInNonintAnim = FALSE;
- pSoldier->fRTInNonintAnim = FALSE;
- // Change to standing,unless we can getup with an animation
- EVENT_InitNewSoldierAnim( pSoldier, STANDING, 0, TRUE );
- BeginSoldierGetup( pSoldier );
- // Makesure center of tile
- sX = CenterX( pSoldier->sGridNo );
- sY = CenterY( pSoldier->sGridNo );
- EVENT_SetSoldierPosition( pSoldier, (FLOAT) sX, (FLOAT) sY );
- // Dirty INterface
- fInterfacePanelDirty = DIRTYLEVEL2;
- }
- }
- void HandleAnimationProfile( SOLDIERTYPE *pSoldier, UINT16 usAnimState, BOOLEAN fRemove )
- {
- //#if 0
- ANIM_PROF *pProfile;
- ANIM_PROF_DIR *pProfileDir;
- ANIM_PROF_TILE *pProfileTile;
- INT8 bProfileID;
- UINT32 iTileCount;
- INT16 sGridNo;
- UINT16 usAnimSurface;
- // ATE
- // Get Surface Index
- usAnimSurface = DetermineSoldierAnimationSurface( pSoldier, usAnimState );
- CHECKV( usAnimSurface != INVALID_ANIMATION_SURFACE );
- bProfileID = gAnimSurfaceDatabase[ usAnimSurface ].bProfile;
- // Determine if this animation has a profile
- if ( bProfileID != -1 )
- {
- // Getprofile
- pProfile = &(gpAnimProfiles[ bProfileID ] );
- // Get direction
- pProfileDir = &( pProfile->Dirs[ pSoldier->bDirection ] );
- // Loop tiles and set accordingly into world
- for( iTileCount = 0; iTileCount < pProfileDir->ubNumTiles; iTileCount++ )
- {
- pProfileTile = &( pProfileDir->pTiles[ iTileCount ] );
- sGridNo = pSoldier->sGridNo + ( ( WORLD_COLS * pProfileTile->bTileY ) + pProfileTile->bTileX );
- // Check if in bounds
- if ( !OutOfBounds( pSoldier->sGridNo, sGridNo ) )
- {
- if ( fRemove )
- {
- // Remove from world
- RemoveMerc( sGridNo, pSoldier, TRUE );
- }
- else
- {
- // PLace into world
- AddMercToHead( sGridNo, pSoldier, FALSE );
- //if ( pProfileTile->bTileY != 0 || pProfileTile->bTileX != 0 )
- {
- gpWorldLevelData[sGridNo].pMercHead->uiFlags |= LEVELNODE_MERCPLACEHOLDER;
- gpWorldLevelData[sGridNo].pMercHead->uiAnimHitLocationFlags = pProfileTile->usTileFlags;
- }
- }
- }
- }
- }
- //#endif
- }
- LEVELNODE *GetAnimProfileFlags( UINT16 sGridNo, UINT16 *usFlags, SOLDIERTYPE **ppTargSoldier, LEVELNODE *pGivenNode )
- {
- LEVELNODE *pNode;
- (*ppTargSoldier) = NULL;
- (*usFlags ) = 0;
- if ( pGivenNode == NULL )
- {
- pNode = gpWorldLevelData[sGridNo].pMercHead;
- }
- else
- {
- pNode = pGivenNode->pNext;
- }
- //#if 0
- if ( pNode != NULL )
- {
- if ( pNode->uiFlags & LEVELNODE_MERCPLACEHOLDER )
- {
- (*usFlags) = (UINT16)pNode->uiAnimHitLocationFlags;
- (*ppTargSoldier) = pNode->pSoldier;
- }
- }
- //#endif
- return( pNode );
- }
- BOOLEAN GetProfileFlagsFromGridno( SOLDIERTYPE *pSoldier, UINT16 usAnimState, UINT16 sTestGridNo, UINT16 *usFlags )
- {
- ANIM_PROF *pProfile;
- ANIM_PROF_DIR *pProfileDir;
- ANIM_PROF_TILE *pProfileTile;
- INT8 bProfileID;
- UINT32 iTileCount;
- INT16 sGridNo;
- UINT16 usAnimSurface;
- // Get Surface Index
- usAnimSurface = DetermineSoldierAnimationSurface( pSoldier, usAnimState );
- CHECKF( usAnimSurface != INVALID_ANIMATION_SURFACE );
- bProfileID = gAnimSurfaceDatabase[ usAnimSurface ].bProfile;
- *usFlags = 0;
- // Determine if this animation has a profile
- if ( bProfileID != -1 )
- {
- // Getprofile
- pProfile = &(gpAnimProfiles[ bProfileID ] );
- // Get direction
- pProfileDir = &( pProfile->Dirs[ pSoldier->bDirection ] );
- // Loop tiles and set accordingly into world
- for( iTileCount = 0; iTileCount < pProfileDir->ubNumTiles; iTileCount++ )
- {
- pProfileTile = &( pProfileDir->pTiles[ iTileCount ] );
- sGridNo = pSoldier->sGridNo + ( ( WORLD_COLS * pProfileTile->bTileY ) + pProfileTile->bTileX );
- // Check if in bounds
- if ( !OutOfBounds( pSoldier->sGridNo, sGridNo ) )
- {
- if ( sGridNo == sTestGridNo )
- {
- *usFlags = pProfileTile->usTileFlags;
- return( TRUE );
- }
- }
- }
- }
- return( FALSE );
- }
- void EVENT_SoldierBeginGiveItem( SOLDIERTYPE *pSoldier )
- {
- SOLDIERTYPE *pTSoldier;
- if ( VerifyGiveItem( pSoldier, &pTSoldier ) )
- {
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- pSoldier->bDesiredDirection = pSoldier->bPendingActionData3;
- pSoldier->bDirection = pSoldier->bPendingActionData3;
- // begin animation
- EVENT_InitNewSoldierAnim( pSoldier, GIVE_ITEM, 0 , FALSE );
- }
- else
- {
- UnSetEngagedInConvFromPCAction( pSoldier );
- MemFree( pSoldier->pTempObject );
- }
- }
- void EVENT_SoldierBeginBladeAttack( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- SOLDIERTYPE *pTSoldier;
- //UINT32 uiMercFlags;
- UINT16 usSoldierIndex;
- UINT8 ubTDirection;
- BOOLEAN fChangeDirection = FALSE;
- ROTTING_CORPSE *pCorpse;
- // Increment the number of people busy doing stuff because of an attack
- //if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
- //{
- gTacticalStatus.ubAttackBusyCount++;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Begin blade attack: ATB %d", gTacticalStatus.ubAttackBusyCount) );
- //}
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- // CHANGE TO ANIMATION
- // DETERMINE ANIMATION TO PLAY
- // LATER BASED ON IF TAREGT KNOWS OF US, STANCE, ETC
- // GET POINTER TO TAREGT
- if (pSoldier->uiStatusFlags & SOLDIER_MONSTER)
- {
- UINT8 ubTargetID;
- // Is there an unconscious guy at gridno......
- ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel );
-
- if ( ubTargetID != NOBODY && ( ( MercPtrs[ ubTargetID ]->bLife < OKLIFE && MercPtrs[ ubTargetID ]->bLife > 0 ) || ( MercPtrs[ ubTargetID ]->bBreath < OKBREATH && MercPtrs[ ubTargetID ]->bCollapsed ) ) )
- {
- pSoldier->uiPendingActionData4 = ubTargetID;
- // add regen bonus
- pSoldier->bRegenerationCounter++;
- EVENT_InitNewSoldierAnim( pSoldier, MONSTER_BEGIN_EATTING_FLESH, 0, FALSE );
- }
- else
- {
- if ( PythSpacesAway( pSoldier->sGridNo, sGridNo ) <= 1 )
- {
- EVENT_InitNewSoldierAnim( pSoldier, MONSTER_CLOSE_ATTACK, 0, FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, ADULTMONSTER_ATTACKING, 0, FALSE );
- }
- }
- }
- else if (pSoldier->ubBodyType == BLOODCAT)
- {
- // Check if it's a claws or teeth...
- if ( pSoldier->inv[ HANDPOS ].usItem == BLOODCAT_CLAW_ATTACK )
- {
- EVENT_InitNewSoldierAnim( pSoldier, BLOODCAT_SWIPE, 0, FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, BLOODCAT_BITE_ANIM, 0, FALSE );
- }
- }
- else
- {
- usSoldierIndex = WhoIsThere2( sGridNo, pSoldier->bTargetLevel );
- if ( usSoldierIndex != NOBODY )
- {
- GetSoldier( &pTSoldier, usSoldierIndex );
- // Look at stance of target
- switch( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- case ANIM_CROUCH:
- // CHECK IF HE CAN SEE US, IF SO RANDOMIZE
- if ( pTSoldier->bOppList[ pSoldier->ubID ] == 0 && pTSoldier->bTeam != pSoldier->bTeam )
- {
- // WE ARE NOT SEEN
- EVENT_InitNewSoldierAnim( pSoldier, STAB, 0 , FALSE );
- }
- else
- {
- // WE ARE SEEN
- if ( Random( 50 ) > 25 )
- {
- EVENT_InitNewSoldierAnim( pSoldier, STAB, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, SLICE, 0 , FALSE );
- }
- // IF WE ARE SEEN, MAKE SURE GUY TURNS!
- // Get direction to target
- // IF WE ARE AN ANIMAL, CAR, MONSTER, DONT'T TURN
- if ( !( pTSoldier->uiStatusFlags & ( SOLDIER_MONSTER | SOLDIER_ANIMAL | SOLDIER_VEHICLE ) ) )
- {
- // OK, stop merc....
- EVENT_StopMerc( pTSoldier, pTSoldier->sGridNo, pTSoldier->bDirection );
- if ( pTSoldier->bTeam != gbPlayerNum )
- {
- CancelAIAction( pTSoldier, TRUE );
- }
- ubTDirection = (UINT8)GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier );
- SendSoldierSetDesiredDirectionEvent( pTSoldier, ubTDirection );
- }
- }
- break;
- case ANIM_PRONE:
- // CHECK OUR STANCE
- if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH )
- {
- // SET DESIRED STANCE AND SET PENDING ANIMATION
- SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH );
- pSoldier->usPendingAnimation = CROUCH_STAB;
- }
- else
- {
- // USE crouched one
- // NEED TO CHANGE STANCE IF NOT CROUCHD!
- EVENT_InitNewSoldierAnim( pSoldier, CROUCH_STAB, 0 , FALSE );
- }
- break;
- }
- }
- else
- {
- // OK, SEE IF THERE IS AN OBSTACLE HERE...
- if ( !NewOKDestination( pSoldier, sGridNo, FALSE, pSoldier->bLevel ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, STAB, 0 , FALSE );
- }
- else
- {
- // Check for corpse!
- pCorpse = GetCorpseAtGridNo( sGridNo, pSoldier->bLevel );
- if ( pCorpse == NULL )
- {
- EVENT_InitNewSoldierAnim( pSoldier, CROUCH_STAB, 0 , FALSE );
- }
- else
- {
- if ( IsValidDecapitationCorpse( pCorpse ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, DECAPITATE, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, CROUCH_STAB, 0 , FALSE );
- }
- }
- }
- }
- }
- // SET TARGET GRIDNO
- pSoldier->sTargetGridNo = sGridNo;
- pSoldier->bTargetLevel = pSoldier->bLevel;
- pSoldier->ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel );
- }
- void EVENT_SoldierBeginPunchAttack( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- BOOLEAN fMartialArtist = FALSE;
- SOLDIERTYPE *pTSoldier;
- //UINT32 uiMercFlags;
- UINT16 usSoldierIndex;
- UINT8 ubTDirection;
- BOOLEAN fChangeDirection = FALSE;
- UINT16 usItem;
- // Get item in hand...
- usItem = pSoldier->inv[ HANDPOS ].usItem;
-
- // Increment the number of people busy doing stuff because of an attack
- //if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
- //{
- gTacticalStatus.ubAttackBusyCount++;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Begin HTH attack: ATB %d", gTacticalStatus.ubAttackBusyCount) );
- //}
- // get target.....
- usSoldierIndex = WhoIsThere2( pSoldier->sTargetGridNo, pSoldier->bLevel );
- if ( usSoldierIndex != NOBODY )
- {
- GetSoldier( &pTSoldier, usSoldierIndex );
- fChangeDirection = TRUE;
- }
- else
- {
- return;
- }
- if ( fChangeDirection )
- {
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- }
- // Are we a martial artist?
- if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS ) )
- {
- fMartialArtist = TRUE;
- }
- if ( fMartialArtist && !AreInMeanwhile( ) && usItem != CROWBAR )
- {
- // Are we in attack mode yet?
- if ( pSoldier->usAnimState != NINJA_BREATH && gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_STAND && gAnimControl[ pTSoldier->usAnimState ].ubHeight != ANIM_PRONE )
- {
- EVENT_InitNewSoldierAnim( pSoldier, NINJA_GOTOBREATH, 0 , FALSE );
- }
- else
- {
- DoNinjaAttack( pSoldier );
- }
- }
- else
- {
- // Look at stance of target
- switch( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- case ANIM_CROUCH:
- if ( usItem != CROWBAR )
- {
- EVENT_InitNewSoldierAnim( pSoldier, PUNCH, 0 , FALSE );
- }
- else
- {
- EVENT_InitNewSoldierAnim( pSoldier, CROWBAR_ATTACK, 0 , FALSE );
- }
- // CHECK IF HE CAN SEE US, IF SO CHANGE DIR
- if ( pTSoldier->bOppList[ pSoldier->ubID ] == 0 && pTSoldier->bTeam != pSoldier->bTeam )
- {
- // Get direction to target
- // IF WE ARE AN ANIMAL, CAR, MONSTER, DONT'T TURN
- if ( !( pTSoldier->uiStatusFlags & ( SOLDIER_MONSTER | SOLDIER_ANIMAL | SOLDIER_VEHICLE ) ) )
- {
- // OK, stop merc....
- EVENT_StopMerc( pTSoldier, pTSoldier->sGridNo, pTSoldier->bDirection );
- if ( pTSoldier->bTeam != gbPlayerNum )
- {
- CancelAIAction( pTSoldier, TRUE );
- }
- ubTDirection = (UINT8)GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier );
- SendSoldierSetDesiredDirectionEvent( pTSoldier, ubTDirection );
- }
- }
- break;
- case ANIM_PRONE:
- // CHECK OUR STANCE
- // ATE: Added this for CIV body types 'cause of elliot
- if ( !IS_MERC_BODY_TYPE( pSoldier ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, PUNCH, 0 , FALSE );
- }
- else
- {
- if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH )
- {
- // SET DESIRED STANCE AND SET PENDING ANIMATION
- SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH );
- pSoldier->usPendingAnimation = PUNCH_LOW;
- }
- else
- {
- // USE crouched one
- // NEED TO CHANGE STANCE IF NOT CROUCHD!
- EVENT_InitNewSoldierAnim( pSoldier, PUNCH_LOW, 0 , FALSE );
- }
- }
- break;
- }
- }
- // SET TARGET GRIDNO
- pSoldier->sTargetGridNo = sGridNo;
- pSoldier->bTargetLevel = pSoldier->bLevel;
- pSoldier->sLastTarget = sGridNo;
- pSoldier->ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel );
- }
- void EVENT_SoldierBeginKnifeThrowAttack( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- // Increment the number of people busy doing stuff because of an attack
- //if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
- //{
- gTacticalStatus.ubAttackBusyCount++;
- //}
- pSoldier->bBulletsLeft = 1;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting knifethrow attack, bullets left %d", pSoldier->bBulletsLeft) );
- EVENT_InitNewSoldierAnim( pSoldier, THROW_KNIFE, 0 , FALSE );
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- // SET TARGET GRIDNO
- pSoldier->sTargetGridNo = sGridNo;
- pSoldier->sLastTarget = sGridNo;
- pSoldier->fTurningFromPronePosition = 0;
- // NB target level must be set by functions outside of here... but I think it
- // is already set in HandleItem or in the AI code - CJC
- pSoldier->ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel );
- }
- void EVENT_SoldierBeginDropBomb( SOLDIERTYPE *pSoldier )
- {
- // Increment the number of people busy doing stuff because of an attack
- switch( gAnimControl[ pSoldier->usAnimState ].ubHeight )
- {
- case ANIM_STAND:
- EVENT_InitNewSoldierAnim( pSoldier, PLANT_BOMB, 0 , FALSE );
- break;
- default:
- // Call hander for planting bomb...
- HandleSoldierDropBomb( pSoldier, pSoldier->sPendingActionData2 );
- SoldierGotoStationaryStance( pSoldier );
- break;
- }
- }
- void EVENT_SoldierBeginUseDetonator( SOLDIERTYPE *pSoldier )
- {
- // Increment the number of people busy doing stuff because of an attack
- switch( gAnimControl[ pSoldier->usAnimState ].ubHeight )
- {
- case ANIM_STAND:
- EVENT_InitNewSoldierAnim( pSoldier, USE_REMOTE, 0 , FALSE );
- break;
- default:
- // Call hander for planting bomb...
- HandleSoldierUseRemote( pSoldier, pSoldier->sPendingActionData2 );
- break;
- }
- }
- void EVENT_SoldierBeginFirstAid( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- SOLDIERTYPE *pTSoldier;
- //UINT32 uiMercFlags;
- UINT16 usSoldierIndex;
- BOOLEAN fRefused = FALSE;
- usSoldierIndex = WhoIsThere2( sGridNo, pSoldier->bLevel );
- if ( usSoldierIndex != NOBODY )
- {
- pTSoldier = MercPtrs[ usSoldierIndex ];
- // OK, check if we should play quote...
- if ( pTSoldier->bTeam != gbPlayerNum )
- {
- if ( pTSoldier->ubProfile != NO_PROFILE && pTSoldier->ubProfile >= FIRST_RPC && !RPC_RECRUITED( pTSoldier ) )
- {
- fRefused = PCDoesFirstAidOnNPC( pTSoldier->ubProfile );
- }
- if ( !fRefused )
- {
- if ( CREATURE_OR_BLOODCAT( pTSoldier ) )
- {
- // nope!!
- fRefused = TRUE;
- ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, Message[ STR_REFUSE_FIRSTAID_FOR_CREATURE ] );
- }
- else if ( !pTSoldier->bNeutral && pTSoldier->bLife >= OKLIFE && pTSoldier->bSide != pSoldier->bSide )
- {
- fRefused = TRUE;
- ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, Message[ STR_REFUSE_FIRSTAID ] );
- }
- }
- }
- if ( fRefused )
- {
- UnSetUIBusy( pSoldier->ubID );
- return;
- }
- // ATE: We can only give firsty aid to one perosn at a time... cancel
- // any now...
- InternalGivingSoldierCancelServices( pSoldier, FALSE );
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- // CHECK OUR STANCE AND GOTO CROUCH IF NEEDED
- //if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH )
- //{
- // SET DESIRED STANCE AND SET PENDING ANIMATION
- // SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH );
- // pSoldier->usPendingAnimation = START_AID;
- //}
- //else
- {
- // CHANGE TO ANIMATION
- EVENT_InitNewSoldierAnim( pSoldier, START_AID, 0 , FALSE );
- }
- // SET TARGET GRIDNO
- pSoldier->sTargetGridNo = sGridNo;
-
- // SET PARTNER ID
- pSoldier->ubServicePartner = (UINT8)usSoldierIndex;
- // SET PARTNER'S COUNT REFERENCE
- pTSoldier->ubServiceCount++;
- // If target and doer are no the same guy...
- if ( pTSoldier->ubID != pSoldier->ubID && !pTSoldier->bCollapsed )
- {
- SoldierGotoStationaryStance( pTSoldier );
- }
- }
- }
- void EVENT_SoldierEnterVehicle( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- SOLDIERTYPE *pTSoldier;
- UINT32 uiMercFlags;
- UINT16 usSoldierIndex;
- if ( FindSoldier( sGridNo, &usSoldierIndex, &uiMercFlags, FIND_SOLDIER_GRIDNO ) )
- {
- pTSoldier = MercPtrs[ usSoldierIndex ];
- // Enter vehicle...
- EnterVehicle( pTSoldier, pSoldier );
- }
- UnSetUIBusy( pSoldier->ubID );
- }
- UINT32 SoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, INT16 sKitPts, INT16 sStatus )
- {
- UINT32 uiDressSkill, uiPossible, uiActual, uiMedcost, uiDeficiency, uiAvailAPs, uiUsedAPs;
- UINT8 ubBelowOKlife, ubPtsLeft;
- BOOLEAN fRanOut = FALSE;
- if (pVictim->bBleeding < 1 && pVictim->bLife >= OKLIFE )
- {
- return(0); // nothing to do, shouldn't have even been called!
- }
- if ( pVictim->bLife == 0 )
- {
- return(0);
- }
- // in case he has multiple kits in hand, limit influence of kit status to 100%!
- if (sStatus >= 100)
- {
- sStatus = 100;
- }
- // calculate wound-dressing skill (3x medical, 2x equip, 1x level, 1x dex)
- uiDressSkill = ( ( 3 * EffectiveMedical( pSoldier ) ) + // medical knowledge
- ( 2 * sStatus) + // state of medical kit
- (10 * EffectiveExpLevel( pSoldier ) ) + // battle injury experience
- EffectiveDexterity( pSoldier ) ) / 7; // general "handiness"
- // try to use every AP that the merc has left
- uiAvailAPs = pSoldier->bActionPoints;
- // OK, If we are in real-time, use another value...
- if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) )
- {
- // Set to a value which looks good based on our tactical turns duration
- uiAvailAPs = RT_FIRST_AID_GAIN_MODIFIER;
- }
- // calculate how much bandaging CAN be done this turn
- uiPossible = ( uiAvailAPs * uiDressSkill ) / 50; // max rate is 2 * fullAPs
- // if no healing is possible (insufficient APs or insufficient dressSkill)
- if (!uiPossible)
- return(0);
- if (pSoldier->inv[ HANDPOS ].usItem == MEDICKIT ) // using the GOOD medic stuff
- {
- uiPossible += ( uiPossible / 2); // add extra 50 %
- }
- uiActual = uiPossible; // start by assuming maximum possible
- // figure out how far below OKLIFE the victim is
- if (pVictim->bLife >= OKLIFE)
- {
- ubBelowOKlife = 0;
- }
- else
- {
- ubBelowOKlife = OKLIFE - pVictim->bLife;
- }
- // figure out how many healing pts we need to stop dying (2x cost)
- uiDeficiency = (2 * ubBelowOKlife );
- // if, after that, the patient will still be bleeding
- if ( (pVictim->bBleeding - ubBelowOKlife ) > 0)
- {
- // then add how many healing pts we need to stop bleeding (1x cost)
- uiDeficiency += ( pVictim->bBleeding - ubBelowOKlife );
- }
- // now, make sure we weren't going to give too much
- if ( uiActual > uiDeficiency) // if we were about to apply too much
- uiActual = uiDeficiency; // reduce actual not to waste anything
- // now make sure we HAVE that much
- if (pSoldier->inv[ HANDPOS ].usItem == MEDICKIT)
- {
- uiMedcost = (uiActual + 1) / 2; // cost is only half, rounded up
- if ( uiMedcost > (UINT32)sKitPts ) // if we can't afford this
- {
- fRanOut = TRUE;
- uiMedcost = sKitPts; // what CAN we afford?
- uiActual = uiMedcost * 2; // give double this as aid
- }
- }
- else
- {
- uiMedcost = uiActual;
- if ( uiMedcost > (UINT32)sKitPts) // can't afford it
- {
- fRanOut = TRUE;
- uiMedcost = uiActual = sKitPts; // recalc cost AND aid
- }
- }
- ubPtsLeft = (UINT8)uiActual;
- // heal real life points first (if below OKLIFE) because we don't want the
- // patient still DYING if bandages run out, or medic is disabled/distracted!
- // NOTE: Dressing wounds for life below OKLIFE now costs 2 pts/life point!
- if ( ubPtsLeft && pVictim->bLife < OKLIFE)
- {
- // if we have enough points to bring him all the way to OKLIFE this turn
- if ( ubPtsLeft >= (2 * ubBelowOKlife ) )
- {
- // raise life to OKLIFE
- pVictim->bLife = OKLIFE;
- // reduce bleeding by the same number of life points healed up
- pVictim->bBleeding -= ubBelowOKlife;
- // use up appropriate # of actual healing points
- ubPtsLeft -= (2 * ubBelowOKlife);
- }
- else
- {
- pVictim->bLife += ( ubPtsLeft / 2);
- pVictim->bBleeding -= ( ubPtsLeft / 2);
- ubPtsLeft = ubPtsLeft % 2; // if ptsLeft was odd, ptsLeft = 1
- }
- // this should never happen any more, but make sure bleeding not negative
- if (pVictim->bBleeding < 0)
- {
- pVictim->bBleeding = 0;
- }
- // if this healing brought the patient out of the worst of it, cancel dying
- if (pVictim->bLife >= OKLIFE )
- {
- //pVictim->dying = pVictim->dyingComment = FALSE;
- //pVictim->shootOn = TRUE;
- // turn off merc QUOTE flags
- pVictim->fDyingComment = FALSE;
- }
- // update patient's entire panel (could have regained consciousness, etc.)
- }
- // if any healing points remain, apply that to any remaining bleeding (1/1)
- // DON'T spend any APs/kit pts to cure bleeding until merc is no longer dying
- //if ( ubPtsLeft && pVictim->bBleeding && !pVictim->dying)
- if ( ubPtsLeft && pVictim->bBleeding )
- {
- // if we have enough points to bandage all remaining bleeding this turn
- if (ubPtsLeft >= pVictim->bBleeding )
- {
- ubPtsLeft -= pVictim->bBleeding;
- pVictim->bBleeding = 0;
- }
- else // bandage what we can
- {
- pVictim->bBleeding -= ubPtsLeft;
- ubPtsLeft = 0;
- }
- // update patient's life bar only
- }
- // if wound has been dressed enough so that bleeding won't occur, turn off
- // the "warned about bleeding" flag so merc tells us about the next bleeding
- if ( pVictim->bBleeding <= MIN_BLEEDING_THRESHOLD )
- {
- pVictim->fWarnedAboutBleeding = FALSE;
- }
- // if there are any ptsLeft now, then we didn't actually get to use them
- uiActual -= ubPtsLeft;
- // usedAPs equals (actionPts) * (%of possible points actually used)
- uiUsedAPs = ( uiActual * uiAvailAPs ) / uiPossible;
- if (pSoldier->inv[ HANDPOS ].usItem == MEDICKIT) // using the GOOD medic stuff
- {
- uiUsedAPs = ( uiUsedAPs * 2) / 3; // reverse 50% bonus by taking 2/3rds
- }
- DeductPoints( pSoldier, (INT16)uiUsedAPs, (INT16)( ( uiUsedAPs * BP_PER_AP_LT_EFFORT) ) );
- if ( PTR_OURTEAM )
- {
- // MEDICAL GAIN (actual / 2): Helped someone by giving first aid
- StatChange(pSoldier, MEDICALAMT, (UINT16)(uiActual / 2), FALSE);
- // DEXTERITY GAIN (actual / 6): Helped someone by giving first aid
- StatChange(pSoldier, DEXTAMT, (UINT16)(uiActual / 6), FALSE);
- }
- return( uiMedcost );
- }
- void InternalReceivingSoldierCancelServices( SOLDIERTYPE *pSoldier, BOOLEAN fPlayEndAnim )
- {
- SOLDIERTYPE *pTSoldier;
- INT32 cnt;
- if ( pSoldier->ubServiceCount > 0 )
- {
- // Loop through guys who have us as servicing
- for ( pTSoldier = Menptr, cnt = 0; cnt < MAX_NUM_SOLDIERS; pTSoldier++, cnt++ )
- {
- if ( pTSoldier->bActive )
- {
- if ( pTSoldier->ubServicePartner == pSoldier->ubID )
- {
- // END SERVICE!
- pSoldier->ubServiceCount--;
- pTSoldier->ubServicePartner = NOBODY;
- if ( gTacticalStatus.fAutoBandageMode )
- {
- pSoldier->ubAutoBandagingMedic = NOBODY;
- ActionDone( pTSoldier );
- }
- else
- {
- // don't use end aid animation in autobandage
- if ( pTSoldier->bLife >= OKLIFE && pTSoldier->bBreath > 0 && fPlayEndAnim )
- {
- EVENT_InitNewSoldierAnim( pTSoldier, END_AID, 0 , FALSE );
- }
- }
- }
- }
- }
- }
- }
- void ReceivingSoldierCancelServices( SOLDIERTYPE *pSoldier )
- {
- InternalReceivingSoldierCancelServices( pSoldier, TRUE );
- }
- void InternalGivingSoldierCancelServices( SOLDIERTYPE *pSoldier, BOOLEAN fPlayEndAnim )
- {
- SOLDIERTYPE *pTSoldier;
- // GET TARGET SOLDIER
- if ( pSoldier->ubServicePartner != NOBODY )
- {
- pTSoldier = MercPtrs[ pSoldier->ubServicePartner ];
- // END SERVICE!
- pTSoldier->ubServiceCount--;
- pSoldier->ubServicePartner = NOBODY;
- if ( gTacticalStatus.fAutoBandageMode )
- {
- pTSoldier->ubAutoBandagingMedic = NOBODY;
- ActionDone( pSoldier );
- }
- else
- {
- if ( pSoldier->bLife >= OKLIFE && pSoldier->bBreath > 0 && fPlayEndAnim )
- {
- // don't use end aid animation in autobandage
- EVENT_InitNewSoldierAnim( pSoldier, END_AID, 0 , FALSE );
- }
- }
- }
- }
- void GivingSoldierCancelServices( SOLDIERTYPE *pSoldier )
- {
- InternalGivingSoldierCancelServices( pSoldier, TRUE );
- }
- void HaultSoldierFromSighting( SOLDIERTYPE *pSoldier, BOOLEAN fFromSightingEnemy )
- {
- // SEND HUALT EVENT!
- //EV_S_STOP_MERC SStopMerc;
- //SStopMerc.sGridNo = pSoldier->sGridNo;
- //SStopMerc.bDirection = pSoldier->bDirection;
- //SStopMerc.usSoldierID = pSoldier->ubID;
- //AddGameEvent( S_STOP_MERC, 0, &SStopMerc );
- // If we are a 'specialmove... ignore...
- if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_SPECIALMOVE ) )
- {
- return;
- }
- // OK, check if we were going to throw something, and give it back if so!
- if ( pSoldier->pTempObject != NULL && fFromSightingEnemy )
- {
- // Place it back into inv....
- AutoPlaceObject( pSoldier, pSoldier->pTempObject, FALSE );
- MemFree( pSoldier->pTempObject );
- pSoldier->pTempObject = NULL;
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
- // Decrement attack counter...
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., ending throw because saw something") );
- ReduceAttackBusyCount( pSoldier->ubID, FALSE );
- // ATE: Goto stationary stance......
- SoldierGotoStationaryStance( pSoldier );
- DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
- }
- if ( !( gTacticalStatus.uiFlags & INCOMBAT ) )
- {
- EVENT_StopMerc( pSoldier, pSoldier->sGridNo, pSoldier->bDirection );
- }
- else
- {
- // Pause this guy from no APS
- AdjustNoAPToFinishMove( pSoldier, TRUE );
- pSoldier->ubReasonCantFinishMove = REASON_STOPPED_SIGHT;
- // ATE; IF turning to shoot, stop!
- // ATE: We want to do this only for enemies, not items....
- if ( pSoldier->fTurningToShoot && fFromSightingEnemy )
- {
- pSoldier->fTurningToShoot = FALSE;
- // Release attacker
- // OK - this is hightly annoying , but due to the huge combinations of
- // things that can happen - 1 of them is that sLastTarget will get unset
- // after turn is done - so set flag here to tell it not to...
- pSoldier->fDontUnsetLastTargetFromTurn = TRUE;
-
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., ending fire because saw something") );
- ReduceAttackBusyCount( pSoldier->ubID, FALSE );
- }
- // OK, if we are stopped at our destination, cancel pending action...
- if ( fFromSightingEnemy )
- {
- if ( pSoldier->ubPendingAction != NO_PENDING_ACTION && pSoldier->sGridNo == pSoldier->sFinalDestination )
- {
- pSoldier->ubPendingAction = NO_PENDING_ACTION;
- }
- // Stop pending animation....
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
- }
- if ( !pSoldier->fTurningToShoot )
- {
- pSoldier->fTurningFromPronePosition = FALSE;
- }
- }
- // Unset UI!
- if ( fFromSightingEnemy || ( pSoldier->pTempObject == NULL && !pSoldier->fTurningToShoot ) )
- {
- UnSetUIBusy( pSoldier->ubID );
- }
- pSoldier->bTurningFromUI = FALSE;
- UnSetEngagedInConvFromPCAction( pSoldier );
- }
- // HUALT EVENT IS USED TO STOP A MERC - NETWORKING SHOULD CHECK / ADJUST TO GRIDNO?
- void EVENT_StopMerc( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDirection )
- {
- INT16 sX, sY;
- // MOVE GUY TO GRIDNO--- SHOULD BE THE SAME UNLESS IN MULTIPLAYER
- // Makesure center of tile
- sX = CenterX( sGridNo );
- sY = CenterY( sGridNo );
- //Cancel pending events
- if ( !pSoldier->fDelayedMovement )
- {
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
- pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
- pSoldier->ubPendingAction = NO_PENDING_ACTION;
- }
- pSoldier->bEndDoorOpenCode = 0;
- pSoldier->fTurningFromPronePosition = 0;
- // Cancel path data!
- pSoldier->usPathIndex = pSoldier->usPathDataSize = 0;
-
- // Set ext tile waiting flag off!
- pSoldier->fDelayedMovement = FALSE;
- // Turn off reverse...
- pSoldier->bReverse = FALSE;
- EVENT_SetSoldierPosition( pSoldier, (FLOAT) sX, (FLOAT) sY );
- pSoldier->sDestXPos = (INT16)pSoldier->dXPos;
- pSoldier->sDestYPos = (INT16)pSoldier->dYPos;
- EVENT_SetSoldierDirection(pSoldier, bDirection);
-
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING )
- {
- SoldierGotoStationaryStance( pSoldier );
- }
- // ATE; IF turning to shoot, stop!
- if ( pSoldier->fTurningToShoot )
- {
- pSoldier->fTurningToShoot = FALSE;
- // Release attacker
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., ending fire because saw something") );
- ReduceAttackBusyCount( pSoldier->ubID, FALSE );
- }
- // Turn off multi-move speed override....
- if ( pSoldier->sGridNo == pSoldier->sFinalDestination )
- {
- pSoldier->fUseMoverrideMoveSpeed = FALSE;
- }
- // Unset UI!
- UnSetUIBusy( pSoldier->ubID );
- UnMarkMovementReserved( pSoldier );
- }
- void ReLoadSoldierAnimationDueToHandItemChange( SOLDIERTYPE *pSoldier, UINT16 usOldItem, UINT16 usNewItem )
- {
- // DON'T continue aiming!
- // GOTO STANCE
- // CHECK FOR AIMING ANIMATIONS
- BOOLEAN fOldRifle = FALSE;
- BOOLEAN fNewRifle = FALSE;
-
- // Shutoff burst....
- // ( we could be on, then change gun that does not have burst )
- if ( Weapon[ usNewItem ].ubShotsPerBurst == 0 )
- {
- pSoldier->bDoBurst = FALSE;
- pSoldier->bWeaponMode = WM_NORMAL;
- }
- if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY )
- {
- // Stop aiming!
- SoldierGotoStationaryStance( pSoldier );
- }
- // Cancel services...
- GivingSoldierCancelServices( pSoldier );
- // Did we have a rifle and do we now not have one?
- if ( usOldItem != NOTHING )
- {
- if ( Item[ usOldItem ].usItemClass == IC_GUN )
- {
- if ( (Item[ usOldItem ].fFlags & ITEM_TWO_HANDED) && usOldItem != ROCKET_LAUNCHER )
- {
- fOldRifle = TRUE;
- }
- }
- }
- if ( usNewItem != NOTHING )
- {
- if ( Item[ usNewItem ].usItemClass == IC_GUN )
- {
- if ( (Item[ usNewItem ].fFlags & ITEM_TWO_HANDED) && usNewItem != ROCKET_LAUNCHER )
- {
- fNewRifle = TRUE;
- }
- }
- }
- // Switch on stance!
- switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- if ( fOldRifle && !fNewRifle )
- {
- // Put it away!
- EVENT_InitNewSoldierAnim( pSoldier, LOWER_RIFLE, 0 , FALSE );
- }
- else if ( !fOldRifle && fNewRifle )
- {
- // Bring it up!
- EVENT_InitNewSoldierAnim( pSoldier, RAISE_RIFLE, 0 , FALSE );
- }
- else
- {
- SetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
- }
- break;
- case ANIM_CROUCH:
- case ANIM_PRONE:
- SetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
- break;
- }
- }
- UINT16 *CreateEnemyGlow16BPPPalette( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, BOOLEAN fAdjustGreen )
- {
- UINT16 *p16BPPPalette, r16, g16, b16, usColor;
- UINT32 cnt;
- UINT32 rmod, gmod, bmod;
- UINT8 r,g,b;
- Assert( pPalette != NULL );
- p16BPPPalette = MemAlloc( sizeof( UINT16 ) * 256 );
- for ( cnt = 0; cnt < 256; cnt++ )
- {
- gmod = (pPalette[ cnt ].peGreen);
- bmod = (pPalette[ cnt ].peBlue);
- rmod = __max( rscale, (pPalette[ cnt ].peRed) );
- if ( fAdjustGreen )
- {
- gmod = __max( gscale, (pPalette[ cnt ].peGreen) );
- }
- r = (UINT8)__min(rmod, 255);
- g = (UINT8)__min(gmod, 255);
- b = (UINT8)__min(bmod, 255);
- if(gusRedShift < 0)
- r16=((UINT16)r>>(-gusRedShift));
- else
- r16=((UINT16)r<<gusRedShift);
- if(gusGreenShift < 0)
- g16=((UINT16)g>>(-gusGreenShift));
- else
- g16=((UINT16)g<<gusGreenShift);
- if(gusBlueShift < 0)
- b16=((UINT16)b>>(-gusBlueShift));
- else
- b16=((UINT16)b<<gusBlueShift);
- // Prevent creation of pure black color
- usColor = (r16&gusRedMask)|(g16&gusGreenMask)|(b16&gusBlueMask);
- if((usColor==0) && ((r+g+b)!=0))
- usColor=0x0001;
- p16BPPPalette[ cnt ] = usColor;
- }
- return( p16BPPPalette );
- }
-
- UINT16 *CreateEnemyGreyGlow16BPPPalette( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, BOOLEAN fAdjustGreen )
- {
- UINT16 *p16BPPPalette, r16, g16, b16, usColor;
- UINT32 cnt, lumin;
- UINT32 rmod, gmod, bmod;
- UINT8 r,g,b;
- Assert( pPalette != NULL );
- p16BPPPalette = MemAlloc( sizeof( UINT16 ) * 256 );
- for ( cnt = 0; cnt < 256; cnt++ )
- {
- lumin=(pPalette[ cnt ].peRed*299/1000)+ (pPalette[ cnt ].peGreen*587/1000)+(pPalette[ cnt ].peBlue*114/1000);
- rmod=(100*lumin)/256;
- gmod=(100*lumin)/256;
- bmod=(100*lumin)/256;
- rmod = __max( rscale, rmod );
- if ( fAdjustGreen )
- {
- gmod = __max( gscale, gmod );
- }
- r = (UINT8)__min(rmod, 255);
- g = (UINT8)__min(gmod, 255);
- b = (UINT8)__min(bmod, 255);
- if(gusRedShift < 0)
- r16=((UINT16)r>>(-gusRedShift));
- else
- r16=((UINT16)r<<gusRedShift);
- if(gusGreenShift < 0)
- g16=((UINT16)g>>(-gusGreenShift));
- else
- g16=((UINT16)g<<gusGreenShift);
- if(gusBlueShift < 0)
- b16=((UINT16)b>>(-gusBlueShift));
- else
- b16=((UINT16)b<<gusBlueShift);
- // Prevent creation of pure black color
- usColor = (r16&gusRedMask)|(g16&gusGreenMask)|(b16&gusBlueMask);
- if((usColor==0) && ((r+g+b)!=0))
- usColor=0x0001;
- p16BPPPalette[ cnt ] = usColor;
- }
- return( p16BPPPalette );
- }
- void ContinueMercMovement( SOLDIERTYPE *pSoldier )
- {
- INT16 sAPCost;
- INT16 sGridNo;
- sGridNo = pSoldier->sFinalDestination;
- // Can we afford this?
- if ( pSoldier->bGoodContPath )
- {
- sGridNo = pSoldier->sContPathLocation;
- }
- else
- {
- // ATE: OK, don't cancel count, so pending actions are still valid...
- pSoldier->ubPendingActionAnimCount = 0;
- }
- // get a path to dest...
- if ( FindBestPath( pSoldier, sGridNo, pSoldier->bLevel, pSoldier->usUIMovementMode, NO_COPYROUTE, 0 ) )
- {
- sAPCost = PtsToMoveDirection( pSoldier, (UINT8)guiPathingData[ 0 ] );
- if ( EnoughPoints( pSoldier, sAPCost, 0 , (BOOLEAN)( pSoldier->bTeam == gbPlayerNum ) ) )
- {
- // Acknowledge
- if ( pSoldier->bTeam == gbPlayerNum )
- {
- DoMercBattleSound( pSoldier, BATTLE_SOUND_OK1 );
- // If we have a face, tell text in it to go away!
- if ( pSoldier->iFaceIndex != -1 )
- {
- gFacesData[ pSoldier->iFaceIndex ].fDisplayTextOver = FACE_ERASE_TEXT_OVER;
- }
- }
- AdjustNoAPToFinishMove( pSoldier, FALSE );
- SetUIBusy( pSoldier->ubID );
- // OK, try and get a path to out dest!
- EVENT_InternalGetNewSoldierPath( pSoldier, sGridNo, pSoldier->usUIMovementMode, FALSE, TRUE );
- }
- }
- }
- BOOLEAN CheckForBreathCollapse( SOLDIERTYPE *pSoldier )
- {
- // Check if we are out of breath!
- // Only check if > 70
- if ( pSoldier->bBreathMax > 70 )
- {
- if ( pSoldier->bBreath < 20 && !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LOW_BREATH ) &&
- gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
- {
- // WARN!
- TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_BREATH );
- // Set flag indicating we were warned!
- pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LOW_BREATH;
- }
- }
- // Check for drowing.....
- //if ( pSoldier->bBreath < 10 && !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_DROWNING ) && pSoldier->bOverTerrainType == DEEP_WATER )
- //{
- // WARN!
- // TacticalCharacterDialogue( pSoldier, QUOTE_DROWNING );
-
- // Set flag indicating we were warned!
- // pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_DROWNING;
- // WISDOM GAIN (25): Starting to drown
- // StatChange( pSoldier, WISDOMAMT, 25, FALSE );
- //}
- if ( pSoldier->bBreath == 0 && !pSoldier->bCollapsed && !( pSoldier->uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_ANIMAL | SOLDIER_MONSTER ) ) )
- {
- // Collapse!
- // OK, Set a flag, because we may still be in the middle of an animation what is not interruptable...
- pSoldier->bBreathCollapsed = TRUE;
- return( TRUE );
- }
- return( FALSE );
- }
- BOOLEAN InternalIsValidStance( SOLDIERTYPE *pSoldier, INT8 bDirection, INT8 bNewStance )
- {
- UINT16 usOKToAddStructID=0;
- STRUCTURE_FILE_REF *pStructureFileRef;
- UINT16 usAnimSurface=0;
- UINT16 usAnimState;
- // Check, if dest is prone, we can actually do this!
- // If we are a vehicle, we can only 'stand'
- if ( ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) && bNewStance != ANIM_STAND )
- {
- return( FALSE );
- }
- // Check if we are in water?
- if ( MercInWater( pSoldier ) )
- {
- if ( bNewStance == ANIM_PRONE || bNewStance == ANIM_CROUCH )
- {
- return( FALSE );
- }
- }
- if ( pSoldier->ubBodyType == ROBOTNOWEAPON && bNewStance != ANIM_STAND )
- {
- return( FALSE );
- }
- // Check if we are in water?
- if ( AM_AN_EPC( pSoldier ) )
- {
- if ( bNewStance == ANIM_PRONE )
- {
- return( FALSE );
- }
- else
- {
- return( TRUE );
- }
- }
- if ( pSoldier->bCollapsed )
- {
- if ( bNewStance == ANIM_STAND || bNewStance == ANIM_CROUCH )
- {
- return( FALSE );
- }
- }
- // Check if we can do this....
- if ( pSoldier->pLevelNode && pSoldier->pLevelNode->pStructureData != NULL )
- {
- usOKToAddStructID = pSoldier->pLevelNode->pStructureData->usStructureID;
- }
- else
- {
- usOKToAddStructID = INVALID_STRUCTURE_ID;
- }
- switch( bNewStance )
- {
- case ANIM_STAND:
- usAnimState = STANDING;
- break;
- case ANIM_CROUCH:
- usAnimState = CROUCHING;
- break;
- case ANIM_PRONE:
- usAnimState = PRONE;
- break;
- default:
- // Something gone funny here....
- usAnimState = pSoldier->usAnimState;
- ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Wrong desired stance given: %d, %d.", bNewStance, pSoldier->usAnimState );
- }
- usAnimSurface = DetermineSoldierAnimationSurface( pSoldier, usAnimState );
- // Get structure ref........
- pStructureFileRef = GetAnimationStructureRef( pSoldier->ubID, usAnimSurface, usAnimState );
- if ( pStructureFileRef != NULL )
- {
- // Can we add structure data for this stance...?
- if ( !OkayToAddStructureToWorld( pSoldier->sGridNo, pSoldier->bLevel, &(pStructureFileRef->pDBStructureRef[gOneCDirection[ bDirection ]]), usOKToAddStructID ) )
- {
- return( FALSE );
- }
- }
- return( TRUE );
- }
- BOOLEAN IsValidStance( SOLDIERTYPE *pSoldier, INT8 bNewStance )
- {
- return( InternalIsValidStance( pSoldier, pSoldier->bDirection, bNewStance ) );
- }
- BOOLEAN IsValidMovementMode( SOLDIERTYPE *pSoldier, INT16 usMovementMode )
- {
- // Check, if dest is prone, we can actually do this!
- // Check if we are in water?
- if ( MercInWater( pSoldier ) )
- {
- if ( usMovementMode == RUNNING || usMovementMode == SWATTING || usMovementMode == CRAWLING )
- {
- return( FALSE );
- }
- }
- return( TRUE );
- }
- void SelectMoveAnimationFromStance( SOLDIERTYPE *pSoldier )
- {
- // Determine which animation to do...depending on stance and gun in hand...
- switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- EVENT_InitNewSoldierAnim( pSoldier, WALKING, 0 , FALSE );
- break;
- case ANIM_PRONE:
- EVENT_InitNewSoldierAnim( pSoldier, CRAWLING, 0 , FALSE );
- break;
- case ANIM_CROUCH:
- EVENT_InitNewSoldierAnim( pSoldier, SWATTING, 0 , FALSE );
- break;
- }
- }
- void GetActualSoldierAnimDims( SOLDIERTYPE *pSoldier, INT16 *psHeight, INT16 *psWidth )
- {
- UINT16 usAnimSurface;
- ETRLEObject *pTrav;
- usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
- if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
- {
- *psHeight = (INT16)5;
- *psWidth = (INT16)5;
-
- return;
- }
- if ( gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject == NULL )
- {
- *psHeight = (INT16)5;
- *psWidth = (INT16)5;
- return;
- }
- // OK, noodle here on what we should do... If we take each frame, it will be different slightly
- // depending on the frame and the value returned here will vary thusly. However, for the
- // uses of this function, we should be able to use just the first frame...
- if ( pSoldier->usAniFrame >= gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->usNumberOfObjects )
- {
- int i = 0;
- }
- pTrav = &(gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->pETRLEObject[ pSoldier->usAniFrame ] );
- *psHeight = (INT16)pTrav->usHeight;
- *psWidth = (INT16)pTrav->usWidth;
- }
- void GetActualSoldierAnimOffsets( SOLDIERTYPE *pSoldier, INT16 *sOffsetX, INT16 *sOffsetY )
- {
- UINT16 usAnimSurface;
- ETRLEObject *pTrav;
- usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
- if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
- {
- *sOffsetX = (INT16)0;
- *sOffsetY = (INT16)0;
- return;
- }
- if ( gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject == NULL )
- {
- *sOffsetX = (INT16)0;
- *sOffsetY = (INT16)0;
- return;
- }
- pTrav = &(gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->pETRLEObject[ pSoldier->usAniFrame ] );
- *sOffsetX = (INT16)pTrav->sOffsetX;
- *sOffsetY = (INT16)pTrav->sOffsetY;
- }
- void SetSoldierLocatorOffsets( SOLDIERTYPE *pSoldier )
- {
- INT16 sHeight, sWidth;
- INT16 sOffsetX, sOffsetY;
- // OK, from our animation, get height, width
- GetActualSoldierAnimDims( pSoldier, &sHeight, &sWidth );
- GetActualSoldierAnimOffsets( pSoldier, &sOffsetX, &sOffsetY );
- // OK, here, use the difference between center of animation ( sWidth/2 ) and our offset!
- //pSoldier->sLocatorOffX = ( abs( sOffsetX ) ) - ( sWidth / 2 );
- pSoldier->sBoundingBoxWidth = sWidth;
- pSoldier->sBoundingBoxHeight = sHeight;
- pSoldier->sBoundingBoxOffsetX = sOffsetX;
- pSoldier->sBoundingBoxOffsetY = sOffsetY;
- }
- BOOLEAN SoldierCarriesTwoHandedWeapon( SOLDIERTYPE *pSoldier )
- {
- UINT16 usItem;
- usItem = pSoldier->inv[ HANDPOS ].usItem;
- if ( usItem != NOTHING && (Item[ usItem ].fFlags & ITEM_TWO_HANDED) )
- {
- return( TRUE );
- }
- return( FALSE );
- }
- INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
- {
- INT8 bBandaged; //,savedOurTurn;
- INT32 iBlood = NOBLOOD;
- if ( pSoldier->bLife != 0 )
- {
- // if merc is hurt beyond the minimum required to bleed, or he's dying
- if ( ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD) || pSoldier->bLife < OKLIFE )
- {
- // if he's NOT in the process of being bandaged or DOCTORed
- if ( ( pSoldier->ubServiceCount == 0 ) && ( AnyDoctorWhoCanHealThisPatient( pSoldier, HEALABLE_EVER ) == NULL ) )
- {
- // may drop blood whether or not any bleeding takes place this turn
- if ( pSoldier->bTilesMoved < 1 )
- {
- iBlood = ( ( pSoldier->bBleeding - MIN_BLEEDING_THRESHOLD ) / BLOODDIVISOR ); // + pSoldier->dying;
- if ( iBlood > MAXBLOODQUANTITY )
- {
- iBlood = MAXBLOODQUANTITY;
- }
- }
- else
- {
- iBlood = NOBLOOD;
- }
- // Are we in a different mode?
- if ( !(gTacticalStatus.uiFlags & TURNBASED ) || !(gTacticalStatus.uiFlags & INCOMBAT ) )
- {
- pSoldier->dNextBleed -= (FLOAT)RT_NEXT_BLEED_MODIFIER;
- }
- else
- {
- // Do a single step descrease
- pSoldier->dNextBleed--;
- }
- // if it's time to lose some blood
- if ( pSoldier->dNextBleed <= 0)
- {
- // first, calculate if soldier is bandaged
- bBandaged = pSoldier->bLifeMax - pSoldier->bBleeding - pSoldier->bLife;
- // as long as he's bandaged and not "dying"
- if ( bBandaged && pSoldier->bLife >= OKLIFE )
- {
- // just bleeding through existing bandages
- pSoldier->bBleeding++;
- SoldierBleed( pSoldier, TRUE );
- }
- else // soldier is either not bandaged at all or is dying
- {
- if ( pSoldier->bLife < OKLIFE ) // if he's dying
- {
- // if he's conscious, and he hasn't already, say his "dying quote"
- if ( ( pSoldier->bLife >= CONSCIOUSNESS ) && !pSoldier->fDyingComment )
- {
- TacticalCharacterDialogue( pSoldier, QUOTE_SERIOUSLY_WOUNDED );
- pSoldier->fDyingComment = TRUE;
- }
- // can't permit lifemax to ever bleed beneath OKLIFE, or that
- // soldier might as well be dead!
- if (pSoldier->bLifeMax >= OKLIFE)
- {
- // bleeding while "dying" costs a PERMANENT point of life each time!
- pSoldier->bLifeMax--;
- pSoldier->bBleeding--;
- }
- }
- }
- // either way, a point of life (health) is lost because of bleeding
- // This will also update the life bar
- SoldierBleed( pSoldier, FALSE );
- // if he's not dying (which includes him saying the dying quote just
- // now), and he hasn't warned us that he's bleeding yet, he does so
- // Also, not if they are being bandaged....
- if ( ( pSoldier->bLife >= OKLIFE ) && !pSoldier->fDyingComment && !pSoldier->fWarnedAboutBleeding && !gTacticalStatus.fAutoBandageMode && pSoldier->ubServiceCount == 0 )
- {
- TacticalCharacterDialogue( pSoldier, QUOTE_STARTING_TO_BLEED );
- // "starting to bleed" quote
- pSoldier->fWarnedAboutBleeding = TRUE;
- }
- pSoldier->dNextBleed = CalcSoldierNextBleed( pSoldier );
- }
- }
- }
- }
- return( iBlood );
- }
- void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed )
- {
- INT8 bOldLife;
- // OK, here make some stuff happen for bleeding
- // A banaged bleed does not show damage taken , just through existing bandages
- // ATE: Do this ONLY if buddy is in sector.....
- if ( ( pSoldier->bInSector && guiCurrentScreen == GAME_SCREEN ) || guiCurrentScreen != GAME_SCREEN )
- {
- pSoldier->fFlashPortrait = TRUE;
- pSoldier->bFlashPortraitFrame = FLASH_PORTRAIT_STARTSHADE;
- RESETTIMECOUNTER( pSoldier->PortraitFlashCounter, FLASH_PORTRAIT_DELAY );
- // If we are in mapscreen, set this person as selected
- if ( guiCurrentScreen == MAP_SCREEN )
- {
- SetInfoChar( pSoldier->ubID );
- }
- }
- bOldLife = pSoldier->bLife;
- // If we are already dead, don't show damage!
- if ( !fBandagedBleed )
- {
- SoldierTakeDamage( pSoldier, ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
- }
- }
- void SoldierCollapse( SOLDIERTYPE *pSoldier )
- {
- BOOLEAN fMerc = FALSE;
- if ( pSoldier->ubBodyType <= REGFEMALE )
- {
- fMerc = TRUE;
- }
- // If we are an animal, etc, don't do anything....
- switch( pSoldier->ubBodyType )
- {
- case ADULTFEMALEMONSTER:
- case AM_MONSTER:
- case YAF_MONSTER:
- case YAM_MONSTER:
- case LARVAE_MONSTER:
- case INFANT_MONSTER:
- case QUEENMONSTER:
- // Give breath back....
- DeductPoints( pSoldier,0, (INT16)-5000 );
- return;
- break;
- }
- pSoldier->bCollapsed = TRUE;
- ReceivingSoldierCancelServices( pSoldier );
- // CC has requested - handle sight here...
- HandleSight( pSoldier, SIGHT_LOOK );
- // Check height
- switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
- {
- case ANIM_STAND:
- if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- EVENT_InitNewSoldierAnim( pSoldier, DEEP_WATER_DIE, 0, FALSE );
- }
- else if ( pSoldier->bOverTerrainType == LOW_WATER )
- {
- EVENT_InitNewSoldierAnim( pSoldier, WATER_DIE, 0, FALSE );
- }
- else
- {
- BeginTyingToFall( pSoldier );
- EVENT_InitNewSoldierAnim( pSoldier, FALLFORWARD_FROMHIT_STAND, 0, FALSE );
- }
- break;
- case ANIM_CROUCH:
- // Crouched or prone, only for mercs!
- BeginTyingToFall( pSoldier );
- if ( fMerc )
- {
- EVENT_InitNewSoldierAnim( pSoldier, FALLFORWARD_FROMHIT_CROUCH, 0 , FALSE);
- }
- else
- {
- // For civs... use fall from stand...
- EVENT_InitNewSoldierAnim( pSoldier, FALLFORWARD_FROMHIT_STAND, 0 , FALSE);
- }
- break;
- case ANIM_PRONE:
- switch( pSoldier->usAnimState )
- {
- case FALLFORWARD_FROMHIT_STAND:
- case ENDFALLFORWARD_FROMHIT_CROUCH:
- ChangeSoldierState( pSoldier, STAND_FALLFORWARD_STOP, 0, FALSE );
- break;
- case FALLBACK_HIT_STAND:
- ChangeSoldierState( pSoldier, FALLBACKHIT_STOP, 0, FALSE );
- break;
- default:
- EVENT_InitNewSoldierAnim( pSoldier, PRONE_LAY_FROMHIT, 0 , FALSE );
- break;
- }
- break;
- }
- if (pSoldier->uiStatusFlags & SOLDIER_ENEMY)
- {
- if ( !(gTacticalStatus.bPanicTriggerIsAlarm) && (gTacticalStatus.ubTheChosenOne == pSoldier->ubID) )
- {
- // replace this guy as the chosen one!
- gTacticalStatus.ubTheChosenOne = NOBODY;
- MakeClosestEnemyChosenOne();
- }
- if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && (pSoldier->uiStatusFlags & SOLDIER_UNDERAICONTROL))
- {
- #ifdef TESTAICONTROL
- DebugAI( String("Ending turn for %d because of error from HandleItem", pSoldier->ubID ) );
- #endif
- EndAIGuysTurn( pSoldier );
- }
- }
- // DON'T DE-SELECT GUY.....
- //else
- //{
- // Check if this is our selected guy...
- // if ( pSoldier->ubID == gusSelectedSoldier )
- // {
- // SelectNextAvailSoldier( pSoldier );
- // }
- //}
- }
- FLOAT CalcSoldierNextBleed( SOLDIERTYPE *pSoldier )
- {
- INT8 bBandaged;
- // calculate how many turns before he bleeds again
- // bleeding faster the lower life gets, and if merc is running around
- //pSoldier->nextbleed = 2 + (pSoldier->life / (10 + pSoldier->tilesMoved)); // min = 2
- // if bandaged, give 1/2 of the bandaged life points back into equation
- bBandaged = pSoldier->bLifeMax - pSoldier->bLife - pSoldier->bBleeding;
- return( (FLOAT)1 + (FLOAT)( (pSoldier->bLife + bBandaged / 2) / (10 + pSoldier->bTilesMoved) ) ); // min = 1
- }
- FLOAT CalcSoldierNextUnmovingBleed( SOLDIERTYPE *pSoldier )
- {
- INT8 bBandaged;
- // calculate bleeding rate without the penalty for tiles moved
- // if bandaged, give 1/2 of the bandaged life points back into equation
- bBandaged = pSoldier->bLifeMax - pSoldier->bLife - pSoldier->bBleeding;
-
- return( (FLOAT)1 + (FLOAT)( (pSoldier->bLife + bBandaged / 2) / 10 ) ); // min = 1
- }
- void HandlePlacingRoofMarker( SOLDIERTYPE *pSoldier, INT16 sGridNo, BOOLEAN fSet, BOOLEAN fForce )
- {
- LEVELNODE *pRoofNode;
- LEVELNODE *pNode;
- if ( pSoldier->bVisible == -1 && fSet )
- {
- return;
- }
- if ( pSoldier->bTeam != gbPlayerNum )
- {
- //return;
- }
- // If we are on the roof, add roof UI peice!
- if ( pSoldier->bLevel == SECOND_LEVEL )
- {
- // Get roof node
- pRoofNode = gpWorldLevelData[ sGridNo ].pRoofHead;
- // Return if we are still climbing roof....
- if ( pSoldier->usAnimState == CLIMBUPROOF && !fForce )
- {
- return;
- }
- if ( pRoofNode != NULL )
- {
- if ( fSet )
- {
- if ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED )
- {
- // Set some flags on this poor thing
- //pRoofNode->uiFlags |= ( LEVELNODE_USEBESTTRANSTYPE | LEVELNODE_REVEAL | LEVELNODE_DYNAMIC );
- //pRoofNode->uiFlags |= ( LEVELNODE_DYNAMIC );
- //pRoofNode->uiFlags &= ( ~LEVELNODE_HIDDEN );
- //ResetSpecificLayerOptimizing( TILES_DYNAMIC_ROOF );
- }
- }
- else
- {
- if ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED )
- {
- // Remove some flags on this poor thing
- //pRoofNode->uiFlags &= ~( LEVELNODE_USEBESTTRANSTYPE | LEVELNODE_REVEAL | LEVELNODE_DYNAMIC );
- //pRoofNode->uiFlags |= LEVELNODE_HIDDEN;
- }
- }
- if ( fSet )
- {
- // If it does not exist already....
- if ( !IndexExistsInRoofLayer( sGridNo, FIRSTPOINTERS11 ) )
- {
- pNode = AddRoofToTail( sGridNo, FIRSTPOINTERS11 );
- pNode->ubShadeLevel =DEFAULT_SHADE_LEVEL;
- pNode->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL;
- }
- }
- else
- {
- RemoveRoof( sGridNo, FIRSTPOINTERS11 );
- }
- }
- }
- }
- void PositionSoldierLight( SOLDIERTYPE *pSoldier )
- {
- // DO ONLY IF WE'RE AT A GOOD LEVEL
- if ( ubAmbientLightLevel < MIN_AMB_LEVEL_FOR_MERC_LIGHTS )
- {
- return;
- }
- if ( !pSoldier->bInSector )
- {
- return;
- }
- if ( pSoldier->bTeam != gbPlayerNum )
- {
- return;
- }
- if ( pSoldier->bLife < OKLIFE )
- {
- return;
- }
- //if the player DOESNT want the merc to cast light
- if( !gGameSettings.fOptions[ TOPTION_MERC_CASTS_LIGHT ] )
- {
- return;
- }
- if ( pSoldier->iLight == -1 )
- {
- CreateSoldierLight( pSoldier );
- }
- //if ( pSoldier->ubID == gusSelectedSoldier )
- {
- LightSpritePower(pSoldier->iLight, TRUE);
- LightSpriteFake(pSoldier->iLight);
- LightSpritePosition( pSoldier->iLight, (INT16)(pSoldier->sX/CELL_X_SIZE), (INT16)(pSoldier->sY/CELL_Y_SIZE));
- }
- }
- void SetCheckSoldierLightFlag( SOLDIERTYPE *pSoldier )
- {
- PositionSoldierLight( pSoldier );
- //pSoldier->uiStatusFlags |= SOLDIER_RECHECKLIGHT;
- }
- void PickPickupAnimation( SOLDIERTYPE *pSoldier, INT32 iItemIndex, INT16 sGridNo, INT8 bZLevel )
- {
- INT8 bDirection;
- STRUCTURE *pStructure;
- BOOLEAN fDoNormalPickup = TRUE;
- // OK, Given the gridno, determine if it's the same one or different....
- if ( sGridNo != pSoldier->sGridNo )
- {
- // Get direction to face....
- bDirection = (INT8)GetDirectionFromGridNo( sGridNo, pSoldier );
- pSoldier->ubPendingDirection = bDirection;
- // Change to pickup animation
- EVENT_InitNewSoldierAnim( pSoldier, ADJACENT_GET_ITEM, 0 , FALSE );
- if (!(pSoldier->uiStatusFlags & SOLDIER_PC))
- {
- // set "pending action" value for AI so it will wait
- pSoldier->bAction = AI_ACTION_PENDING_ACTION;
- }
- }
- else
- {
- // If in water....
- if ( MercInWater( pSoldier ) )
- {
- UnSetUIBusy( pSoldier->ubID );
- HandleSoldierPickupItem( pSoldier, iItemIndex, sGridNo, bZLevel );
- SoldierGotoStationaryStance( pSoldier );
- if (!(pSoldier->uiStatusFlags & SOLDIER_PC))
- {
- // reset action value for AI because we're done!
- ActionDone( pSoldier );
- }
- }
- else
- {
- // Don't show animation of getting item, if we are not standing
- switch ( gAnimControl[ pSoldier->usAnimState ].ubHeight )
- {
- case ANIM_STAND:
-
- // OK, if we are looking at z-level >0, AND
- // we have a strucxture with items in it
- // look for orientation and use angle accordingly....
- if ( bZLevel > 0 )
- {
- //#if 0
- // Get direction to face....
- if ( ( pStructure = FindStructure( (INT16)sGridNo, ( STRUCTURE_HASITEMONTOP | STRUCTURE_OPENABLE ) ) ) != NULL )
- {
- fDoNormalPickup = FALSE;
- // OK, look at orientation
- switch( pStructure->ubWallOrientation )
- {
- case OUTSIDE_TOP_LEFT:
- case INSIDE_TOP_LEFT:
- bDirection = (INT8)NORTH;
- break;
- case OUTSIDE_TOP_RIGHT:
- case INSIDE_TOP_RIGHT:
- bDirection = (INT8)WEST;
- break;
- default:
- bDirection = pSoldier->bDirection;
- break;
- }
- //pSoldier->ubPendingDirection = bDirection;
- EVENT_SetSoldierDesiredDirection( pSoldier, bDirection );
- EVENT_SetSoldierDirection( pSoldier, bDirection );
- // Change to pickup animation
- EVENT_InitNewSoldierAnim( pSoldier, ADJACENT_GET_ITEM, 0 , FALSE );
- }
- //#endif
- }
- if ( fDoNormalPickup )
- {
- EVENT_InitNewSoldierAnim( pSoldier, PICKUP_ITEM, 0 , FALSE );
- }
- if (!(pSoldier->uiStatusFlags & SOLDIER_PC))
- {
- // set "pending action" value for AI so it will wait
- pSoldier->bAction = AI_ACTION_PENDING_ACTION;
- }
- break;
-
- case ANIM_CROUCH:
- case ANIM_PRONE:
- UnSetUIBusy( pSoldier->ubID );
- HandleSoldierPickupItem( pSoldier, iItemIndex, sGridNo, bZLevel );
- SoldierGotoStationaryStance( pSoldier );
- if (!(pSoldier->uiStatusFlags & SOLDIER_PC))
- {
- // reset action value for AI because we're done!
- ActionDone( pSoldier );
- }
- break;
- }
- }
- }
- }
- void PickDropItemAnimation( SOLDIERTYPE *pSoldier )
- {
- // Don't show animation of getting item, if we are not standing
- switch ( gAnimControl[ pSoldier->usAnimState ].ubHeight )
- {
- case ANIM_STAND:
-
- EVENT_InitNewSoldierAnim( pSoldier, DROP_ITEM, 0 , FALSE );
- break;
-
- case ANIM_CROUCH:
- case ANIM_PRONE:
- SoldierHandleDropItem( pSoldier );
- SoldierGotoStationaryStance( pSoldier );
- break;
- }
- }
- void EVENT_SoldierBeginCutFence( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- // Make sure we have a structure here....
- if ( IsCuttableWireFenceAtGridNo( sGridNo ) )
- {
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- //BOOLEAN CutWireFence( INT16 sGridNo )
- // SET TARGET GRIDNO
- pSoldier->sTargetGridNo = sGridNo;
- // CHANGE TO ANIMATION
- EVENT_InitNewSoldierAnim( pSoldier, CUTTING_FENCE, 0 , FALSE );
- }
- }
- void EVENT_SoldierBeginRepair( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- INT8 bRepairItem;
- UINT8 ubID;
- // Make sure we have a structure here....
- bRepairItem = IsRepairableStructAtGridNo( sGridNo, &ubID );
- if ( bRepairItem )
- {
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- //BOOLEAN CutWireFence( INT16 sGridNo )
- // SET TARGET GRIDNO
- //pSoldier->sTargetGridNo = sGridNo;
- // CHANGE TO ANIMATION
- EVENT_InitNewSoldierAnim( pSoldier, GOTO_REPAIRMAN, 0 , FALSE );
- // SET BUDDY'S ASSIGNMENT TO REPAIR...
- // Are we a SAM site? ( 3 == SAM )
- if ( bRepairItem == 3 )
- {
- SetSoldierAssignment( pSoldier, REPAIR, TRUE, FALSE, -1 );
- }
- else if ( bRepairItem == 2 ) // ( 2 == VEHICLE )
- {
- SetSoldierAssignment( pSoldier, REPAIR, FALSE, FALSE, ubID );
- }
- }
- }
- void EVENT_SoldierBeginRefuel( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- INT8 bRefuelItem;
- UINT8 ubID;
- // Make sure we have a structure here....
- bRefuelItem = IsRefuelableStructAtGridNo( sGridNo, &ubID );
- if ( bRefuelItem )
- {
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- //BOOLEAN CutWireFence( INT16 sGridNo )
- // SET TARGET GRIDNO
- //pSoldier->sTargetGridNo = sGridNo;
- // CHANGE TO ANIMATION
- EVENT_InitNewSoldierAnim( pSoldier, REFUEL_VEHICLE, 0 , FALSE );
- // SET BUDDY'S ASSIGNMENT TO REPAIR...
- }
- }
- void EVENT_SoldierBeginTakeBlood( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- ROTTING_CORPSE *pCorpse;
- // See if these is a corpse here....
- pCorpse = GetCorpseAtGridNo( sGridNo , pSoldier->bLevel );
- if ( pCorpse != NULL )
- {
- pSoldier->uiPendingActionData4 = pCorpse->iID;
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- EVENT_InitNewSoldierAnim( pSoldier, TAKE_BLOOD_FROM_CORPSE, 0 , FALSE );
- }
- else
- {
- // Say NOTHING quote...
- DoMercBattleSound( pSoldier, BATTLE_SOUND_NOTHING );
- }
- }
- void EVENT_SoldierBeginAttachCan( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection )
- {
- STRUCTURE * pStructure;
- DOOR_STATUS * pDoorStatus;
- // OK, find door, attach to door, do animation...., remove item....
- // First make sure we still have item in hand....
- if ( pSoldier->inv[ HANDPOS ].usItem != STRING_TIED_TO_TIN_CAN )
- {
- return;
- }
- pStructure = FindStructure( sGridNo, STRUCTURE_ANYDOOR );
- if ( pStructure == NULL )
- {
- return;
- }
- // Modify door status to make sure one is created for this door
- // Use the current door state for this
- if ( !(pStructure->fFlags & STRUCTURE_OPEN) )
- {
- ModifyDoorStatus( sGridNo, FALSE, FALSE );
- }
- else
- {
- ModifyDoorStatus( sGridNo, TRUE, TRUE );
- }
- // Now get door status...
- pDoorStatus = GetDoorStatus( sGridNo );
- if ( pDoorStatus == NULL )
- {
- // SOmething wrong here...
- return;
- }
-
- // OK set flag!
- pDoorStatus->ubFlags |= DOOR_HAS_TIN_CAN;
- // Do animation
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- EVENT_InitNewSoldierAnim( pSoldier, ATTACH_CAN_TO_STRING, 0 , FALSE );
- // Remove item...
- DeleteObj( &(pSoldier->inv[ HANDPOS ] ) );
- fInterfacePanelDirty = DIRTYLEVEL2;
- }
- void EVENT_SoldierBeginReloadRobot( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubDirection, UINT8 ubMercSlot )
- {
- UINT8 ubPerson;
- // Make sure we have a robot here....
- ubPerson = WhoIsThere2( sGridNo, pSoldier->bLevel );
- if ( ubPerson != NOBODY && MercPtrs[ ubPerson ]->uiStatusFlags & SOLDIER_ROBOT )
- {
- // CHANGE DIRECTION AND GOTO ANIMATION NOW
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_SetSoldierDirection( pSoldier, ubDirection );
- // CHANGE TO ANIMATION
- EVENT_InitNewSoldierAnim( pSoldier, RELOAD_ROBOT, 0 , FALSE );
- }
- }
- void ResetSoldierChangeStatTimer( SOLDIERTYPE *pSoldier )
- {
- pSoldier->uiChangeLevelTime = 0;
- pSoldier->uiChangeHealthTime = 0;
- pSoldier->uiChangeStrengthTime= 0;
- pSoldier->uiChangeDexterityTime= 0;
- pSoldier->uiChangeAgilityTime= 0;
- pSoldier->uiChangeWisdomTime= 0;
- pSoldier->uiChangeLeadershipTime= 0;
- pSoldier->uiChangeMarksmanshipTime= 0;
- pSoldier->uiChangeExplosivesTime= 0;
- pSoldier->uiChangeMedicalTime= 0;
- pSoldier->uiChangeMechanicalTime= 0;
- return;
- }
- void ChangeToFlybackAnimation( SOLDIERTYPE *pSoldier, INT8 bDirection )
- {
- UINT16 usNewGridNo;
- // Get dest gridno, convert to center coords
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bDirection ] ) );
- usNewGridNo = NewGridNo( (UINT16)usNewGridNo, DirectionInc( gOppositeDirection[ bDirection ] ) );
- // Remove any previous actions
- pSoldier->ubPendingAction = NO_PENDING_ACTION;
- // Set path....
- pSoldier->usPathDataSize = 0;
- pSoldier->usPathIndex = 0;
- pSoldier->usPathingData[ pSoldier->usPathDataSize ] = gOppositeDirection[ pSoldier->bDirection ];
- pSoldier->usPathDataSize++;
- pSoldier->usPathingData[ pSoldier->usPathDataSize ] = gOppositeDirection[ pSoldier->bDirection ];
- pSoldier->usPathDataSize++;
- pSoldier->sFinalDestination = usNewGridNo;
- EVENT_InternalSetSoldierDestination( pSoldier, pSoldier->usPathingData[ pSoldier->usPathIndex ], FALSE, FLYBACK_HIT );
- // Get a new direction based on direction
- EVENT_InitNewSoldierAnim( pSoldier, FLYBACK_HIT, 0 , FALSE );
- }
- void ChangeToFallbackAnimation( SOLDIERTYPE *pSoldier, INT8 bDirection )
- {
- UINT16 usNewGridNo;
- // Get dest gridno, convert to center coords
- usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bDirection ] ) );
- //usNewGridNo = NewGridNo( (UINT16)usNewGridNo, (UINT16)(-1 * DirectionInc( bDirection ) ) );
- // Remove any previous actions
- pSoldier->ubPendingAction = NO_PENDING_ACTION;
- // Set path....
- pSoldier->usPathDataSize = 0;
- pSoldier->usPathIndex = 0;
- pSoldier->usPathingData[ pSoldier->usPathDataSize ] = gOppositeDirection[ pSoldier->bDirection ];
- pSoldier->usPathDataSize++;
- pSoldier->sFinalDestination = usNewGridNo;
- EVENT_InternalSetSoldierDestination( pSoldier, pSoldier->usPathingData[ pSoldier->usPathIndex ], FALSE, FALLBACK_HIT_STAND );
- // Get a new direction based on direction
- EVENT_InitNewSoldierAnim( pSoldier, FALLBACK_HIT_STAND, 0 , FALSE );
- }
- void SetSoldierCowerState( SOLDIERTYPE *pSoldier, BOOLEAN fOn )
- {
- // Robot's don't cower!
- if ( pSoldier->ubBodyType == ROBOTNOWEAPON )
- {
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("ERROR: Robot was told to cower!" ) );
- return;
- }
- // OK< set flag and do anim...
- if ( fOn )
- {
- if ( !( pSoldier->uiStatusFlags & SOLDIER_COWERING ) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, START_COWER, 0, FALSE );
-
- pSoldier->uiStatusFlags |= SOLDIER_COWERING;
- pSoldier->ubDesiredHeight = ANIM_CROUCH;
- }
- }
- else
- {
- if ( (pSoldier->uiStatusFlags & SOLDIER_COWERING) )
- {
- EVENT_InitNewSoldierAnim( pSoldier, END_COWER, 0, FALSE );
-
- pSoldier->uiStatusFlags &= (~SOLDIER_COWERING );
- pSoldier->ubDesiredHeight = ANIM_STAND;
- }
- }
- }
- void MercStealFromMerc( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTarget )
- {
- INT16 sActionGridNo, sGridNo, sAdjustedGridNo;
- UINT8 ubDirection;
- // OK, find an adjacent gridno....
- sGridNo = pTarget->sGridNo;
- // See if we can get there to punch
- sActionGridNo = FindAdjacentGridEx( pSoldier, sGridNo, &ubDirection, &sAdjustedGridNo, TRUE, FALSE );
- if ( sActionGridNo != -1 )
- {
- // SEND PENDING ACTION
- pSoldier->ubPendingAction = MERC_STEAL;
- pSoldier->sPendingActionData2 = pTarget->sGridNo;
- pSoldier->bPendingActionData3 = ubDirection;
- pSoldier->ubPendingActionAnimCount = 0;
- // CHECK IF WE ARE AT THIS GRIDNO NOW
- if ( pSoldier->sGridNo != sActionGridNo )
- {
- // WALK UP TO DEST FIRST
- SendGetNewSoldierPathEvent( pSoldier, sActionGridNo, pSoldier->usUIMovementMode );
- }
- else
- {
- EVENT_SetSoldierDesiredDirection( pSoldier, ubDirection );
- EVENT_InitNewSoldierAnim( pSoldier, STEAL_ITEM, 0 , FALSE );
- }
- // OK, set UI
- gTacticalStatus.ubAttackBusyCount++;
- // reset attacking item (hand)
- pSoldier->usAttackingWeapon = 0;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting STEAL attack, attack count now %d", gTacticalStatus.ubAttackBusyCount) );
- SetUIBusy( pSoldier->ubID );
- }
- }
- BOOLEAN PlayerSoldierStartTalking( SOLDIERTYPE *pSoldier, UINT8 ubTargetID, BOOLEAN fValidate )
- {
- INT16 sFacingDir, sXPos, sYPos, sAPCost;
- SOLDIERTYPE *pTSoldier;
- UINT32 uiRange;
- if ( ubTargetID == NOBODY )
- {
- return( FALSE );
- }
- pTSoldier = MercPtrs[ ubTargetID ];
- // Check distance again, to be sure
- if ( fValidate )
- {
- // OK, since we locked this guy from moving
- // we should be close enough, so talk ( unless he is now dead )
- if ( !IsValidTalkableNPC( (UINT8)ubTargetID, FALSE, FALSE, FALSE ) )
- {
- return( FALSE );
- }
- uiRange = GetRangeFromGridNoDiff( pSoldier->sGridNo, pTSoldier->sGridNo );
- if ( uiRange > ( NPC_TALK_RADIUS * 2 ) )
- {
- // Todo here - should we follow dude?
- return( FALSE );
- }
- }
- // Get APs...
- sAPCost = AP_TALK;
- // Deduct points from our guy....
- DeductPoints( pSoldier, sAPCost, 0 );
- ConvertGridNoToXY( pTSoldier->sGridNo, &sXPos, &sYPos );
- // Get direction from mouse pos
- sFacingDir = GetDirectionFromXY( sXPos, sYPos, pSoldier );
- // Set our guy facing
- SendSoldierSetDesiredDirectionEvent( pSoldier, sFacingDir );
- // Set NPC facing
- SendSoldierSetDesiredDirectionEvent( pTSoldier, gOppositeDirection[ sFacingDir ] );
-
- // Stop our guys...
- EVENT_StopMerc( pSoldier, pSoldier->sGridNo, pSoldier->bDirection );
- // ATE; Check for normal civs...
- if ( GetCivType( pTSoldier ) != CIV_TYPE_NA )
- {
- StartCivQuote( pTSoldier );
- return( FALSE );
- }
- // Are we an EPC that is being escorted?
- if ( pTSoldier->ubProfile != NO_PROFILE && pTSoldier->ubWhatKindOfMercAmI == MERC_TYPE__EPC )
- {
- return( InitiateConversation( pTSoldier, pSoldier, APPROACH_EPC_WHO_IS_RECRUITED, 0 ) );
- //Converse( pTSoldier->ubProfile, pSoldier->ubProfile, APPROACH_EPC_WHO_IS_RECRUITED, 0 );
- }
- else if (pTSoldier->bNeutral)
- {
- switch( pTSoldier->ubProfile )
- {
- case JIM:
- case JACK:
- case OLAF:
- case RAY:
- case OLGA:
- case TYRONE:
- // Start combat etc
- DeleteTalkingMenu();
- CancelAIAction( pTSoldier, TRUE );
- AddToShouldBecomeHostileOrSayQuoteList( pTSoldier->ubID );
- break;
- default:
- // Start talking!
- return( InitiateConversation( pTSoldier, pSoldier, NPC_INITIAL_QUOTE, 0 ) );
- break;
- }
- }
- else
- {
- // Start talking with hostile NPC
- return( InitiateConversation( pTSoldier, pSoldier, APPROACH_ENEMY_NPC_QUOTE, 0 ) );
- }
- return( TRUE );
- }
- BOOLEAN IsValidSecondHandShot( SOLDIERTYPE *pSoldier )
- {
- if ( Item[ pSoldier->inv[ SECONDHANDPOS ].usItem ].usItemClass == IC_GUN &&
- !(Item[ pSoldier->inv[SECONDHANDPOS ].usItem ].fFlags & ITEM_TWO_HANDED) &&
- !pSoldier->bDoBurst &&
- pSoldier->inv[ HANDPOS ].usItem != GLAUNCHER &&
- Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass == IC_GUN &&
- pSoldier->inv[SECONDHANDPOS].bGunStatus >= USABLE &&
- pSoldier->inv[SECONDHANDPOS].ubGunShotsLeft > 0 )
- {
- return( TRUE );
- }
- return( FALSE );
- }
- BOOLEAN IsValidSecondHandShotForReloadingPurposes( SOLDIERTYPE *pSoldier )
- {
- // should be maintained as same as function above with line
- // about ammo taken out!
- if ( Item[ pSoldier->inv[ SECONDHANDPOS ].usItem ].usItemClass == IC_GUN &&
- !pSoldier->bDoBurst &&
- pSoldier->inv[ HANDPOS ].usItem != GLAUNCHER &&
- Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass == IC_GUN &&
- pSoldier->inv[SECONDHANDPOS].bGunStatus >= USABLE //&&
- // pSoldier->inv[SECONDHANDPOS].ubGunShotsLeft > 0 &&
- // gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE )
- )
- {
- return( TRUE );
- }
- return( FALSE );
- }
- BOOLEAN CanRobotBeControlled( SOLDIERTYPE *pSoldier )
- {
- SOLDIERTYPE *pController;
-
- if ( !( pSoldier->uiStatusFlags & SOLDIER_ROBOT ) )
- {
- return( FALSE );
- }
- if ( pSoldier->ubRobotRemoteHolderID == NOBODY )
- {
- return( FALSE );
- }
- pController = MercPtrs[ pSoldier->ubRobotRemoteHolderID ];
- if ( pController->bActive )
- {
- if ( ControllingRobot( pController ) )
- {
- // ALL'S OK!
- return( TRUE );
- }
- }
- return( FALSE );
- }
- BOOLEAN ControllingRobot( SOLDIERTYPE *pSoldier )
- {
- SOLDIERTYPE *pRobot;
- INT8 bPos;
- if ( !pSoldier->bActive )
- {
- return( FALSE );
- }
- // EPCs can't control the robot (no inventory to hold remote, for one)
- if ( AM_AN_EPC( pSoldier ) )
- {
- return( FALSE );
- }
- // Don't require pSoldier->bInSector here, it must work from mapscreen!
- // are we in ok shape?
- if ( pSoldier->bLife < OKLIFE || ( pSoldier->bTeam != gbPlayerNum ) )
- {
- return( FALSE );
- }
- // allow control from within vehicles - allows strategic travel in a vehicle with robot!
- if ( ( pSoldier->bAssignment >= ON_DUTY ) && ( pSoldier->bAssignment != VEHICLE ) )
- {
- return( FALSE );
- }
- // is the soldier wearing a robot remote control?
- bPos = FindObj( pSoldier, ROBOT_REMOTE_CONTROL );
- if ( bPos != HEAD1POS && bPos != HEAD2POS )
- {
- return( FALSE );
- }
- // Find the robot
- pRobot = FindSoldierByProfileID( ROBOT, TRUE );
- if ( !pRobot )
- {
- return( FALSE );
- }
- if ( pRobot->bActive )
- {
- // Are we in the same sector....?
- // ARM: CHANGED TO WORK IN MAPSCREEN, DON'T USE WorldSector HERE
- if ( pRobot->sSectorX == pSoldier->sSectorX &&
- pRobot->sSectorY == pSoldier->sSectorY &&
- pRobot->bSectorZ == pSoldier->bSectorZ )
- {
- // they have to be either both in sector, or both on the road
- if ( pRobot->fBetweenSectors == pSoldier->fBetweenSectors )
- {
- // if they're on the road...
- if ( pRobot->fBetweenSectors )
- {
- // they have to be in the same squad or vehicle
- if ( pRobot->bAssignment != pSoldier->bAssignment )
- {
- return( FALSE );
- }
- // if in a vehicle, must be the same vehicle
- if ( pRobot->bAssignment == VEHICLE && ( pRobot->iVehicleId != pSoldier->iVehicleId ) )
- {
- return( FALSE );
- }
- }
- // all OK!
- return( TRUE );
- }
- }
- }
- return( FALSE );
- }
- SOLDIERTYPE *GetRobotController( SOLDIERTYPE *pSoldier )
- {
- if ( pSoldier->ubRobotRemoteHolderID == NOBODY )
- {
- return( NULL );
- }
- else
- {
- return( MercPtrs[ pSoldier->ubRobotRemoteHolderID ] );
- }
- }
- void UpdateRobotControllerGivenRobot( SOLDIERTYPE *pRobot )
- {
- SOLDIERTYPE *pTeamSoldier;
- INT32 cnt = 0;
- // Loop through guys and look for a controller!
- // set up soldier ptr as first element in mercptrs list
- cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
- // run through list
- for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++, pTeamSoldier++)
- {
- if ( pTeamSoldier->bActive )
- {
- if ( ControllingRobot( pTeamSoldier ) )
- {
- pRobot->ubRobotRemoteHolderID = pTeamSoldier->ubID;
- return;
- }
- }
- }
- pRobot->ubRobotRemoteHolderID = NOBODY;
- }
- void UpdateRobotControllerGivenController( SOLDIERTYPE *pSoldier )
- {
- SOLDIERTYPE *pTeamSoldier;
- INT32 cnt = 0;
- // First see if are still controlling the robot
- if ( !ControllingRobot( pSoldier ) )
- {
- return;
- }
-
- // set up soldier ptr as first element in mercptrs list
- cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
- // Loop through guys to find the robot....
- for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++, pTeamSoldier++)
- {
- if ( pTeamSoldier->bActive && ( pTeamSoldier->uiStatusFlags & SOLDIER_ROBOT ) )
- {
- pTeamSoldier->ubRobotRemoteHolderID = pSoldier->ubID;
- }
- }
- }
- void HandleSoldierTakeDamageFeedback( SOLDIERTYPE *pSoldier )
- {
- // Do sound.....
- // if ( pSoldier->bLife >= CONSCIOUSNESS )
- {
- // ATE: Limit how often we grunt...
- if ( ( GetJA2Clock( ) - pSoldier->uiTimeSinceLastBleedGrunt ) > 1000 )
- {
- pSoldier->uiTimeSinceLastBleedGrunt = GetJA2Clock( );
- DoMercBattleSound( pSoldier, (INT8)( BATTLE_SOUND_HIT1 + Random( 2 ) ) );
- }
- }
- // Flash portrait....
- pSoldier->fFlashPortrait = TRUE;
- pSoldier->bFlashPortraitFrame = FLASH_PORTRAIT_STARTSHADE;
- RESETTIMECOUNTER( pSoldier->PortraitFlashCounter, FLASH_PORTRAIT_DELAY );
- }
- void HandleSystemNewAISituation( SOLDIERTYPE *pSoldier, BOOLEAN fResetABC )
- {
- // Are we an AI guy?
- if ( gTacticalStatus.ubCurrentTeam != gbPlayerNum && pSoldier->bTeam != gbPlayerNum )
- {
- if ( pSoldier->bNewSituation == IS_NEW_SITUATION )
- {
- // Cancel what they were doing....
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
- pSoldier->fTurningFromPronePosition = FALSE;
- pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
- pSoldier->ubPendingAction = NO_PENDING_ACTION;
- pSoldier->bEndDoorOpenCode = 0;
- // if this guy isn't under direct AI control, WHO GIVES A FLYING FLICK?
- if ( pSoldier->uiStatusFlags & SOLDIER_UNDERAICONTROL )
- {
- if ( pSoldier->fTurningToShoot )
- {
- pSoldier->fTurningToShoot = FALSE;
- // Release attacker
- // OK - this is hightly annoying , but due to the huge combinations of
- // things that can happen - 1 of them is that sLastTarget will get unset
- // after turn is done - so set flag here to tell it not to...
- pSoldier->fDontUnsetLastTargetFromTurn = TRUE;
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., ending fire because saw something: DONE IN SYSTEM NEW SITUATION") );
- ReduceAttackBusyCount( pSoldier->ubID, FALSE );
- }
- if ( pSoldier->pTempObject != NULL )
- {
- // Place it back into inv....
- AutoPlaceObject( pSoldier, pSoldier->pTempObject, FALSE );
- MemFree( pSoldier->pTempObject );
- pSoldier->pTempObject = NULL;
- pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
- pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
- // Decrement attack counter...
- DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., ending throw because saw something: DONE IN SYSTEM NEW SITUATION") );
- ReduceAttackBusyCount( pSoldier->ubID, FALSE );
- }
- }
- }
- }
- }
- void InternalPlaySoldierFootstepSound( SOLDIERTYPE * pSoldier )
- {
- UINT8 ubRandomSnd;
- INT8 bVolume = MIDVOLUME;
- // Assume outside
- UINT32 ubSoundBase = WALK_LEFT_OUT;
- UINT8 ubRandomMax = 4;
- // Determine if we are on the floor
- if ( !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
- {
- if ( pSoldier->usAnimState == HOPFENCE )
- {
- bVolume = HIGHVOLUME;
- }
- if ( pSoldier->uiStatusFlags & SOLDIER_ROBOT )
- {
- PlaySoldierJA2Sample( pSoldier->ubID, ROBOT_BEEP, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
- return;
- }
- //if ( SoldierOnScreen( pSoldier->ubID ) )
- {
- if ( pSoldier->usAnimState == CRAWLING )
- {
- ubSoundBase = CRAWL_1;
- }
- else
- {
- // Pick base based on terrain over....
- if ( pSoldier->bOverTerrainType == FLAT_FLOOR )
- {
- ubSoundBase = WALK_LEFT_IN;
- }
- else if ( pSoldier->bOverTerrainType == DIRT_ROAD || pSoldier->bOverTerrainType == PAVED_ROAD )
- {
- ubSoundBase = WALK_LEFT_ROAD;
- }
- else if ( pSoldier->bOverTerrainType == LOW_WATER || pSoldier->bOverTerrainType == MED_WATER )
- {
- ubSoundBase = WATER_WALK1_IN;
- ubRandomMax = 2;
- }
- else if ( pSoldier->bOverTerrainType == DEEP_WATER )
- {
- ubSoundBase = SWIM_1;
- ubRandomMax = 2;
- }
- }
- // Pick a random sound...
- do
- {
- ubRandomSnd = (UINT8)Random( ubRandomMax );
- } while ( ubRandomSnd == pSoldier->ubLastFootPrintSound );
- pSoldier->ubLastFootPrintSound = ubRandomSnd;
- // OK, if in realtime, don't play at full volume, because too many people walking around
- // sounds don't sound good - ( unless we are the selected guy, then always play at reg volume )
- if ( ! ( gTacticalStatus.uiFlags & INCOMBAT ) && ( pSoldier->ubID != gusSelectedSoldier ) )
- {
- bVolume = LOWVOLUME;
- }
- PlaySoldierJA2Sample( pSoldier->ubID, ubSoundBase + pSoldier->ubLastFootPrintSound, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
- }
- }
- }
- void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier )
- {
- // normally, not in stealth mode
- if ( !pSoldier->bStealthMode )
- {
- InternalPlaySoldierFootstepSound( pSoldier );
- }
- }
- void PlayStealthySoldierFootstepSound( SOLDIERTYPE *pSoldier )
- {
- // even if in stealth mode
- InternalPlaySoldierFootstepSound( pSoldier );
- }
- void CrowsFlyAway( UINT8 ubTeam )
- {
- UINT32 cnt;
- SOLDIERTYPE *pTeamSoldier;
- for ( cnt = gTacticalStatus.Team[ ubTeam ].bFirstID, pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ ubTeam ].bLastID; cnt++, pTeamSoldier++ )
- {
- if ( pTeamSoldier->bActive && pTeamSoldier->bInSector )
- {
- if ( pTeamSoldier->ubBodyType == CROW && pTeamSoldier->usAnimState != CROW_FLY )
- {
- // fly away even if not seen!
- HandleCrowFlyAway( pTeamSoldier );
- }
- }
- }
- }
- #ifdef JA2BETAVERSION
- void DebugValidateSoldierData( )
- {
- UINT32 cnt;
- SOLDIERTYPE *pSoldier;
- CHAR16 sString[ 1024 ];
- BOOLEAN fProblemDetected = FALSE;
- static uiFrameCount = 0;
- // this function is too slow to run every frame, so do the check only every 50 frames
- if ( uiFrameCount++ < 50 )
- {
- return;
- }
- // reset frame counter
- uiFrameCount = 0;
- // Loop through our team...
- cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
- for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pSoldier++)
- {
- if ( pSoldier->bActive )
- {
- // OK, first check for alive people
- // Don't do this check if we are a vehicle...
- if ( pSoldier->bLife > 0 && !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
- {
- // Alive -- now check for proper group IDs
- if ( pSoldier->ubGroupID == 0 && pSoldier->bAssignment != IN_TRANSIT && pSoldier->bAssignment != ASSIGNMENT_POW && !( pSoldier->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
- {
- // This is bad!
- swprintf( sString, L"Soldier Data Error: Soldier %d is alive but has a zero group ID.", cnt );
- fProblemDetected = TRUE;
- }
- else if ( ( pSoldier->ubGroupID != 0 ) && ( GetGroup( pSoldier->ubGroupID ) == NULL ) )
- {
- // This is bad!
- swprintf( sString, L"Soldier Data Error: Soldier %d has an invalid group ID of %d.", cnt, pSoldier->ubGroupID );
- fProblemDetected = TRUE;
- }
- }
- else
- {
- if ( pSoldier->ubGroupID != 0 && ( pSoldier->uiStatusFlags & SOLDIER_DEAD ) )
- {
- // Dead guys should have 0 group IDs
- //swprintf( sString, L"GroupID Error: Soldier %d is dead but has a non-zero group ID.", cnt );
- //fProblemDetected = TRUE;
- }
- }
- // check for invalid sector data
- if ( ( pSoldier->bAssignment != IN_TRANSIT ) &&
- ( ( pSoldier->sSectorX <= 0 ) || ( pSoldier->sSectorX >= 17 ) ||
- ( pSoldier->sSectorY <= 0 ) || ( pSoldier->sSectorY >= 17 ) ||
- ( pSoldier->bSectorZ < 0 ) || ( pSoldier->bSectorZ > 3 ) ) )
- {
- swprintf( sString, L"Soldier Data Error: Soldier %d is located at %d/%d/%d.", cnt, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
- fProblemDetected = TRUE;
- }
- }
- if ( fProblemDetected )
- {
- SAIReportError( sString );
- /*
- if ( guiCurrentScreen == MAP_SCREEN )
- DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, MSG_BOX_FLAG_OK, MapScreenDefaultOkBoxCallback );
- else
- DoMessageBox( MSG_BOX_BASIC_STYLE, sString, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_OK, NULL, NULL );
- */
- break;
- }
- }
- // also do this
- ValidatePlayersAreInOneGroupOnly();
- }
- #endif
- void BeginTyingToFall( SOLDIERTYPE *pSoldier )
- {
- pSoldier->bStartFallDir = pSoldier->bDirection;
- pSoldier->fTryingToFall = TRUE;
- // Randomize direction
- if ( Random( 50 ) < 25 )
- {
- pSoldier->fFallClockwise = TRUE;
- }
- else
- {
- pSoldier->fFallClockwise = FALSE;
- }
- }
- void SetSoldierAsUnderAiControl( SOLDIERTYPE *pSoldierToSet )
- {
- SOLDIERTYPE *pSoldier=NULL;
- INT32 cnt;
- if ( pSoldierToSet == NULL )
- {
- return;
- }
- // Loop through ALL teams...
- cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID;
- for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ LAST_TEAM ].bLastID; cnt++,pSoldier++)
- {
- if( pSoldier->bActive )
- {
- pSoldier->uiStatusFlags &= ~SOLDIER_UNDERAICONTROL;
- }
- }
- pSoldierToSet->uiStatusFlags |= SOLDIER_UNDERAICONTROL;
- }
- void HandlePlayerTogglingLightEffects( BOOLEAN fToggleValue )
- {
- if( fToggleValue )
- {
- //Toggle light status
- gGameSettings.fOptions[ TOPTION_MERC_CASTS_LIGHT ] ^= TRUE;
- }
- //Update all the mercs in the sector
- EnableDisableSoldierLightEffects( gGameSettings.fOptions[ TOPTION_MERC_CASTS_LIGHT ] );
- SetRenderFlags(RENDER_FLAG_FULL);
- }
- void EnableDisableSoldierLightEffects( BOOLEAN fEnableLights )
- {
- SOLDIERTYPE *pSoldier=NULL;
- INT32 cnt;
- // Loop through player teams...
- cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID;
- for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pSoldier++)
- {
- //if the soldier is in the sector
- if( pSoldier->bActive && pSoldier->bInSector && pSoldier->bLife >= OKLIFE )
- {
- //if we are to enable the lights
- if( fEnableLights )
- {
- //Add the light around the merc
- PositionSoldierLight( pSoldier );
- }
- else
- {
- //Delete the fake light the merc casts
- DeleteSoldierLight( pSoldier );
- //Light up the merc though
- SetSoldierPersonalLightLevel( pSoldier );
- }
- }
- }
- }
- void SetSoldierPersonalLightLevel( SOLDIERTYPE *pSoldier )
- {
- if( pSoldier == NULL )
- {
- return;
- }
- if( pSoldier->sGridNo == NOWHERE )
- {
- return;
- }
- //THe light level for the soldier
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubShadeLevel = 3;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubSumLights = 5;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubMaxLights = 5;
- gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubNaturalShadeLevel = 5;
- }
|