AIStates.cpp 252 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // AIStates.cpp
  24. // Implementation of AI behavior states
  25. // Author: Michael S. Booth, January 2002
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/ActionManager.h"
  28. #include "Common/AudioHandleSpecialValues.h"
  29. #include "Common/CRCDebug.h"
  30. #include "Common/GameAudio.h"
  31. #include "Common/GlobalData.h"
  32. #include "Common/Money.h"
  33. #include "Common/PerfTimer.h"
  34. #include "Common/Player.h"
  35. #include "Common/PlayerList.h"
  36. #include "Common/RandomValue.h"
  37. #include "Common/Team.h"
  38. #include "Common/ThingTemplate.h"
  39. #include "Common/ThingFactory.h"
  40. #include "Common/Xfer.h"
  41. #include "Common/XFerCRC.h"
  42. #include "GameClient/ControlBar.h"
  43. #include "GameClient/FXList.h"
  44. #include "GameClient/InGameUI.h"
  45. #include "GameLogic/AIDock.h"
  46. #include "GameLogic/AIGuard.h"
  47. #include "GameLogic/AIGuardRetaliate.h"
  48. #include "GameLogic/AITNGuard.h"
  49. #include "GameLogic/AIStateMachine.h"
  50. #include "GameLogic/AIPathfind.h"
  51. #include "GameLogic/Locomotor.h"
  52. #include "GameLogic/PartitionManager.h"
  53. #include "GameLogic/PolygonTrigger.h"
  54. #include "GameLogic/ScriptEngine.h"
  55. #include "GameLogic/Squad.h"
  56. #include "GameLogic/TurretAI.h"
  57. #include "GameLogic/Weapon.h"
  58. #include "GameLogic/Module/AIUpdate.h"
  59. #include "GameLogic/Module/BodyModule.h"
  60. #include "GameLogic/Module/ContainModule.h"
  61. #include "GameLogic/Module/JetAIUpdate.h"
  62. #include "GameLogic/Module/PhysicsUpdate.h"
  63. #include "GameLogic/Module/StealthUpdate.h"
  64. #ifdef _INTERNAL
  65. // for occasional debugging...
  66. //#pragma optimize("", off)
  67. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  68. #endif
  69. static Bool cannotPossiblyAttackObject( State *thisState, void* userData );
  70. //----------------------------------------------------------------------------------------------------------
  71. AICommandParms::AICommandParms(AICommandType cmd, CommandSourceType cmdSource) :
  72. m_cmd(cmd),
  73. m_cmdSource(cmdSource),
  74. m_obj(NULL),
  75. m_otherObj(NULL),
  76. m_team(NULL),
  77. m_waypoint(NULL),
  78. m_polygon(NULL),
  79. m_intValue(0),
  80. m_commandButton(NULL),
  81. m_path(NULL)
  82. {
  83. m_pos.zero();
  84. m_coords.clear();
  85. }
  86. //----------------------------------------------------------------------------------------------------------
  87. void AICommandParmsStorage::store(const AICommandParms& parms)
  88. {
  89. m_cmd = parms.m_cmd;
  90. m_cmdSource = parms.m_cmdSource;
  91. m_pos = parms.m_pos;
  92. m_obj = parms.m_obj ? parms.m_obj->getID() : INVALID_ID;
  93. m_otherObj = parms.m_otherObj ? parms.m_otherObj->getID() : INVALID_ID;
  94. m_teamName = parms.m_team ? parms.m_team->getName() : AsciiString::TheEmptyString;
  95. m_coords = parms.m_coords;
  96. m_waypoint = parms.m_waypoint;
  97. m_polygon = parms.m_polygon;
  98. m_intValue = parms.m_intValue; /// misc usage
  99. m_damage = parms.m_damage;
  100. m_commandButton = parms.m_commandButton;
  101. m_path = parms.m_path; /// @todo srj -- probably need a better way to safely save/restore this
  102. }
  103. //----------------------------------------------------------------------------------------------------------
  104. void AICommandParmsStorage::reconstitute(AICommandParms& parms) const
  105. {
  106. parms.m_cmd = m_cmd;
  107. parms.m_cmdSource = m_cmdSource;
  108. parms.m_pos = m_pos;
  109. parms.m_obj = TheGameLogic->findObjectByID(m_obj);
  110. parms.m_otherObj = TheGameLogic->findObjectByID(m_otherObj);
  111. parms.m_team = TheTeamFactory->findTeam(m_teamName);
  112. parms.m_coords = m_coords;
  113. parms.m_waypoint = m_waypoint;
  114. parms.m_polygon = m_polygon;
  115. parms.m_intValue = m_intValue;
  116. parms.m_damage = m_damage;
  117. parms.m_commandButton = m_commandButton;
  118. parms.m_path = m_path; /// @todo srj -- probably need a better way to safely save/restore this
  119. }
  120. //----------------------------------------------------------------------------------------------------------
  121. void AICommandParmsStorage::doXfer(Xfer *xfer)
  122. {
  123. xfer->xferUser(&m_cmd, sizeof(m_cmd));
  124. xfer->xferUser(&m_cmd, sizeof(m_cmdSource));
  125. xfer->xferCoord3D(&m_pos);
  126. xfer->xferObjectID(&m_obj);
  127. xfer->xferObjectID(&m_otherObj);
  128. xfer->xferAsciiString(&m_teamName);
  129. Int numCoords = m_coords.size();
  130. xfer->xferInt(&numCoords);
  131. Int i;
  132. if (xfer->getXferMode() == XFER_LOAD)
  133. {
  134. for (i=0; i<numCoords; i++) {
  135. Coord3D pos;
  136. xfer->xferCoord3D(&pos);
  137. m_coords.push_back(pos);
  138. }
  139. } else {
  140. for (i=0; i<numCoords; i++) {
  141. Coord3D pos = m_coords[i];
  142. xfer->xferCoord3D(&pos);
  143. }
  144. }
  145. UnsignedInt id = INVALID_WAYPOINT_ID;
  146. if (m_waypoint) {
  147. id = m_waypoint->getID();
  148. }
  149. xfer->xferUnsignedInt(&id);
  150. if (xfer->getXferMode() == XFER_LOAD && id!= INVALID_WAYPOINT_ID)
  151. {
  152. m_waypoint = TheTerrainLogic->getWaypointByID(id);
  153. }
  154. AsciiString triggerName;
  155. if (m_polygon) triggerName = m_polygon->getTriggerName();
  156. xfer->xferAsciiString(&triggerName);
  157. if (xfer->getXferMode() == XFER_LOAD)
  158. {
  159. if (triggerName.isNotEmpty()) {
  160. m_polygon = TheTerrainLogic->getTriggerAreaByName(triggerName);
  161. }
  162. }
  163. xfer->xferInt(&m_intValue);
  164. xfer->xferSnapshot(&m_damage);
  165. AsciiString cmdName;
  166. if (m_commandButton) {
  167. cmdName = m_commandButton->getName();
  168. }
  169. xfer->xferAsciiString(&cmdName);
  170. if (cmdName.isNotEmpty() && m_commandButton==NULL) {
  171. m_commandButton = TheControlBar->findCommandButton(cmdName);
  172. }
  173. Bool hasPath = m_path!=NULL;
  174. xfer->xferBool(&hasPath);
  175. if (hasPath && m_path==NULL) {
  176. m_path = newInstance(Path);
  177. }
  178. if (hasPath) {
  179. xfer->xferSnapshot(m_path);
  180. }
  181. }
  182. //----------------------------------------------------------------------------------------------------------
  183. /**
  184. * Compare two positions to see if they are logically equal
  185. * @todo Move this somewhere more useful (MSB)
  186. */
  187. static Bool isSamePosition( const Coord3D *ourPos, const Coord3D *prevTargetPos, const Coord3D *curTargetPos )
  188. {
  189. Coord3D diff;
  190. // for pathfinding purposes, only care about 2d pos. (srj)
  191. diff.x = curTargetPos->x - prevTargetPos->x;
  192. diff.y = curTargetPos->y - prevTargetPos->y;
  193. Coord3D toTarget;
  194. // for pathfinding purposes, only care about 2d pos. (srj)
  195. toTarget.x = curTargetPos->x - ourPos->x;
  196. toTarget.y = curTargetPos->y - ourPos->y;
  197. // Tolerance is (dist/10)squared.
  198. const Real TOLERANCE_FACTOR = 1.0f / (10.0f * 10.0f);
  199. Real toleranceSqr = (toTarget.x*toTarget.x+toTarget.y*toTarget.y) * TOLERANCE_FACTOR;
  200. if (diff.x * diff.x + diff.y * diff.y > toleranceSqr)
  201. return false;
  202. return true;
  203. }
  204. //----------------------------------------------------------------------------------------------------------
  205. //----------------------------------------------------------------------------------------------------------
  206. // ------------------------------------------------------------------------------------------------
  207. /** CRC */
  208. // ------------------------------------------------------------------------------------------------
  209. void AttackStateMachine::crc( Xfer *xfer )
  210. {
  211. StateMachine::crc(xfer);
  212. } // end crc
  213. // ------------------------------------------------------------------------------------------------
  214. /** Xfer Method */
  215. // ------------------------------------------------------------------------------------------------
  216. void AttackStateMachine::xfer( Xfer *xfer )
  217. {
  218. XferVersion cv = 1;
  219. XferVersion v = cv;
  220. xfer->xferVersion( &v, cv );
  221. StateMachine::xfer(xfer);
  222. } // end xfer
  223. // ------------------------------------------------------------------------------------------------
  224. /** Load post process */
  225. // ------------------------------------------------------------------------------------------------
  226. void AttackStateMachine::loadPostProcess( void )
  227. {
  228. StateMachine::loadPostProcess();
  229. } // end loadPostProcess
  230. //----------------------------------------------------------------------------------------------------------
  231. static Bool inWeaponRangeObject(State *thisState, void* userData);
  232. //----------------------------------------------------------------------------------------------------------
  233. /**
  234. * Create an AI state machine. Define all of the states the machine
  235. * can possibly be in, and set the initial (default) state.
  236. */
  237. AttackStateMachine::AttackStateMachine( Object *obj, AIAttackState* att, AsciiString name, Bool follow, Bool attackingObject, Bool forceAttacking )
  238. : StateMachine( obj, name )
  239. {
  240. // we want to use the CONTINUE mode (not NEW) since we already have acquired the target.
  241. static const StateConditionInfo objectConditionsNormal[] =
  242. {
  243. StateConditionInfo(outOfWeaponRangeObject, AttackStateMachine::CHASE_TARGET, NULL),
  244. StateConditionInfo(wantToSquishTarget, AttackStateMachine::CHASE_TARGET, NULL),
  245. StateConditionInfo(cannotPossiblyAttackObject, EXIT_MACHINE_WITH_FAILURE, (void*)ATTACK_CONTINUED_TARGET),
  246. StateConditionInfo(NULL, NULL, NULL) // keep last
  247. };
  248. // we want to use the CONTINUE mode (not NEW) since we already have acquired the target.
  249. static const StateConditionInfo objectConditionsForced[] =
  250. {
  251. StateConditionInfo(outOfWeaponRangeObject, AttackStateMachine::CHASE_TARGET, NULL),
  252. StateConditionInfo(cannotPossiblyAttackObject, EXIT_MACHINE_WITH_FAILURE, (void*)ATTACK_CONTINUED_TARGET_FORCED),
  253. StateConditionInfo(wantToSquishTarget, AttackStateMachine::CHASE_TARGET, NULL),
  254. StateConditionInfo(NULL, NULL, NULL) // keep last
  255. };
  256. const StateConditionInfo* objectConditions = forceAttacking ? objectConditionsForced : objectConditionsNormal;
  257. static const StateConditionInfo positionConditions[] =
  258. {
  259. StateConditionInfo(outOfWeaponRangePosition, AttackStateMachine::CHASE_TARGET, NULL),
  260. StateConditionInfo(NULL, NULL, NULL) // keep last
  261. };
  262. #ifdef STATE_MACHINE_DEBUG
  263. AsciiString fullName = name;
  264. if (follow) fullName.concat(" follow");
  265. if (attackingObject) fullName.concat(" object");
  266. setName(fullName);
  267. //setDebugOutput(true);
  268. #endif
  269. // order matters: first state is the default state.
  270. // The default is Aim rather than Approach so things that cannot move will be able to shoot
  271. // things that are in range. Things that cannot move will automatically FAILURE on approach state.
  272. /*
  273. This state will succeed when we are aiming a useful weapon at the victim, and fail
  274. if the victim is dead. (Exception: if the weapon is on a turret, we don't leave this
  275. state unless we get out of range.)
  276. */
  277. defineState( AttackStateMachine::AIM_AT_TARGET,
  278. newInstance(AIAttackAimAtTargetState)( this, attackingObject, forceAttacking ),
  279. AttackStateMachine::FIRE_WEAPON,
  280. EXIT_MACHINE_WITH_FAILURE,
  281. attackingObject ? objectConditions : positionConditions );
  282. /*
  283. Note that the fire state succeeds iff it is able to fire... it will "fail"
  284. if unable to fire. However, it may be unable to fire because the target object
  285. is already dead.
  286. */
  287. defineState( AttackStateMachine::FIRE_WEAPON,
  288. newInstance(AIAttackFireWeaponState)( this, att ),
  289. AttackStateMachine::AIM_AT_TARGET,
  290. AttackStateMachine::AIM_AT_TARGET,
  291. attackingObject ? objectConditions : positionConditions );
  292. if (obj->isKindOf(KINDOF_IMMOBILE) == FALSE)
  293. {
  294. if (obj->isKindOf(KINDOF_PORTABLE_STRUCTURE) && obj->isKindOf(KINDOF_CAN_ATTACK))
  295. {
  296. static const StateConditionInfo portableStructureChaseConditions[] =
  297. {
  298. StateConditionInfo(inWeaponRangeObject, AttackStateMachine::AIM_AT_TARGET, NULL),
  299. StateConditionInfo(NULL, NULL, NULL) // keep last
  300. };
  301. /* we're a rider on a mobile object, so we can't control our motion.
  302. just make bogus states that always fall back into "aim".
  303. */
  304. defineState( AttackStateMachine::CHASE_TARGET,
  305. newInstance(ContinueState)(this),
  306. EXIT_MACHINE_WITH_FAILURE,
  307. EXIT_MACHINE_WITH_FAILURE,
  308. portableStructureChaseConditions );
  309. }
  310. else if (attackingObject)
  311. {
  312. /*
  313. This state will pursue a target that is moving away from it. If it is not moving away,
  314. it will drop into the AIAttackApproachTarget state.
  315. */
  316. defineState( AttackStateMachine::CHASE_TARGET,
  317. newInstance(AIAttackPursueTargetState)( this, follow, attackingObject, forceAttacking ),
  318. AttackStateMachine::APPROACH_TARGET,
  319. AttackStateMachine::APPROACH_TARGET );
  320. /*
  321. This state will succeed when we have a useful weapon within range of victim, and fail
  322. if the victim is dead
  323. */
  324. defineState( AttackStateMachine::APPROACH_TARGET,
  325. newInstance(AIAttackApproachTargetState)( this, follow, attackingObject, forceAttacking ),
  326. AttackStateMachine::AIM_AT_TARGET,
  327. EXIT_MACHINE_WITH_FAILURE );
  328. }
  329. else
  330. {
  331. /*
  332. This state will succeed when we have a useful weapon within range of victim, and fail
  333. if the victim is dead
  334. */
  335. defineState( AttackStateMachine::CHASE_TARGET,
  336. newInstance(AIAttackApproachTargetState)( this, follow, attackingObject, forceAttacking ),
  337. AttackStateMachine::AIM_AT_TARGET,
  338. EXIT_MACHINE_WITH_FAILURE );
  339. /*
  340. This state will succeed when we have a useful weapon within range of victim, and fail
  341. if the victim is dead
  342. */
  343. defineState( AttackStateMachine::APPROACH_TARGET,
  344. newInstance(AIAttackApproachTargetState)( this, follow, attackingObject, forceAttacking ),
  345. AttackStateMachine::AIM_AT_TARGET,
  346. EXIT_MACHINE_WITH_FAILURE );
  347. }
  348. }
  349. else
  350. {
  351. /*
  352. This state always instantly fails, so when immobile things transition here, we bail.
  353. */
  354. defineState( AttackStateMachine::CHASE_TARGET,
  355. newInstance(FailureState)(this),
  356. EXIT_MACHINE_WITH_FAILURE,
  357. EXIT_MACHINE_WITH_FAILURE );
  358. }
  359. };
  360. //----------------------------------------------------------------------------------------------------------
  361. AttackStateMachine::~AttackStateMachine()
  362. {
  363. }
  364. //-----------------------------------------------------------------------------------------------------------
  365. //-----------------------------------------------------------------------------------------------------------
  366. //-----------------------------------------------------------------------------------------------------------
  367. static Object* findEnemyInContainer(Object* killer, Object* bldg)
  368. {
  369. const ContainedItemsList* items = bldg->getContain() ? bldg->getContain()->getContainedItemsList() : NULL;
  370. if (items)
  371. {
  372. for (ContainedItemsList::const_iterator it = items->begin(); it != items->end(); ++it )
  373. {
  374. if ((*it)->isEffectivelyDead())
  375. {
  376. DEBUG_CRASH(("why is there a dead thing in this container?"));
  377. continue;
  378. }
  379. // order matters: we want to know if I consider it to be an enemy, not vice versa
  380. if (killer->getRelationship(*it) == ENEMIES)
  381. {
  382. return *it;
  383. }
  384. }
  385. }
  386. return NULL;
  387. }
  388. //-----------------------------------------------------------------------------------------------------------
  389. static Int killEnemiesInContainer(Object* killer, Object* bldg, Int maxToKill)
  390. {
  391. Int numKilled = 0;
  392. while (numKilled < maxToKill)
  393. {
  394. Object* enemy = findEnemyInContainer(killer, bldg);
  395. if (enemy)
  396. {
  397. Object *containedByObject = enemy->getContainedBy();
  398. if( containedByObject )
  399. {
  400. ContainModuleInterface *contain = containedByObject->getContain();
  401. if( contain )
  402. {
  403. contain->removeFromContain(enemy);
  404. }
  405. }
  406. if (killer)
  407. killer->scoreTheKill( enemy );
  408. enemy->kill();
  409. ++numKilled;
  410. }
  411. else
  412. {
  413. break;
  414. }
  415. }
  416. return numKilled;
  417. }
  418. //-----------------------------------------------------------------------------------------------------------
  419. //-----------------------------------------------------------------------------------------------------------
  420. AIRappelState::AIRappelState( StateMachine *machine ) : State( machine, "AIRappelState" )
  421. {
  422. }
  423. //-----------------------------------------------------------------------------------------------------------
  424. // ------------------------------------------------------------------------------------------------
  425. /** CRC */
  426. // ------------------------------------------------------------------------------------------------
  427. void AIRappelState::crc( Xfer *xfer )
  428. {
  429. } // end crc
  430. // ------------------------------------------------------------------------------------------------
  431. /** Xfer Method */
  432. // ------------------------------------------------------------------------------------------------
  433. void AIRappelState::xfer( Xfer *xfer )
  434. {
  435. // version
  436. XferVersion currentVersion = 1;
  437. XferVersion version = currentVersion;
  438. xfer->xferVersion( &version, currentVersion );
  439. xfer->xferReal(&m_rappelRate);
  440. xfer->xferReal(&m_destZ);
  441. xfer->xferBool(&m_targetIsBldg);
  442. } // end xfer
  443. // ------------------------------------------------------------------------------------------------
  444. /** Load post process */
  445. // ------------------------------------------------------------------------------------------------
  446. void AIRappelState::loadPostProcess( void )
  447. {
  448. } // end loadPostProcess
  449. //-----------------------------------------------------------------------------------------------------------
  450. StateReturnType AIRappelState::onEnter()
  451. {
  452. Object* obj = getMachineOwner();
  453. if (!obj->isKindOf(KINDOF_CAN_RAPPEL))
  454. return STATE_FAILURE;
  455. //AIUpdateInterface* ai = obj->getAI();
  456. obj->setModelConditionState(MODELCONDITION_RAPPELLING);
  457. // don't do this, or we'll be unable to be forced out of this state.
  458. // instead, just manipulate physics directly.
  459. //obj->setHeld();
  460. obj->getPhysics()->resetDynamicPhysics();
  461. m_targetIsBldg = true;
  462. Object* bldg = getMachineGoalObject();
  463. if (bldg == NULL || bldg->isEffectivelyDead() || !bldg->isKindOf(KINDOF_STRUCTURE))
  464. m_targetIsBldg = false;
  465. const Coord3D* pos = obj->getPosition();
  466. const Bool onlyHealthyBridges = true; // ignore dead bridges.
  467. PathfindLayerEnum layerAtDest = TheTerrainLogic->getHighestLayerForDestination(pos, onlyHealthyBridges);
  468. m_destZ = TheTerrainLogic->getLayerHeight(pos->x, pos->y, layerAtDest);
  469. if (m_targetIsBldg)
  470. m_destZ += bldg->getGeometryInfo().getMaxHeightAbovePosition();
  471. else
  472. obj->setLayer(layerAtDest);
  473. AIUpdateInterface *ai = obj->getAI();
  474. Real MAX_RAPPEL_RATE = fabs(TheGlobalData->m_gravity) * LOGICFRAMES_PER_SECOND * 2.5f;
  475. m_rappelRate = -min(ai->getDesiredSpeed(), MAX_RAPPEL_RATE);
  476. return STATE_CONTINUE;
  477. }
  478. //-----------------------------------------------------------------------------------------------------------
  479. StateReturnType AIRappelState::update()
  480. {
  481. StateReturnType result = STATE_CONTINUE;
  482. Object* obj = getMachineOwner();
  483. const Coord3D* pos = obj->getPosition();
  484. Object* bldg = getMachineGoalObject();
  485. if (m_targetIsBldg && (bldg == NULL || bldg->isEffectivelyDead()))
  486. {
  487. // if bldg is destroyed, just head for the ground
  488. // BGC - bldg could be destroyed as they are heading down the rope.
  489. m_targetIsBldg = false;
  490. m_destZ = TheTerrainLogic->getGroundHeight(pos->x, pos->y);
  491. }
  492. // nuke 2d speed...
  493. obj->getPhysics()->scrubVelocity2D(0);
  494. // and clamp z speed to rappel rate (gravity will have accelerated us)
  495. obj->getPhysics()->scrubVelocityZ(m_rappelRate);
  496. if (!m_targetIsBldg)
  497. {
  498. // if heading for ground, do this every frame... since jitter at the very start
  499. // can move us slightly, and on uneven ground it might matter.
  500. m_destZ = TheTerrainLogic->getLayerHeight(pos->x, pos->y, obj->getLayer());
  501. }
  502. if (pos->z <= m_destZ)
  503. {
  504. Coord3D tmp = *pos;
  505. tmp.z = m_destZ;
  506. obj->setPosition(&tmp);
  507. if (m_targetIsBldg)
  508. {
  509. DEBUG_ASSERTCRASH(TheActionManager->canEnterObject(obj, bldg, obj->getAI()->getLastCommandSource(), COMBATDROP_INTO), ("Hmm, this seems unlikely"));
  510. // if there are enemies... kill up to two. if we kill two, then we die ourselves,
  511. // otherwise we enter the bldg.
  512. const Int MAX_TO_KILL = 2;
  513. Int numKilled = killEnemiesInContainer(obj, bldg, MAX_TO_KILL);
  514. if (numKilled > 0)
  515. {
  516. const FXList* fx = obj->getTemplate()->getPerUnitFX("CombatDropKillFX");
  517. FXList::doFXObj(fx, bldg, NULL);
  518. DEBUG_LOG(("Killing %d enemies in combat drop!\n",numKilled));
  519. }
  520. if (numKilled == MAX_TO_KILL)
  521. {
  522. obj->kill();
  523. DEBUG_LOG(("Killing SELF in combat drop!\n"));
  524. }
  525. else
  526. {
  527. if (bldg->getContain() && bldg->getContain()->isValidContainerFor(obj, TRUE ))
  528. {
  529. bldg->getContain()->addToContain(obj);
  530. }
  531. else
  532. {
  533. // this can legitimately happen if you drop into a full (or nearly full) building.
  534. // let's just place the guy on the ground nearby, since it sucks to fall from the top of a building.
  535. Real exitAngle = bldg->getOrientation();
  536. // Garrison doesn't have reserveDoor or exitDelay, so if we do nothing, everyone will appear on top
  537. // of each other and get stuck inside each others' extent (except for the first guy). So we'll
  538. // scatter the start point around a little to make it better.
  539. Real offset = min(obj->getGeometryInfo().getBoundingCircleRadius(),
  540. bldg->getGeometryInfo().getBoundingCircleRadius());
  541. Real angle = GameLogicRandomValueReal( PI, 2*PI );//Downish.
  542. Coord3D startPosition = *bldg->getPosition();
  543. startPosition.x += offset * Cos( angle );
  544. startPosition.y += offset * Sin( angle );
  545. startPosition.z = TheTerrainLogic->getGroundHeight( startPosition.x, startPosition.y );
  546. obj->setPosition( &startPosition );
  547. obj->setOrientation( exitAngle );
  548. FindPositionOptions options;
  549. options.startAngle = (Real)(1.5 * PI);//Down.
  550. options.maxRadius = 200;
  551. Coord3D endPosition;
  552. Bool foundPosition = ThePartitionManager->findPositionAround( &startPosition, &options, &endPosition );
  553. if( foundPosition )
  554. {
  555. std::vector<Coord3D> exitPath;
  556. exitPath.push_back(endPosition);
  557. AIUpdateInterface* ai = obj->getAI();
  558. if( ai )
  559. {
  560. ai->aiFollowPath( &exitPath, bldg, CMD_FROM_AI );
  561. }
  562. }
  563. }
  564. }
  565. }
  566. result = STATE_SUCCESS;
  567. }
  568. return result;
  569. }
  570. //-----------------------------------------------------------------------------------------------------------
  571. void AIRappelState::onExit( StateExitType status )
  572. {
  573. Object* obj = getMachineOwner();
  574. AIUpdateInterface *ai = obj->getAI();
  575. obj->clearModelConditionState(MODELCONDITION_RAPPELLING);
  576. // don't do this, or we'll be unable to be forced out of this state.
  577. // instead, just manipulate physics directly.
  578. //obj->clearHeld();
  579. ai->setDesiredSpeed( FAST_AS_POSSIBLE );
  580. }
  581. //----------------------------------------------------------------------------------------------------------
  582. //----------------------------------------------------------------------------------------------------------
  583. //----------------------------------------------------------------------------------------------------------
  584. //----------------------------------------------------------------------------------------------------------
  585. /*
  586. NOTE NOTE NOTE NOTE NOTE
  587. Do NOT subclass this unless you want ALL of the states this machine possesses.
  588. If you only want SOME of the states, please make a new StateMachine, descended
  589. from StateMachine, NOT AIStateMachine. Thank you. (srj)
  590. NOTE NOTE NOTE NOTE NOTE
  591. */
  592. AIStateMachine::AIStateMachine( Object *obj, AsciiString name ) : StateMachine( obj, name )
  593. {
  594. DEBUG_ASSERTCRASH(getOwner(), ("An AI State Machine '%s' was constructed without an owner, please tell JKMCD", name));
  595. DEBUG_ASSERTCRASH(getOwner()->getAI(), ("An AI State Machine '%s' was constructed without an AIUpdateInterface, please tell JKMCD", name));
  596. m_goalPath.clear();
  597. m_goalWaypoint = NULL;
  598. m_goalSquad = NULL;
  599. m_temporaryState = NULL;
  600. m_temporaryStateFramEnd = 0;
  601. // order matters: first state is the default state.
  602. defineState( AI_IDLE, newInstance(AIIdleState)( this, AIIdleState::LOOK_FOR_TARGETS), AI_IDLE, AI_IDLE );
  603. defineState( AI_MOVE_TO, newInstance(AIMoveToState)( this ), AI_IDLE, AI_IDLE );
  604. defineState( AI_MOVE_OUT_OF_THE_WAY, newInstance(AIMoveOutOfTheWayState)( this ), AI_IDLE, AI_IDLE );
  605. defineState( AI_MOVE_AND_TIGHTEN, newInstance(AIMoveAndTightenState)( this ), AI_IDLE, AI_IDLE );
  606. defineState( AI_MOVE_AWAY_FROM_REPULSORS, newInstance(AIMoveAwayFromRepulsorsState)( this ), AI_WANDER_IN_PLACE, AI_WANDER_IN_PLACE );
  607. defineState( AI_WANDER_IN_PLACE, newInstance(AIWanderInPlaceState)( this ), AI_MOVE_AWAY_FROM_REPULSORS, AI_MOVE_AWAY_FROM_REPULSORS );
  608. defineState( AI_ATTACK_MOVE_TO, newInstance(AIAttackMoveToState)( this ), AI_IDLE, AI_IDLE );
  609. defineState( AI_ATTACKFOLLOW_WAYPOINT_PATH_AS_TEAM, newInstance(AIAttackFollowWaypointPathState)( this, true ), AI_IDLE, AI_IDLE );
  610. defineState( AI_ATTACKFOLLOW_WAYPOINT_PATH_AS_INDIVIDUALS, newInstance(AIAttackFollowWaypointPathState)( this, false ), AI_IDLE, AI_IDLE );
  611. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_TEAM, newInstance(AIFollowWaypointPathState)( this, true ), AI_IDLE, AI_IDLE );
  612. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_INDIVIDUALS, newInstance(AIFollowWaypointPathState)( this, false ), AI_IDLE, AI_IDLE );
  613. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_TEAM_EXACT, newInstance(AIFollowWaypointPathExactState)( this, true ), AI_IDLE, AI_IDLE );
  614. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_INDIVIDUALS_EXACT,newInstance(AIFollowWaypointPathExactState)( this, false ), AI_IDLE, AI_IDLE );
  615. defineState( AI_FOLLOW_PATH, newInstance(AIFollowPathState)( this ), AI_IDLE, AI_IDLE );
  616. defineState( AI_FOLLOW_EXITPRODUCTION_PATH, newInstance(AIFollowPathState)( this ), AI_IDLE, AI_IDLE );
  617. defineState( AI_MOVE_AND_EVACUATE, newInstance(AIMoveAndEvacuateState)( this ), AI_IDLE, AI_IDLE );
  618. defineState( AI_MOVE_AND_EVACUATE_AND_EXIT, newInstance(AIMoveAndEvacuateState)( this ), AI_MOVE_AND_DELETE, AI_MOVE_AND_DELETE );
  619. defineState( AI_MOVE_AND_DELETE, newInstance(AIMoveAndDeleteState)( this ), AI_IDLE, AI_IDLE );
  620. defineState( AI_WAIT, newInstance(AIWaitState)( this ), AI_IDLE, AI_IDLE );
  621. defineState( AI_ATTACK_POSITION, newInstance(AIAttackState)( this, false, false, false, NULL ), AI_IDLE, AI_IDLE );
  622. defineState( AI_ATTACK_OBJECT, newInstance(AIAttackState)( this, false, true, false, NULL ), AI_IDLE, AI_IDLE );
  623. defineState( AI_FORCE_ATTACK_OBJECT, newInstance(AIAttackState)( this, false, true, true, NULL ), AI_IDLE, AI_IDLE );
  624. defineState( AI_ATTACK_AND_FOLLOW_OBJECT, newInstance(AIAttackState)( this, true, true, false, NULL ), AI_IDLE, AI_IDLE );
  625. defineState( AI_ATTACK_SQUAD, newInstance(AIAttackSquadState)( this, NULL ), AI_IDLE, AI_IDLE );
  626. defineState( AI_WANDER, newInstance(AIWanderState)( this ), AI_IDLE, AI_MOVE_AWAY_FROM_REPULSORS );
  627. defineState( AI_PANIC, newInstance(AIPanicState)( this ), AI_IDLE, AI_MOVE_AWAY_FROM_REPULSORS );
  628. defineState( AI_DEAD, newInstance(AIDeadState)( this ), AI_IDLE, AI_IDLE );
  629. defineState( AI_DOCK, newInstance(AIDockState)( this ), AI_IDLE, AI_IDLE );
  630. defineState( AI_ENTER, newInstance(AIEnterState)( this ), AI_IDLE, AI_IDLE );
  631. defineState( AI_EXIT, newInstance(AIExitState)( this ), AI_IDLE, AI_IDLE );
  632. defineState( AI_EXIT_INSTANTLY, newInstance(AIExitInstantlyState)( this ), AI_IDLE, AI_IDLE );
  633. defineState( AI_GUARD, newInstance(AIGuardState)( this ), AI_IDLE, AI_IDLE );
  634. defineState( AI_GUARD_TUNNEL_NETWORK, newInstance(AITunnelNetworkGuardState)( this ), AI_IDLE, AI_IDLE );
  635. defineState( AI_GUARD_RETALIATE, newInstance(AIGuardRetaliateState)( this ), AI_IDLE, AI_IDLE );
  636. defineState( AI_HUNT, newInstance(AIHuntState)( this ), AI_IDLE, AI_IDLE );
  637. defineState( AI_ATTACK_AREA, newInstance(AIAttackAreaState)( this ), AI_IDLE, AI_IDLE );
  638. defineState( AI_FACE_OBJECT, newInstance(AIFaceState)( this, true ), AI_IDLE, AI_IDLE );
  639. defineState( AI_FACE_POSITION, newInstance(AIFaceState)( this, false ), AI_IDLE, AI_IDLE );
  640. defineState( AI_PICK_UP_CRATE, newInstance(AIPickUpCrateState)( this ), AI_IDLE, AI_IDLE );
  641. defineState( AI_RAPPEL_INTO, newInstance(AIRappelState)( this ), AI_IDLE, AI_IDLE );
  642. defineState( AI_BUSY, newInstance(AIBusyState)( this ), AI_IDLE, AI_IDLE );
  643. }
  644. //----------------------------------------------------------------------------------------------------------
  645. AIStateMachine::~AIStateMachine()
  646. {
  647. if (m_goalSquad)
  648. {
  649. m_goalSquad->deleteInstance();
  650. }
  651. }
  652. // ------------------------------------------------------------------------------------------------
  653. /** CRC */
  654. // ------------------------------------------------------------------------------------------------
  655. void AIStateMachine::crc( Xfer *xfer )
  656. {
  657. StateMachine::crc(xfer);
  658. } // end crc
  659. // ------------------------------------------------------------------------------------------------
  660. /** Xfer Method */
  661. // ------------------------------------------------------------------------------------------------
  662. void AIStateMachine::xfer( Xfer *xfer )
  663. {
  664. // version
  665. XferVersion currentVersion = 1;
  666. XferVersion version = currentVersion;
  667. xfer->xferVersion( &version, currentVersion );
  668. // extend base class
  669. StateMachine::xfer(xfer);
  670. Int i;
  671. Int count = m_goalPath.size();
  672. xfer->xferInt(&count);
  673. for (i=0; i<count; i++) {
  674. Coord3D pos;
  675. if (xfer->getXferMode() != XFER_LOAD)
  676. {
  677. pos = m_goalPath[i];
  678. }
  679. xfer->xferCoord3D(&pos);
  680. if (xfer->getXferMode() == XFER_LOAD)
  681. {
  682. m_goalPath.push_back(pos);
  683. }
  684. }
  685. AsciiString waypointName;
  686. if (m_goalWaypoint) waypointName = m_goalWaypoint->getName();
  687. xfer->xferAsciiString(&waypointName);
  688. if (xfer->getXferMode() == XFER_LOAD)
  689. {
  690. if (waypointName.isNotEmpty()) {
  691. m_goalWaypoint = TheTerrainLogic->getWaypointByName(waypointName);
  692. }
  693. }
  694. Bool hasSquad = (m_goalSquad!=NULL);
  695. xfer->xferBool(&hasSquad);
  696. if (xfer->getXferMode() == XFER_LOAD)
  697. {
  698. if (hasSquad && m_goalSquad==NULL) {
  699. m_goalSquad = newInstance( Squad );
  700. }
  701. }
  702. if (hasSquad) {
  703. xfer->xferSnapshot(m_goalSquad);
  704. }
  705. StateID id = INVALID_STATE_ID;
  706. if (m_temporaryState) {
  707. id = m_temporaryState->getID();
  708. DEBUG_ASSERTCRASH(id!=INVALID_STATE_ID, ("State has invalid state id, no really. jba."));
  709. }
  710. xfer->xferUnsignedInt(&id);
  711. if (xfer->getXferMode() == XFER_LOAD && id != INVALID_STATE_ID) {
  712. m_temporaryState = internalGetState( id );
  713. }
  714. if (m_temporaryState!=NULL) {
  715. xfer->xferSnapshot(m_temporaryState);
  716. }
  717. xfer->xferUnsignedInt(&m_temporaryStateFramEnd);
  718. } // end xfer
  719. // ------------------------------------------------------------------------------------------------
  720. /** Load post process */
  721. // ------------------------------------------------------------------------------------------------
  722. void AIStateMachine::loadPostProcess( void )
  723. {
  724. StateMachine::loadPostProcess();
  725. } // end loadPostProcess
  726. //----------------------------------------------------------------------------------------------------------
  727. /**
  728. * Define a simple path
  729. */
  730. void AIStateMachine::setGoalPath( const std::vector<Coord3D>* path )
  731. {
  732. m_goalPath = *path;
  733. }
  734. #ifdef STATE_MACHINE_DEBUG
  735. //----------------------------------------------------------------------------------------------------------
  736. /**
  737. * Get the current state name.
  738. */
  739. AsciiString AIStateMachine::getCurrentStateName(void) const
  740. {
  741. AsciiString name = StateMachine::getCurrentStateName();
  742. if (m_temporaryState) {
  743. name.concat(" /T/");
  744. name.concat(m_temporaryState->getName());
  745. }
  746. return name;
  747. }
  748. #endif
  749. //-----------------------------------------------------------------------------
  750. /**
  751. * Run one step of the machine
  752. */
  753. StateReturnType AIStateMachine::updateStateMachine()
  754. {
  755. //-extraLogging
  756. #if (defined(_DEBUG) || defined(_INTERNAL))
  757. Bool idle = getOwner()->getAI()->isIdle();
  758. if( !idle && TheGlobalData->m_extraLogging )
  759. DEBUG_LOG( ("%d - %s::update() start - %s", TheGameLogic->getFrame(), getCurrentStateName().str(), getOwner()->getTemplate()->getName().str() ) );
  760. #endif
  761. //end -extraLogging
  762. if (m_temporaryState)
  763. {
  764. // execute this state
  765. StateReturnType status = m_temporaryState->update();
  766. if (m_temporaryStateFramEnd < TheGameLogic->getFrame()) {
  767. // ran out of time.
  768. if (status == STATE_CONTINUE) {
  769. status = STATE_SUCCESS;
  770. }
  771. }
  772. if (status==STATE_CONTINUE)
  773. {
  774. //-extraLogging
  775. #if (defined(_DEBUG) || defined(_INTERNAL))
  776. if( !idle && TheGlobalData->m_extraLogging )
  777. DEBUG_LOG( (" - RETURN EARLY STATE_CONTINUE\n") );
  778. #endif
  779. //end -extraLogging
  780. return status;
  781. }
  782. m_temporaryState->onExit(EXIT_NORMAL);
  783. m_temporaryState = NULL;
  784. }
  785. StateReturnType retType = StateMachine::updateStateMachine();
  786. //-extraLogging
  787. #if (defined(_DEBUG) || defined(_INTERNAL))
  788. AsciiString result;
  789. if( TheGlobalData->m_extraLogging )
  790. {
  791. switch( retType )
  792. {
  793. case STATE_CONTINUE:
  794. result.format( "CONTINUE" );
  795. break;
  796. case STATE_SUCCESS:
  797. result.format( "SUCCESS" );
  798. break;
  799. case STATE_FAILURE:
  800. result.format( "FAILURE" );
  801. break;
  802. default:
  803. result.format( "UNKNOWN %d", retType );
  804. break;
  805. }
  806. if( !idle )
  807. DEBUG_LOG( (" - RETURNING %s\n", result.str() ) );
  808. }
  809. #endif
  810. //end -extraLogging
  811. return retType;
  812. }
  813. //----------------------------------------------------------------------------------------------------------
  814. /**
  815. * Change the temporary state of the machine, and number of frames limit.th
  816. */
  817. StateReturnType AIStateMachine::setTemporaryState( StateID newStateID, Int frameLimitCoount )
  818. {
  819. // extract the state associated with the given ID
  820. State *newState = internalGetState( newStateID );
  821. #ifdef STATE_MACHINE_DEBUG
  822. if (getWantsDebugOutput())
  823. {
  824. StateID curState = INVALID_STATE_ID;
  825. if (m_temporaryState) {
  826. curState = m_temporaryState->getID();
  827. }
  828. DEBUG_LOG(("%d '%s' -(TEMP)- '%s' %x exit ", TheGameLogic->getFrame(), getOwner()->getTemplate()->getName().str(), getName().str(), this));
  829. if (m_temporaryState) {
  830. DEBUG_LOG((" '%s' ", m_temporaryState->getName().str()));
  831. } else {
  832. DEBUG_LOG((" INVALID_STATE_ID "));
  833. }
  834. if (newState) {
  835. DEBUG_LOG(("enter '%s' \n", newState->getName().str()));
  836. } else {
  837. DEBUG_LOG(("to INVALID_STATE\n"));
  838. }
  839. }
  840. #endif
  841. if (m_temporaryState) {
  842. m_temporaryState->onExit(EXIT_RESET);
  843. m_temporaryState = NULL;
  844. }
  845. if (newState) {
  846. m_temporaryState = newState;
  847. StateReturnType ret = m_temporaryState->onEnter();
  848. if (ret != STATE_CONTINUE) {
  849. m_temporaryState->onExit(EXIT_NORMAL);
  850. m_temporaryState = NULL;
  851. return ret;
  852. }
  853. enum {FRAME_COUNT_MAX = 60*LOGICFRAMES_PER_SECOND};
  854. // If you need to up this check, ok, but 1 minute seems overly long for a temporary state override. jba.
  855. DEBUG_ASSERTCRASH(frameLimitCoount<=FRAME_COUNT_MAX, ("Unusually long time to set temporary state."));
  856. if (frameLimitCoount>FRAME_COUNT_MAX) {
  857. frameLimitCoount = FRAME_COUNT_MAX;
  858. }
  859. m_temporaryStateFramEnd = TheGameLogic->getFrame()+frameLimitCoount;
  860. return ret;
  861. }
  862. return STATE_FAILURE;
  863. }
  864. //----------------------------------------------------------------------------------------------------------
  865. /**
  866. * Add a point to a simple path
  867. */
  868. void AIStateMachine::addToGoalPath( const Coord3D *pathPoint)
  869. {
  870. if (m_goalPath.size()==0) {
  871. m_goalPath.push_back(*pathPoint);
  872. } else {
  873. Coord3D *finalPoint = &m_goalPath[ m_goalPath.size() - 1 ];
  874. if( !finalPoint->equals( *pathPoint ) )
  875. {
  876. m_goalPath.push_back(*pathPoint);
  877. }
  878. }
  879. }
  880. //----------------------------------------------------------------------------------------------------------
  881. /**
  882. * Return path position at index "i"
  883. */
  884. const Coord3D *AIStateMachine::getGoalPathPosition( Int i ) const
  885. {
  886. if (i < 0 || i >= m_goalPath.size())
  887. return NULL;
  888. return &m_goalPath[i];
  889. }
  890. //----------------------------------------------------------------------------------------------------------
  891. /**
  892. * Set the current goal waypoint. If we reach this waypoint and there
  893. * are connections to further points, continue on.
  894. */
  895. void AIStateMachine::setGoalWaypoint( const Waypoint *way )
  896. {
  897. m_goalWaypoint = way;
  898. }
  899. //----------------------------------------------------------------------------------------------------------
  900. /**
  901. * Return the current goal waypoint
  902. */
  903. const Waypoint *AIStateMachine::getGoalWaypoint()
  904. {
  905. return m_goalWaypoint;
  906. }
  907. //----------------------------------------------------------------------------------------------------------
  908. void AIStateMachine::clear()
  909. {
  910. StateMachine::clear();
  911. m_goalPath.clear();
  912. m_goalWaypoint = NULL;
  913. m_goalSquad = NULL;
  914. AIUpdateInterface* ai = getOwner()->getAI();
  915. if (ai)
  916. ai->friend_notifyStateMachineChanged();
  917. }
  918. //----------------------------------------------------------------------------------------------------------
  919. StateReturnType AIStateMachine::resetToDefaultState()
  920. {
  921. StateReturnType tmp = StateMachine::resetToDefaultState();
  922. AIUpdateInterface* ai = getOwner()->getAI();
  923. if (ai)
  924. ai->friend_notifyStateMachineChanged();
  925. return tmp;
  926. }
  927. //----------------------------------------------------------------------------------------------------------
  928. StateReturnType AIStateMachine::setState(StateID newStateID)
  929. {
  930. StateID oldID = getCurrentStateID();
  931. StateReturnType tmp = StateMachine::setState(newStateID);
  932. AIUpdateInterface* ai = getOwner()->getAI();
  933. if (ai && oldID != newStateID)
  934. ai->friend_notifyStateMachineChanged();
  935. return tmp;
  936. }
  937. //----------------------------------------------------------------------------------------------------------
  938. void AIStateMachine::setGoalTeam( const Team *team )
  939. {
  940. if (m_goalSquad == NULL) {
  941. m_goalSquad = newInstance( Squad );
  942. }
  943. m_goalSquad->squadFromTeam(team, true);
  944. }
  945. //----------------------------------------------------------------------------------------------------------
  946. void AIStateMachine::setGoalSquad( const Squad *squad )
  947. {
  948. if (m_goalSquad == NULL) {
  949. m_goalSquad = newInstance( Squad );
  950. }
  951. (*m_goalSquad) = (*squad);
  952. }
  953. //----------------------------------------------------------------------------------------------------------
  954. void AIStateMachine::setGoalAIGroup( const AIGroup *group )
  955. {
  956. if (m_goalSquad == NULL) {
  957. m_goalSquad = newInstance( Squad );
  958. }
  959. m_goalSquad->squadFromAIGroup(group, true);
  960. }
  961. //----------------------------------------------------------------------------------------------------------
  962. Squad *AIStateMachine::getGoalSquad( void )
  963. {
  964. return m_goalSquad;
  965. }
  966. // State transition conditions ----------------------------------------------------------------------------
  967. /**
  968. * Return true if the machine's owner's current weapon's range
  969. * cannot reach the goalObject.
  970. */
  971. Bool outOfWeaponRangeObject( State *thisState, void* userData )
  972. {
  973. Object *obj = thisState->getMachineOwner();
  974. Object *victim = thisState->getMachineGoalObject();
  975. Weapon *weapon = obj->getCurrentWeapon();
  976. CRCDEBUG_LOG(("outOfWeaponRangeObject()\n"));
  977. if (victim && weapon)
  978. {
  979. Bool viewBlocked = false;
  980. AIUpdateInterface *ai = obj->getAI();
  981. Bool onGround = true;
  982. if (ai) {
  983. onGround = ai->isDoingGroundMovement();
  984. }
  985. if( obj->isKindOf(KINDOF_IMMOBILE) ) {
  986. onGround = true;
  987. }
  988. // brutal special case for stinger soldiers, who
  989. // generally don't have locomotors, but are still on the ground.
  990. if (obj->isKindOf(KINDOF_SPAWNS_ARE_THE_WEAPONS))
  991. {
  992. onGround = true;
  993. }
  994. Object *containedBy = obj->getContainedBy();
  995. if( containedBy && (containedBy->isKindOf( KINDOF_STRUCTURE ) || !containedBy->isAirborneTarget()) )
  996. {
  997. //Contained objects on the ground -- garrisoned buildings for example!
  998. onGround = true;
  999. }
  1000. // srj sez: at tiny ranges, isAttackViewBlockedByObstacle() can return false positives,
  1001. // so just skip it for contact weapons
  1002. if (victim && !weapon->isContactWeapon() && onGround && !victim->isSignificantlyAboveTerrain())
  1003. {
  1004. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(obj, *obj->getPosition(), victim, *victim->getPosition());
  1005. }
  1006. // A weapon with leech range temporarily has unlimited range and is locked onto its target.
  1007. if (!weapon->hasLeechRange() && viewBlocked)
  1008. {
  1009. //CRCDEBUG_LOG(("outOfWeaponRangeObject() - object %d (%s) view is blocked for attacking %d (%s)\n",
  1010. // obj->getID(), obj->getTemplate()->getName().str(),
  1011. // victim->getID(), victim->getTemplate()->getName().str()));
  1012. return true;
  1013. }
  1014. if (!weapon->hasLeechRange() && !weapon->isWithinAttackRange(obj, victim))
  1015. {
  1016. //CRCDEBUG_LOG(("outOfWeaponRangeObject() - object %d (%s) is out of range for attacking %d (%s)\n",
  1017. // obj->getID(), obj->getTemplate()->getName().str(),
  1018. // victim->getID(), victim->getTemplate()->getName().str()));
  1019. return true;
  1020. }
  1021. }
  1022. return false;
  1023. }
  1024. static Bool inWeaponRangeObject(State *thisState, void* userData)
  1025. {
  1026. return !outOfWeaponRangeObject(thisState, userData);
  1027. }
  1028. Bool wantToSquishTarget( State *thisState, void* userData )
  1029. {
  1030. Object *obj = thisState->getMachineOwner();
  1031. Object *victim = thisState->getMachineGoalObject();
  1032. if (obj && victim)
  1033. {
  1034. if (victim->getContainedBy()) {
  1035. return false; // can't crush guys in buildings or vehicles.
  1036. }
  1037. if( obj->getAI() && (obj->getAI()->getWhichTurretForCurWeapon() != TURRET_INVALID) )
  1038. {
  1039. // I can only decide to crush-attack if I am attacking with a turreted weapon.
  1040. if (TheAI->getAiData()->m_aiCrushesInfantry) {
  1041. if (obj && obj->getControllingPlayer() &&
  1042. obj->getControllingPlayer()->getPlayerType()==PLAYER_COMPUTER) {
  1043. if (obj->canCrushOrSquish(victim)) {
  1044. if (!obj->isKindOf(KINDOF_DONT_AUTO_CRUSH_INFANTRY)) {
  1045. return true;
  1046. }
  1047. }
  1048. }
  1049. }
  1050. }
  1051. }
  1052. return false;
  1053. }
  1054. Bool outOfWeaponRangePosition( State *thisState, void* userData )
  1055. {
  1056. Object *obj = thisState->getMachineOwner();
  1057. const Coord3D *pos = thisState->getMachineGoalPosition();
  1058. Weapon *weapon = obj->getCurrentWeapon();
  1059. if (weapon && pos)
  1060. {
  1061. AIUpdateInterface *ai = obj->getAI();
  1062. Bool onGround = true;
  1063. if (ai) {
  1064. onGround = ai->isDoingGroundMovement();
  1065. }
  1066. if( obj->isKindOf(KINDOF_IMMOBILE) ) {
  1067. onGround = true;
  1068. }
  1069. // brutal special case for stinger soldiers, who
  1070. // generally don't have locomotors, but are still on the ground.
  1071. if (obj->isKindOf(KINDOF_SPAWNS_ARE_THE_WEAPONS))
  1072. {
  1073. onGround = true;
  1074. }
  1075. Object *containedBy = obj->getContainedBy();
  1076. if( containedBy && (containedBy->isKindOf( KINDOF_STRUCTURE ) || !containedBy->isAirborneTarget()) )
  1077. {
  1078. //Contained objects on the ground -- garrisoned buildings for example!
  1079. onGround = true;
  1080. }
  1081. Bool viewBlocked = false;
  1082. if (onGround)
  1083. {
  1084. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(obj, *obj->getPosition(), NULL, *pos);
  1085. }
  1086. if (viewBlocked)
  1087. {
  1088. return true;
  1089. }
  1090. if (!weapon->isWithinAttackRange(obj, pos))
  1091. {
  1092. return true;
  1093. }
  1094. }
  1095. return false;
  1096. }
  1097. /**
  1098. * Return true if the machine's owner's cannot attack in any way
  1099. */
  1100. static Bool cannotPossiblyAttackObject( State *thisState, void* userData )
  1101. {
  1102. AbleToAttackType attackType = (AbleToAttackType)(UnsignedInt)userData;
  1103. Object *obj = thisState->getMachineOwner();
  1104. Object *victim = thisState->getMachineGoalObject();
  1105. if (obj && victim)
  1106. {
  1107. if( !obj->isAbleToAttack() )
  1108. {
  1109. return TRUE;
  1110. }
  1111. CanAttackResult result = obj->getAbleToAttackSpecificObject( attackType, victim, obj->getAI()->getLastCommandSource() );
  1112. if( result != ATTACKRESULT_POSSIBLE && result != ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  1113. {
  1114. return TRUE;
  1115. }
  1116. }
  1117. return FALSE;
  1118. }
  1119. //----------------------------------------------------------------------------------------------
  1120. //----------------------------------------------------------------------------------------------
  1121. //----------------------------------------------------------------------------------------------
  1122. const UnsignedInt IDLE_COUNTDOWN_DELAY = (LOGICFRAMES_PER_SECOND * 2);
  1123. //----------------------------------------------------------------------------------------------
  1124. AIIdleState::AIIdleState( StateMachine *machine, AIIdleState::AIIdleTargetingType shouldLookForTargets ) :
  1125. State( machine,"AIIdleState"),
  1126. m_shouldLookForTargets(shouldLookForTargets == AIIdleState::LOOK_FOR_TARGETS)
  1127. {
  1128. m_inited = FALSE;
  1129. m_initialSleepOffset = -1;
  1130. }
  1131. // ------------------------------------------------------------------------------------------------
  1132. /** CRC */
  1133. // ------------------------------------------------------------------------------------------------
  1134. void AIIdleState::crc( Xfer *xfer )
  1135. {
  1136. } // end crc
  1137. // ------------------------------------------------------------------------------------------------
  1138. /** Xfer Method */
  1139. // ------------------------------------------------------------------------------------------------
  1140. void AIIdleState::xfer( Xfer *xfer )
  1141. {
  1142. // version
  1143. XferVersion currentVersion = 1;
  1144. XferVersion version = currentVersion;
  1145. xfer->xferVersion( &version, currentVersion );
  1146. xfer->xferUnsignedShort(&m_initialSleepOffset);
  1147. xfer->xferBool(&m_shouldLookForTargets);
  1148. xfer->xferBool(&m_inited);
  1149. } // end xfer
  1150. // ------------------------------------------------------------------------------------------------
  1151. /** Load post process */
  1152. // ------------------------------------------------------------------------------------------------
  1153. void AIIdleState::loadPostProcess( void )
  1154. {
  1155. } // end loadPostProcess
  1156. //----------------------------------------------------------------------------------------------
  1157. /**
  1158. * Stake out our space.
  1159. */
  1160. DECLARE_PERF_TIMER(AIIdleState)
  1161. StateReturnType AIIdleState::onEnter()
  1162. {
  1163. USE_PERF_TIMER(AIIdleState)
  1164. Object *obj = getMachineOwner();
  1165. AIUpdateInterface *ai = obj->getAI();
  1166. // We could possibly not have ai here if we were constructed this frame. Strange but true. :-<
  1167. if (ai)
  1168. ai->resetNextMoodCheckTime();
  1169. m_inited = true;
  1170. // reset the idle countdown so that we don't do expensive checks too often,
  1171. // randomized so we avoid spikes
  1172. m_initialSleepOffset = (UnsignedShort)GameLogicRandomValue(0, IDLE_COUNTDOWN_DELAY);
  1173. // never sleep at the start, since we have to do checkGoalPos first time thru
  1174. return STATE_CONTINUE;
  1175. }
  1176. //----------------------------------------------------------------------------------------------
  1177. void AIIdleState::doInitIdleState()
  1178. {
  1179. // Only do it once, but do it in the update cause onEnter for idle is called during object creation. jba.
  1180. if (!m_inited)
  1181. return;
  1182. m_inited = false;
  1183. Object *obj = getMachineOwner();
  1184. AIUpdateInterface *ai = obj->getAI();
  1185. const Locomotor* loco = ai->getCurLocomotor();
  1186. Bool ultraAccurate = (loco != NULL && loco->isUltraAccurate());
  1187. #define NO_STOP_AND_SLIDE
  1188. if (ai->isIdle() && ai->isDoingGroundMovement())
  1189. {
  1190. /*
  1191. You may be asking yourself, "If I'm in an idle state, how can I be doing ground movement?"
  1192. answer from jba:
  1193. If a unit is moving, and you hit stop, it forces it into the idle state.
  1194. Depending where it is, it may be between pathfind grids.
  1195. This is a bad thing.
  1196. So it "cheat moves", to the nearest grid.
  1197. Also, for locos the "close enough" distance is 1 or so.
  1198. So it moves the rest of the way to it's goal location by cheating.
  1199. */
  1200. // Update the goal.
  1201. Coord3D goalPos = *obj->getPosition();
  1202. // but only if we have a valid position.
  1203. if (goalPos.x || goalPos.y || goalPos.z)
  1204. {
  1205. TheAI->pathfinder()->updateGoal(obj, &goalPos, obj->getLayer());
  1206. if (!ultraAccurate && TheAI->pathfinder()->goalPosition(obj, &goalPos))
  1207. {
  1208. if (TheGameLogic->getFrame()<=1) {
  1209. obj->setPosition(&goalPos);
  1210. } else {
  1211. #ifdef STOP_AND_SLIDE
  1212. ai->setFinalPosition(&goalPos);
  1213. #endif
  1214. }
  1215. TheAI->pathfinder()->updateGoal(obj, &goalPos, obj->getLayer());
  1216. }
  1217. }
  1218. }
  1219. ai->setLocomotorGoalNone();
  1220. ai->setCurrentVictim(NULL);
  1221. }
  1222. //----------------------------------------------------------------------------------------------
  1223. /**
  1224. * Just sit there.
  1225. */
  1226. StateReturnType AIIdleState::update()
  1227. {
  1228. USE_PERF_TIMER(AIIdleState)
  1229. doInitIdleState();
  1230. UnsignedInt timeToSleep = IDLE_COUNTDOWN_DELAY + m_initialSleepOffset;
  1231. UnsignedInt oldSleepOffset = m_initialSleepOffset;
  1232. m_initialSleepOffset = 0;
  1233. // This state is used internally some places, so we don't necessarily want to be looking for targets
  1234. // Places that use AI_IDLE internally should set this to false in the constructor. jkmcd
  1235. if ( m_shouldLookForTargets && !getMachine()->isLocked() )
  1236. {
  1237. // if we are here, it's time to check again
  1238. Object *obj = getMachineOwner();
  1239. AIUpdateInterface *ai = obj->getAI();
  1240. // do repulsor logic
  1241. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED) && ai->isIdle())
  1242. {
  1243. Object* enemy = TheAI->findClosestRepulsor(obj, obj->getVisionRange());
  1244. if (enemy)
  1245. {
  1246. getMachine()->setState(AI_MOVE_AWAY_FROM_REPULSORS);
  1247. // since we just changed the state, it doesn't really matter what we return here.
  1248. return STATE_CONTINUE;
  1249. }
  1250. }
  1251. // Check to see if we have created a crate we need to pick up.
  1252. Object* crate = ai->checkForCrateToPickup();
  1253. if (crate)
  1254. {
  1255. ai->aiMoveToObject(crate, CMD_FROM_AI);
  1256. // since we just changed the state, it doesn't really matter what we return here.
  1257. return STATE_CONTINUE;
  1258. }
  1259. if (! obj->isDisabledByType( DISABLED_PARALYZED ) &&
  1260. ! obj->isDisabledByType( DISABLED_UNMANNED ) &&
  1261. ! obj->isDisabledByType( DISABLED_EMP ) &&
  1262. ! obj->isDisabledByType( DISABLED_SUBDUED ) &&
  1263. ! obj->isDisabledByType( DISABLED_HACKED ) )
  1264. {
  1265. // mood targeting
  1266. UnsignedInt moodAdjust = ai->getMoodMatrixActionAdjustment(MM_Action_Idle);
  1267. if ((moodAdjust & MAA_Affect_Range_IgnoreAll) == 0)
  1268. {
  1269. // If we're supposed to attack based on mood, etc, then we will do so.
  1270. Object* enemy = ai->getNextMoodTarget( true, true );
  1271. if (enemy)
  1272. {
  1273. ai->aiAttackObject(enemy, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  1274. // weird but true. return state_continue, because if we're here, we're actually an attack state
  1275. // since we just changed the state, it doesn't really matter what we return here.
  1276. return STATE_CONTINUE;
  1277. }
  1278. }
  1279. }
  1280. UnsignedInt now = TheGameLogic->getFrame();
  1281. UnsignedInt nextMoodCheckTime = ai->getNextMoodCheckTime();
  1282. if (nextMoodCheckTime > now)
  1283. {
  1284. // if we need to look for targets, might need to sleep less.
  1285. UnsignedInt moodSleep = nextMoodCheckTime - now;
  1286. if (moodSleep < timeToSleep)
  1287. {
  1288. timeToSleep = moodSleep;
  1289. // if we do this, save the random sleep offset for next time.
  1290. m_initialSleepOffset = oldSleepOffset;
  1291. }
  1292. }
  1293. } // end if, should look for targets
  1294. return STATE_SLEEP(timeToSleep);
  1295. }
  1296. //----------------------------------------------------------------------------------------------
  1297. /**
  1298. * Just sit there, but dead-like.
  1299. */
  1300. StateReturnType AIDeadState::onEnter()
  1301. {
  1302. Object *obj = getMachineOwner();
  1303. // How can an object be NULL here? I don't think it actually can, but this check must be
  1304. // here for a reason. - jkmcd
  1305. if (obj)
  1306. {
  1307. ModelConditionFlags nonDyingStuff;
  1308. nonDyingStuff.set(MODELCONDITION_USING_WEAPON_A);
  1309. nonDyingStuff.set(MODELCONDITION_USING_WEAPON_B);
  1310. nonDyingStuff.set(MODELCONDITION_USING_WEAPON_C);
  1311. nonDyingStuff.set(MODELCONDITION_FIRING_A);
  1312. nonDyingStuff.set(MODELCONDITION_FIRING_B);
  1313. nonDyingStuff.set(MODELCONDITION_FIRING_C);
  1314. nonDyingStuff.set(MODELCONDITION_BETWEEN_FIRING_SHOTS_A);
  1315. nonDyingStuff.set(MODELCONDITION_BETWEEN_FIRING_SHOTS_B);
  1316. nonDyingStuff.set(MODELCONDITION_BETWEEN_FIRING_SHOTS_C);
  1317. nonDyingStuff.set(MODELCONDITION_RELOADING_A);
  1318. nonDyingStuff.set(MODELCONDITION_RELOADING_B);
  1319. nonDyingStuff.set(MODELCONDITION_RELOADING_C);
  1320. nonDyingStuff.set(MODELCONDITION_PREATTACK_A);
  1321. nonDyingStuff.set(MODELCONDITION_PREATTACK_B);
  1322. nonDyingStuff.set(MODELCONDITION_PREATTACK_C);
  1323. #ifdef ALLOW_SURRENDER
  1324. nonDyingStuff.set(MODELCONDITION_SURRENDER);
  1325. #endif
  1326. nonDyingStuff.set(MODELCONDITION_MOVING);
  1327. // dying objects are NEVER firing, surrendered, etc, so clear 'em all here.
  1328. obj->clearAndSetModelConditionFlags(nonDyingStuff, MAKE_MODELCONDITION_MASK(MODELCONDITION_DYING));
  1329. TheScriptEngine->notifyOfObjectCreationOrDestruction();
  1330. }
  1331. return STATE_CONTINUE;
  1332. }
  1333. StateReturnType AIDeadState::update()
  1334. {
  1335. Object *obj = getMachineOwner();
  1336. AIUpdateInterface *ai = obj->getAI();
  1337. ai->setLocomotorGoalNone();
  1338. // re-mark this every time, just in case our health miraculously heals from 0 to nonzero...
  1339. obj->setEffectivelyDead(true);
  1340. if (obj->isKindOf(KINDOF_INFANTRY))
  1341. {
  1342. PhysicsBehavior* phys = obj->getPhysics();
  1343. if (phys)
  1344. {
  1345. // we want 'em to stop, but looks wonky if they stop dead in their tracks in onEnter.
  1346. // this slows 'em down quickly
  1347. const Real FACTOR = 0.8f; // 0.8 ^ 30 == 0.012, so they slow to 4% of speed over 1 sec
  1348. Real vel = phys->getVelocityMagnitude();
  1349. phys->scrubVelocity2D(vel * FACTOR);
  1350. }
  1351. }
  1352. return STATE_CONTINUE;
  1353. }
  1354. void AIDeadState::onExit( StateExitType status )
  1355. {
  1356. Object *obj = getMachineOwner();
  1357. obj->clearModelConditionState(MODELCONDITION_DYING);
  1358. }
  1359. //----------------------------------------------------------------------------------------------
  1360. // ------------------------------------------------------------------------------------------------
  1361. /** CRC */
  1362. // ------------------------------------------------------------------------------------------------
  1363. void AIInternalMoveToState::crc( Xfer *xfer )
  1364. {
  1365. } // end crc
  1366. // ------------------------------------------------------------------------------------------------
  1367. /** Xfer Method */
  1368. // ------------------------------------------------------------------------------------------------
  1369. void AIInternalMoveToState::xfer( Xfer *xfer )
  1370. {
  1371. // version
  1372. XferVersion currentVersion = 1;
  1373. XferVersion version = currentVersion;
  1374. xfer->xferVersion( &version, currentVersion );
  1375. // extend base class
  1376. xfer->xferCoord3D(&m_goalPosition);
  1377. xfer->xferUser(&m_goalLayer, sizeof(m_goalLayer));
  1378. xfer->xferBool(&m_waitingForPath);
  1379. xfer->xferCoord3D(&m_pathGoalPosition);
  1380. xfer->xferUnsignedInt(&m_pathTimestamp);
  1381. xfer->xferUnsignedInt(&m_blockedRepathTimestamp);
  1382. xfer->xferBool(&m_adjustDestinations);
  1383. } // end xfer
  1384. // ------------------------------------------------------------------------------------------------
  1385. /** Load post process */
  1386. // ------------------------------------------------------------------------------------------------
  1387. void AIInternalMoveToState::loadPostProcess( void )
  1388. {
  1389. startMoveSound();
  1390. } // end loadPostProcess
  1391. Bool AIInternalMoveToState::getAdjustsDestination() const
  1392. {
  1393. const Object *obj = getMachineOwner();
  1394. if (obj->testStatus(OBJECT_STATUS_PARACHUTING))
  1395. return false;
  1396. const AIUpdateInterface* ai = obj->getAI();
  1397. if (ai && !ai->isAllowedToAdjustDestination())
  1398. return false;
  1399. return m_adjustDestinations;
  1400. }
  1401. /**
  1402. * (Re)compute a path to the goal position, if we are on our own,
  1403. * or we are the leader of a group.
  1404. */
  1405. Bool AIInternalMoveToState::computePath()
  1406. {
  1407. Object *obj = getMachineOwner();
  1408. AIUpdateInterface *ai = obj->getAI();
  1409. m_waitingForPath = true;
  1410. ai->requestPath(&m_goalPosition, getAdjustsDestination());
  1411. ai->friend_startingMove();
  1412. return true;
  1413. }
  1414. /**
  1415. * We are initiating a moveTo action.
  1416. * Pathfind from m_goalPosition to goal.
  1417. */
  1418. StateReturnType AIInternalMoveToState::onEnter()
  1419. {
  1420. m_ambientPlayingHandle = AHSV_Error;
  1421. Object *obj = getMachineOwner();
  1422. AIUpdateInterface *ai = obj->getAI();
  1423. m_waitingForPath = ai->isWaitingForPath();
  1424. if( obj->testStatus( OBJECT_STATUS_IMMOBILE ) )
  1425. {
  1426. return STATE_FAILURE;
  1427. }
  1428. if (ai->getCurLocomotor()) {
  1429. ai->getCurLocomotor()->startMove();
  1430. if (ai->getCurLocomotor()->isUltraAccurate())
  1431. {
  1432. setAdjustsDestination(false); // if we're being ultra accurate, we can't adjust the destination. jba.
  1433. }
  1434. }
  1435. m_tryOneMoreRepath = true; // We may try one more repath after the first one is finished.
  1436. ai->friend_startingMove();
  1437. // get object physics state
  1438. PhysicsBehavior *physics = obj->getPhysics();
  1439. if (physics && physics->isMotive()) {
  1440. // If we were already moving, go immediately to the animation.
  1441. // This is so if you redirect a moving infantry or other animated model, he doesn't
  1442. // pop into idle for 1 frame. jba.
  1443. //Determine if we are on a cliff cell... if so, use the climbing model condition
  1444. //instead of moving.
  1445. Int cellX = REAL_TO_INT( obj->getPosition()->x / PATHFIND_CELL_SIZE );
  1446. Int cellY = REAL_TO_INT( obj->getPosition()->y / PATHFIND_CELL_SIZE );
  1447. PathfindCell* cell = TheAI->pathfinder()->getCell( obj->getLayer(), cellX, cellY );
  1448. ModelConditionFlagType modelConditionFlag = (cell && cell->getType() != PathfindCell::CELL_CLIFF) ? MODELCONDITION_MOVING : MODELCONDITION_CLIMBING;
  1449. obj->setModelConditionState( modelConditionFlag );
  1450. }
  1451. // This is a classic January 2 type of hack
  1452. // Since the worker can go into its attack modelcondition in AIAttack::OnEnter(),
  1453. // it needs to get its moving modelcondition set timely enough to trigger a transition
  1454. // from conditionX into ATTACKING|MOVING... Thanks for reading, MLorenzen, Jan 2, 2003
  1455. else if ( obj->isKindOf( KINDOF_DOZER ) && obj->isKindOf( KINDOF_HARVESTER ) )
  1456. obj->setModelConditionState( MODELCONDITION_MOVING );
  1457. if( getAdjustsDestination() && !obj->testStatus( OBJECT_STATUS_RIDER8 ) )
  1458. {
  1459. if (!TheAI->pathfinder()->adjustDestination(obj, ai->getLocomotorSet(), &m_goalPosition))
  1460. {
  1461. TheAI->pathfinder()->snapClosestGoalPosition(obj, &m_goalPosition);
  1462. }
  1463. TheAI->pathfinder()->updateGoal(obj, &m_goalPosition, TheTerrainLogic->getLayerForDestination(&m_goalPosition));
  1464. }
  1465. // request a path to the destination
  1466. if (!computePath())
  1467. {
  1468. ai->friend_endingMove();
  1469. return STATE_FAILURE;
  1470. }
  1471. // Target to stop at the end of this path.
  1472. // This value will be overriden by the FollowWaypoint ai state.
  1473. ai->setPathExtraDistance(0);
  1474. ai->setDesiredSpeed( FAST_AS_POSSIBLE );
  1475. startMoveSound();
  1476. return STATE_CONTINUE;
  1477. }
  1478. /**
  1479. * Start playing the object's move sound.
  1480. */
  1481. void AIInternalMoveToState::startMoveSound(void)
  1482. {
  1483. Object *obj = getMachineOwner();
  1484. const BodyModuleInterface *objBody = obj->getBodyModule();
  1485. if (objBody && IS_CONDITION_WORSE(objBody->getDamageState(), BODY_DAMAGED))
  1486. {
  1487. AudioEventRTS soundEventMoveDamaged = *obj->getTemplate()->getSoundMoveStartDamaged();
  1488. if (!soundEventMoveDamaged.getEventName().isEmpty())
  1489. {
  1490. soundEventMoveDamaged.setObjectID(obj->getID());
  1491. TheAudio->addAudioEvent( &soundEventMoveDamaged );
  1492. }
  1493. else
  1494. {
  1495. soundEventMoveDamaged = *obj->getTemplate()->getSoundMoveLoopDamaged();
  1496. if (!soundEventMoveDamaged.getEventName().isEmpty())
  1497. {
  1498. soundEventMoveDamaged.setObjectID(obj->getID());
  1499. m_ambientPlayingHandle = TheAudio->addAudioEvent( &soundEventMoveDamaged );
  1500. }
  1501. }
  1502. }
  1503. else
  1504. {
  1505. AudioEventRTS soundEventMove = *obj->getTemplate()->getSoundMoveStart();
  1506. soundEventMove.setObjectID(obj->getID());
  1507. if (!soundEventMove.getEventName().isEmpty())
  1508. {
  1509. TheAudio->addAudioEvent( &soundEventMove );
  1510. }
  1511. else
  1512. {
  1513. soundEventMove = *obj->getTemplate()->getSoundMoveLoop();
  1514. soundEventMove.setObjectID(obj->getID());
  1515. if (!soundEventMove.getEventName().isEmpty())
  1516. {
  1517. m_ambientPlayingHandle = TheAudio->addAudioEvent( &soundEventMove );
  1518. }
  1519. }
  1520. }
  1521. }
  1522. /**
  1523. * We are leaving the moveTo state.
  1524. */
  1525. void AIInternalMoveToState::onExit( StateExitType status )
  1526. {
  1527. Object *obj = getMachineOwner();
  1528. AIUpdateInterface *ai = obj->getAI();
  1529. // stop ambient sound associated with movement
  1530. TheAudio->removeAudioEvent( m_ambientPlayingHandle );
  1531. // If this onExit is the result of the state machine being deleted, then there is no AI.
  1532. // (This is why destructors should not do game logic)
  1533. if (ai) {
  1534. ai->friend_endingMove();
  1535. DEBUG_ASSERTLOG(obj->getTeam(), ("AIInternalMoveToState::onExit obj has NULL team.\n"));
  1536. if (obj->getTeam() && ai->isDoingGroundMovement() && ai->getCurLocomotor() &&
  1537. ai->getCurLocomotor()->isUltraAccurate()) {
  1538. Real dx = m_goalPosition.x-obj->getPosition()->x;
  1539. Real dy = m_goalPosition.y-obj->getPosition()->y;
  1540. if (dx*dx+dy*dy<PATHFIND_CELL_SIZE_F*PATHFIND_CELL_SIZE_F)
  1541. {
  1542. // We are doing accurate ground movement, so make sure we end exactly at the goal.
  1543. ai->setFinalPosition(&m_goalPosition);
  1544. }
  1545. }
  1546. }
  1547. }
  1548. /**
  1549. * Execute the moveTo behavior towards GoalPosition.
  1550. */
  1551. StateReturnType AIInternalMoveToState::update()
  1552. {
  1553. Object *obj = getMachineOwner();
  1554. AIUpdateInterface *ai = obj->getAI();
  1555. //Kris: 7/01/03 (Temporary debug hook for units not being able to leave maps)
  1556. Bool blah = FALSE;
  1557. if( getMachineOwner()->testStatus( OBJECT_STATUS_RIDER8 ) )
  1558. {
  1559. blah = TRUE;
  1560. }
  1561. //If we're deployed, don't move! But keep the state around until we can packup (edge case).
  1562. //if( obj->testStatus( OBJECT_STATUS_DEPLOYED ) )
  1563. //{
  1564. // return STATE_CONTINUE;
  1565. //}
  1566. Path *thePath = ai->getPath();
  1567. if (m_waitingForPath)
  1568. {
  1569. // bump the timer.
  1570. m_pathTimestamp = TheGameLogic->getFrame();
  1571. if (ai->isWaitingForPath()) {
  1572. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  1573. return STATE_CONTINUE;
  1574. }
  1575. if (thePath==NULL)
  1576. {
  1577. //Kris: 7/01/03 (Temporary debug hook for units not being able to leave maps)
  1578. if( blah )
  1579. {
  1580. blah = blah;
  1581. }
  1582. return STATE_FAILURE;
  1583. }
  1584. m_waitingForPath = false;
  1585. m_pathGoalPosition = m_goalPosition;
  1586. if (this->getAdjustsDestination()) {
  1587. TheAI->pathfinder()->updateGoal(obj, thePath->getLastNode()->getPosition(), thePath->getLastNode()->getLayer());
  1588. } else {
  1589. TheAI->pathfinder()->removeGoal(obj);
  1590. }
  1591. if (!ai->getRetryPath()) {
  1592. m_tryOneMoreRepath = false;
  1593. }
  1594. }
  1595. Bool forceRecompute = false;
  1596. if (thePath==NULL) {
  1597. forceRecompute = true;
  1598. }
  1599. Bool blocked=false;
  1600. if (ai->isBlockedAndStuck() || ai->getNumFramesBlocked()>2*LOGICFRAMES_PER_SECOND) {
  1601. forceRecompute = true;
  1602. blocked = true;
  1603. m_blockedRepathTimestamp = TheGameLogic->getFrame();
  1604. // Intense debug logging jba.
  1605. //DEBUG_LOG(("Info - Blocked - recomputing.\n"));
  1606. }
  1607. //Determine if we are on a cliff cell... if so, use the climbing model condition
  1608. //instead of moving.
  1609. Int cellX = REAL_TO_INT( obj->getPosition()->x / PATHFIND_CELL_SIZE );
  1610. Int cellY = REAL_TO_INT( obj->getPosition()->y / PATHFIND_CELL_SIZE );
  1611. PathfindCell* cell = TheAI->pathfinder()->getCell( obj->getLayer(), cellX, cellY );
  1612. ModelConditionFlagType setConditionFlag = MODELCONDITION_MOVING;
  1613. // Totally hacky set of conditions to make col. burton's monkey ass not slide down
  1614. // the cliffs backwards. This could use some improvement at some point. jba. 31DEC2002
  1615. if (cell && cell->getType() == PathfindCell::CELL_CLIFF && !cell->getPinched()) {
  1616. if (ai->getCurLocomotor() && ai->getCurLocomotor()->isMovingBackwards()) {
  1617. setConditionFlag = MODELCONDITION_RAPPELLING;
  1618. obj->clearModelConditionState( MODELCONDITION_CLIMBING );
  1619. } else {
  1620. setConditionFlag = MODELCONDITION_CLIMBING;
  1621. obj->clearModelConditionState( MODELCONDITION_RAPPELLING );
  1622. }
  1623. }
  1624. if (ai->getNumFramesBlocked()>LOGICFRAMES_PER_SECOND/4)
  1625. {
  1626. obj->clearModelConditionState( MODELCONDITION_MOVING );
  1627. }
  1628. else
  1629. {
  1630. //Clear climbing if modelConditionFlag is not climbing
  1631. if( setConditionFlag == MODELCONDITION_MOVING )
  1632. {
  1633. obj->clearModelConditionState( MODELCONDITION_CLIMBING );
  1634. obj->clearModelConditionState( MODELCONDITION_RAPPELLING );
  1635. }
  1636. obj->setModelConditionState(MODELCONDITION_MOVING);
  1637. if (setConditionFlag!=MODELCONDITION_MOVING) {
  1638. obj->setModelConditionState( setConditionFlag );
  1639. }
  1640. }
  1641. if (ai->canComputeQuickPath()) {
  1642. if (obj->isKindOf(KINDOF_PROJECTILE)) {
  1643. m_pathTimestamp = 0; // We can compute paths cheap, so don't delay to recompute. jba.
  1644. forceRecompute = true;
  1645. }
  1646. }
  1647. if (thePath != NULL)
  1648. ai->setLocomotorGoalPositionOnPath();
  1649. // if our goal has moved, recompute our path
  1650. if (forceRecompute || TheGameLogic->getFrame() - m_pathTimestamp > MIN_REPATH_TIME)
  1651. {
  1652. if (forceRecompute || !isSamePosition(obj->getPosition(), &m_pathGoalPosition, &m_goalPosition ))
  1653. {
  1654. // goal moved - repath
  1655. if (!computePath())
  1656. {
  1657. //Kris: 7/01/03 (Temporary debug hook for units not being able to leave maps)
  1658. if( blah )
  1659. {
  1660. blah = blah;
  1661. }
  1662. return STATE_FAILURE;
  1663. }
  1664. // srj sez: must re-set setLocoGoal after computePath, since computePath
  1665. // can set the loco goal to NONE...
  1666. if (ai->getPath() != NULL)
  1667. ai->setLocomotorGoalPositionOnPath();
  1668. else
  1669. {
  1670. return STATE_CONTINUE;
  1671. }
  1672. }
  1673. }
  1674. //
  1675. // Check if we have reached our destination
  1676. //
  1677. Real onPathDistToGoal = ai->getLocomotorDistanceToGoal();
  1678. //DEBUG_LOG(("onPathDistToGoal = %f %s\n",onPathDistToGoal, obj->getTemplate()->getName().str()));
  1679. if (ai->getCurLocomotor() && (onPathDistToGoal < ai->getCurLocomotor()->getCloseEnoughDist()))
  1680. {
  1681. if (ai->isDoingGroundMovement()) {
  1682. // sanity check
  1683. Coord3D delta;
  1684. Coord3D goalPos = m_goalPosition;
  1685. if (ai->getPath()->getLastNode()) {
  1686. goalPos = *ai->getPath()->getLastNode()->getPosition();
  1687. }
  1688. delta.x = obj->getPosition()->x - goalPos.x;
  1689. delta.y = obj->getPosition()->y - goalPos.y;
  1690. delta.z = 0;
  1691. if (delta.length() > 4*PATHFIND_CELL_SIZE_F) {
  1692. //DEBUG_LOG(("AIInternalMoveToState Trying to finish early. Continuing...\n"));
  1693. onPathDistToGoal = ai->getLocomotorDistanceToGoal();
  1694. return STATE_CONTINUE;
  1695. }
  1696. }
  1697. // we have reached the end of the path
  1698. if (getAdjustsDestination())
  1699. {
  1700. ai->setLocomotorGoalNone();
  1701. }
  1702. DEBUG_ASSERTLOG(!getMachine()->getWantsDebugOutput(), ("AIInternalMoveToState::update: reached end of path, exiting state with success\n"));
  1703. //Kris: 7/01/03 (Temporary debug hook for units not being able to leave maps)
  1704. if( blah )
  1705. {
  1706. blah = blah;
  1707. }
  1708. return STATE_SUCCESS;
  1709. }
  1710. return STATE_CONTINUE;
  1711. }
  1712. //-------------------------------------------------------------------------------------------------
  1713. //-------------------------------------------------------------------------------------------------
  1714. //-------------------------------------------------------------------------------------------------
  1715. //-----------------------------------------------------------------------------------------------------------
  1716. class AIAttackMoveStateMachine : public StateMachine
  1717. {
  1718. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( AIAttackMoveStateMachine, "AIAttackMoveStateMachine" );
  1719. public:
  1720. AIAttackMoveStateMachine( Object *owner, AsciiString name );
  1721. protected:
  1722. // snapshot interface
  1723. virtual void crc( Xfer *xfer );
  1724. virtual void xfer( Xfer *xfer );
  1725. virtual void loadPostProcess();
  1726. };
  1727. // ------------------------------------------------------------------------------------------------
  1728. /** CRC */
  1729. // ------------------------------------------------------------------------------------------------
  1730. void AIAttackMoveStateMachine::crc( Xfer *xfer )
  1731. {
  1732. StateMachine::crc(xfer);
  1733. } // end crc
  1734. // ------------------------------------------------------------------------------------------------
  1735. /** Xfer Method */
  1736. // ------------------------------------------------------------------------------------------------
  1737. void AIAttackMoveStateMachine::xfer( Xfer *xfer )
  1738. {
  1739. XferVersion cv = 1;
  1740. XferVersion v = cv;
  1741. xfer->xferVersion( &v, cv );
  1742. StateMachine::xfer(xfer);
  1743. } // end xfer
  1744. // ------------------------------------------------------------------------------------------------
  1745. /** Load post process */
  1746. // ------------------------------------------------------------------------------------------------
  1747. void AIAttackMoveStateMachine::loadPostProcess( void )
  1748. {
  1749. StateMachine::loadPostProcess();
  1750. } // end loadPostProcess
  1751. //-----------------------------------------------------------------------------------------------------------
  1752. AIAttackMoveStateMachine::AIAttackMoveStateMachine(Object *owner, AsciiString name) : StateMachine(owner, name)
  1753. {
  1754. // order matters: first state is the default state.
  1755. defineState( AI_IDLE, newInstance(AIIdleState)( this, AIIdleState::DO_NOT_LOOK_FOR_TARGETS ), AI_IDLE, AI_IDLE );
  1756. defineState( AI_PICK_UP_CRATE, newInstance(AIPickUpCrateState)( this ), AI_IDLE, AI_IDLE );
  1757. defineState( AI_ATTACK_OBJECT, newInstance(AIAttackState)(this, false, true, false, NULL ), AI_IDLE, AI_IDLE);
  1758. }
  1759. //----------------------------------------------------------------------------------------------------------
  1760. AIAttackMoveStateMachine::~AIAttackMoveStateMachine()
  1761. {
  1762. }
  1763. //-------------------------------------------------------------------------------------------------
  1764. //-------------------------------------------------------------------------------------------------
  1765. //-------------------------------------------------------------------------------------------------
  1766. //
  1767. // note - has no crc/xfer as has no member vars. jba.
  1768. //-------------------------------------------------------------------------------------------------
  1769. AIMoveToState::AIMoveToState(StateMachine *machine) : m_isMoveTo(true), AIInternalMoveToState( machine, "AIMoveToState" )
  1770. {
  1771. // m_isMoveTo is a boolean that specifies that this thing is ACTUALLY A MOVE TO.
  1772. // child classes should set it false. (We don't have or want RTTI, so...)
  1773. }
  1774. //----------------------------------------------------------------------------------------------------------
  1775. StateReturnType AIMoveToState::onEnter()
  1776. {
  1777. //Kris: 7/01/03 (Temporary debug hook for units not being able to leave maps)
  1778. if( getMachineOwner()->testStatus( OBJECT_STATUS_RIDER8 ) )
  1779. {
  1780. int blah = 0;
  1781. blah++;
  1782. }
  1783. setAdjustsDestination(true);
  1784. //If we have a goal object and are trying to ignore it as an obstacle...
  1785. //This is used in the case of units trying to get really close.
  1786. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1787. if( getMachineGoalObject() )
  1788. {
  1789. if( ai && getMachineGoalObject()->getID() == ai->getIgnoredObstacleID() )
  1790. {
  1791. setAdjustsDestination( false );
  1792. }
  1793. }
  1794. // if we have a goal object, move to it, otherwise move to goal position
  1795. if (getMachineGoalObject()) {
  1796. m_goalPosition = *getMachineGoalObject()->getPosition();
  1797. if (getMachineOwner()->isKindOf(KINDOF_PROJECTILE)) {
  1798. Real halfHeight = getMachineGoalObject()->getGeometryInfo().getMaxHeightAbovePosition()/2.0f;
  1799. m_goalPosition.z += halfHeight;
  1800. if (getMachineGoalObject()->getPosition()->z < m_goalPosition.z) {
  1801. m_goalPosition.z += halfHeight;
  1802. }
  1803. }
  1804. } else
  1805. m_goalPosition = *getMachineGoalPosition();
  1806. StateReturnType ret = AIInternalMoveToState::onEnter();
  1807. if (getMachineOwner()->getFormationID() != NO_FORMATION_ID) {
  1808. AIGroup *group = ai->getGroup();
  1809. if (group) {
  1810. Real speed = group->getSpeed();
  1811. ai->setDesiredSpeed(speed);
  1812. }
  1813. }
  1814. return ret;
  1815. }
  1816. //----------------------------------------------------------------------------------------------------------
  1817. void AIMoveToState::onExit( StateExitType status )
  1818. {
  1819. AIInternalMoveToState::onExit( status );
  1820. }
  1821. //----------------------------------------------------------------------------------------------------------
  1822. StateReturnType AIMoveToState::update()
  1823. {
  1824. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1825. //Kris: 7/01/03 (Temporary debug hook for units not being able to leave maps)
  1826. if( getMachineOwner()->testStatus( OBJECT_STATUS_RIDER8 ) )
  1827. {
  1828. Int blah = 0;
  1829. blah++;
  1830. }
  1831. UnsignedInt adjustment = ai->getMoodMatrixActionAdjustment(MM_Action_Move);
  1832. if (m_isMoveTo && (adjustment & MAA_Action_To_AttackMove))
  1833. ai->aiAttackMoveToPosition(&m_goalPosition, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  1834. // if we have a goal object, move to it, as it may have moved
  1835. Object* goalObj = getMachineGoalObject();
  1836. Object *obj = getMachineOwner();
  1837. if (goalObj)
  1838. {
  1839. m_goalPosition = *goalObj->getPosition();
  1840. Bool gotPhysics = obj->getPhysics()!=NULL && goalObj->getPhysics()!=NULL;
  1841. Bool isMissile = obj->isKindOf(KINDOF_PROJECTILE);
  1842. if (isMissile) {
  1843. Real halfHeight = getMachineGoalObject()->getGeometryInfo().getMaxHeightAbovePosition()/2.0f;
  1844. m_goalPosition.z += halfHeight;
  1845. Real zDelta = m_goalPosition.z - obj->getPosition()->z;
  1846. if (zDelta>0) {
  1847. m_goalPosition.z += zDelta;
  1848. }
  1849. }
  1850. //gotPhysics = false;
  1851. if (gotPhysics && isMissile && !goalObj->isKindOf(KINDOF_IMMOBILE)) {
  1852. Coord3D ourPos = *obj->getPosition();
  1853. Coord3D delta;
  1854. delta.x = m_goalPosition.x - ourPos.x;
  1855. delta.y = m_goalPosition.y - ourPos.y;
  1856. delta.z = m_goalPosition.z - ourPos.z;
  1857. Real mySpeed = obj->getPhysics()->getVelocityMagnitude();
  1858. Real goalSpeed = goalObj->getPhysics()->getVelocityMagnitude();
  1859. if (mySpeed<5.0f) mySpeed = 5.0f; // avoid divide by 0.
  1860. Real leadDistance = (0.5*delta.length()) * goalSpeed / mySpeed;
  1861. Coord3D dir;
  1862. goalObj->getUnitDirectionVector3D(dir);
  1863. m_goalPosition.x += dir.x*leadDistance;
  1864. m_goalPosition.y += dir.y*leadDistance;
  1865. m_goalPosition.z += dir.z*leadDistance;
  1866. }
  1867. //DEBUG_LOG(("update goal pos to %f %f %f\n",m_goalPosition.x,m_goalPosition.y,m_goalPosition.z));
  1868. } else {
  1869. Bool isMissile = obj->isKindOf(KINDOF_PROJECTILE);
  1870. if (isMissile) {
  1871. // When missiles are moving uphill, they need to start up quickly to clear hills. jba.
  1872. m_goalPosition = *getMachineGoalPosition();
  1873. Real zDelta = m_goalPosition.z - obj->getPosition()->z;
  1874. if (zDelta>0) {
  1875. m_goalPosition.z += zDelta;
  1876. }
  1877. }
  1878. }
  1879. return AIInternalMoveToState::update();
  1880. }
  1881. //----------------------------------------------------------------------------------------------------------
  1882. //----------------------------------------------------------------------------------------------------------
  1883. //----------------------------------------------------------------------------------------------------------
  1884. //
  1885. // note - has no crc/xfer as has no member vars. jba.
  1886. //----------------------------------------------------------------------------------------------------------
  1887. StateReturnType AIMoveOutOfTheWayState::onEnter()
  1888. {
  1889. setAdjustsDestination(true);
  1890. Object *obj = getMachineOwner();
  1891. AIUpdateInterface *ai = obj->getAI();
  1892. if (ai->getPath()==NULL) {
  1893. // Must have existing path.
  1894. return STATE_FAILURE;
  1895. }
  1896. m_goalPosition = *ai->getPath()->getLastNode()->getPosition();
  1897. return AIInternalMoveToState::onEnter();
  1898. }
  1899. //----------------------------------------------------------------------------------------------------------
  1900. Bool AIMoveOutOfTheWayState::computePath()
  1901. {
  1902. Object *obj = getMachineOwner();
  1903. AIUpdateInterface *ai = obj->getAI();
  1904. m_waitingForPath = true;
  1905. if (ai->isBlockedAndStuck()) {
  1906. ai->setCanPathThroughUnits(true);
  1907. return true; // don't repath, just stop.
  1908. }
  1909. return true; // just use the existing path. See above.
  1910. }
  1911. //----------------------------------------------------------------------------------------------------------
  1912. StateReturnType AIMoveOutOfTheWayState::update()
  1913. {
  1914. if (getMachineOwner()->isEffectivelyDead()) {
  1915. return STATE_SUCCESS;
  1916. }
  1917. return AIInternalMoveToState::update();
  1918. }
  1919. //----------------------------------------------------------------------------------------------------------
  1920. void AIMoveOutOfTheWayState::onExit( StateExitType status )
  1921. {
  1922. AIInternalMoveToState::onExit(status);
  1923. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1924. if (ai) {
  1925. ai->destroyPath();
  1926. ai->setCanPathThroughUnits(false);
  1927. ai->clearMoveOutOfWay();
  1928. }
  1929. }
  1930. //----------------------------------------------------------------------------------------------------------
  1931. //----------------------------------------------------------------------------------------------------------
  1932. //----------------------------------------------------------------------------------------------------------
  1933. // ------------------------------------------------------------------------------------------------
  1934. /** CRC */
  1935. // ------------------------------------------------------------------------------------------------
  1936. void AIMoveAndTightenState::crc( Xfer *xfer )
  1937. {
  1938. AIInternalMoveToState::crc(xfer);
  1939. } // end crc
  1940. // ------------------------------------------------------------------------------------------------
  1941. /** Xfer Method */
  1942. // ------------------------------------------------------------------------------------------------
  1943. void AIMoveAndTightenState::xfer( Xfer *xfer )
  1944. {
  1945. // version
  1946. XferVersion currentVersion = 1;
  1947. XferVersion version = currentVersion;
  1948. xfer->xferVersion( &version, currentVersion );
  1949. // extend base class
  1950. AIInternalMoveToState::xfer(xfer);
  1951. xfer->xferInt(&m_okToRepathTimes);
  1952. xfer->xferBool(&m_checkForPath);
  1953. } // end xfer
  1954. // ------------------------------------------------------------------------------------------------
  1955. /** Load post process */
  1956. // ------------------------------------------------------------------------------------------------
  1957. void AIMoveAndTightenState::loadPostProcess( void )
  1958. {
  1959. AIInternalMoveToState::loadPostProcess();
  1960. } // end loadPostProcess
  1961. //----------------------------------------------------------------------------------------------------------
  1962. StateReturnType AIMoveAndTightenState::onEnter()
  1963. {
  1964. setAdjustsDestination(false);
  1965. Object *obj = getMachineOwner();
  1966. AIUpdateInterface *ai = obj->getAI();
  1967. m_okToRepathTimes = 1;
  1968. m_checkForPath = true;
  1969. TheAI->pathfinder()->removeGoal(obj);
  1970. m_goalPosition = *getMachineGoalPosition();
  1971. ai->requestApproachPath(&m_goalPosition);
  1972. return AIInternalMoveToState::onEnter();
  1973. }
  1974. //----------------------------------------------------------------------------------------------------------
  1975. StateReturnType AIMoveAndTightenState::update()
  1976. {
  1977. if (m_checkForPath) {
  1978. Object *obj = getMachineOwner();
  1979. AIUpdateInterface *ai = obj->getAI();
  1980. Path *thePath = ai->getPath();
  1981. if (thePath && !ai->isWaitingForPath()) {
  1982. setAdjustsDestination(true);
  1983. m_checkForPath = false;
  1984. }
  1985. }
  1986. return AIInternalMoveToState::update();
  1987. }
  1988. //----------------------------------------------------------------------------------------------------------
  1989. Bool AIMoveAndTightenState::computePath()
  1990. {
  1991. Object *obj = getMachineOwner();
  1992. AIUpdateInterface *ai = obj->getAI();
  1993. if (ai->isBlockedAndStuck()) {
  1994. if (m_okToRepathTimes>0) {
  1995. m_okToRepathTimes--;
  1996. m_waitingForPath = true;
  1997. ai->requestPath(&m_goalPosition, true);
  1998. return true;
  1999. }
  2000. //DEBUG_LOG(("AIMoveAndTightenState::computePath - stuck, failing.\n"));
  2001. return false; // don't repath for now. jba.
  2002. }
  2003. return true; // just use the existing path. See above.
  2004. }
  2005. //----------------------------------------------------------------------------------------------------------
  2006. //----------------------------------------------------------------------------------------------------------
  2007. //----------------------------------------------------------------------------------------------------------
  2008. StateReturnType AIMoveAwayFromRepulsorsState::onEnter()
  2009. {
  2010. setAdjustsDestination(false);
  2011. Object *obj = getMachineOwner();
  2012. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  2013. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2014. if (!enemy || !ai) {
  2015. return STATE_FAILURE;
  2016. }
  2017. ai->chooseLocomotorSet(LOCOMOTORSET_PANIC);
  2018. if (obj)
  2019. {
  2020. obj->setModelConditionState(MODELCONDITION_PANICKING);
  2021. }
  2022. m_okToRepathTimes = 1;
  2023. m_checkForPath = true;
  2024. TheAI->pathfinder()->removeGoal(obj);
  2025. ai->requestSafePath(enemy->getID());
  2026. return AIInternalMoveToState::onEnter();
  2027. }
  2028. //----------------------------------------------------------------------------------------------------------
  2029. StateReturnType AIMoveAwayFromRepulsorsState::update()
  2030. {
  2031. if (m_checkForPath) {
  2032. Object *obj = getMachineOwner();
  2033. AIUpdateInterface *ai = obj->getAI();
  2034. Path *thePath = ai->getPath();
  2035. if (thePath && !ai->isWaitingForPath()) {
  2036. m_goalPosition = *thePath->getLastNode()->getPosition();
  2037. setAdjustsDestination(false);
  2038. m_checkForPath = false;
  2039. }
  2040. }
  2041. return AIInternalMoveToState::update();
  2042. }
  2043. //----------------------------------------------------------------------------------------------------------
  2044. Bool AIMoveAwayFromRepulsorsState::computePath()
  2045. {
  2046. if (m_okToRepathTimes>0) {
  2047. m_okToRepathTimes--;
  2048. return true;
  2049. }
  2050. return false; // don't recompute path, just stop moving.
  2051. }
  2052. //----------------------------------------------------------------------------------------------------------
  2053. void AIMoveAwayFromRepulsorsState::onExit( StateExitType status )
  2054. {
  2055. AIInternalMoveToState::onExit( status );
  2056. Object *obj = getMachineOwner();
  2057. if (obj)
  2058. {
  2059. obj->clearModelConditionState(MODELCONDITION_PANICKING);
  2060. }
  2061. }
  2062. //----------------------------------------------------------------------------------------------------------
  2063. //----------------------------------------------------------------------------------------------------------
  2064. //----------------------------------------------------------------------------------------------------------
  2065. /**
  2066. * Returns true if we can pursue the unit. Requires that :
  2067. * 1. We are faster than the other unit.
  2068. * 2. The other unit is moving.
  2069. * 3. The other unit is moving away from us.
  2070. */
  2071. static Bool canPursue(Object *source, Weapon *weapon, Object *victim)
  2072. {
  2073. /* This state is only used if the target is moving away from us, and has physics. */
  2074. if (!victim->getPhysics()) {
  2075. return false;
  2076. }
  2077. AIUpdateInterface *ai = source->getAI();
  2078. if (!ai) {
  2079. return false;
  2080. }
  2081. // Have to have a turret to pursue.
  2082. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2083. if (tur == TURRET_INVALID) {
  2084. return false;
  2085. }
  2086. if (TheAI->getAiData()->m_aiCrushesInfantry) {
  2087. if ( source->getControllingPlayer() &&
  2088. (source->getControllingPlayer()->getPlayerType() == PLAYER_COMPUTER) &&
  2089. source->canCrushOrSquish(victim) ) {
  2090. return true; // Always pursue if we can squish.
  2091. }
  2092. }
  2093. if (weapon->isTooClose(source, victim)) {
  2094. return false; // Don't chase it if we are already too close.
  2095. }
  2096. Real ourMaxSpeed = source->getAI()->getCurLocomotorSpeed();
  2097. Real victimSpeed = victim->getPhysics()->getForwardSpeed2D();
  2098. if (victimSpeed >= ourMaxSpeed) {
  2099. return false; // we can't catch them.
  2100. }
  2101. if (victimSpeed < ourMaxSpeed/10) {
  2102. return false; // They aren't moving very fast, so don't chase.
  2103. }
  2104. Real dx = victim->getPosition()->x - source->getPosition()->x;
  2105. Real dy = victim->getPosition()->y - source->getPosition()->y;
  2106. Coord3D victimVector = *victim->getUnitDirectionVector2D();
  2107. if (dx*victimVector.x + dy*victimVector.y < 0 ) {
  2108. return false; // they are moving towards us.
  2109. }
  2110. return true;
  2111. }
  2112. //----------------------------------------------------------------------------------------------------------
  2113. /**
  2114. * Compute a valid spot to fire our weapon from.
  2115. * Result in m_goalPosition.
  2116. * Return false if can't find a good spot.
  2117. */
  2118. Bool AIAttackApproachTargetState::computePath()
  2119. {
  2120. Bool forceRepath = false;
  2121. // if we're immobile we can't possibly approach the target
  2122. if( getMachineOwner()->isMobile() == false )
  2123. return false;
  2124. //CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - begin for object %d\n", getMachineOwner()->getID()));
  2125. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2126. if (ai->isBlockedAndStuck())
  2127. {
  2128. forceRepath = true;
  2129. // Intense logging. jba
  2130. //CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - stuck, recomputing for object %d\n", getMachineOwner()->getID()));
  2131. }
  2132. if (m_waitingForPath) return true;
  2133. if (!forceRepath && ai->getPath()==NULL && !ai->isWaitingForPath())
  2134. {
  2135. forceRepath = true;
  2136. }
  2137. // force minimum time between recomputation
  2138. /// @todo Unify recomputation conditions & account for obj ID so everyone doesnt compute on the same frame (MSB)
  2139. if (!forceRepath && TheGameLogic->getFrame() - m_approachTimestamp < MIN_RECOMPUTE_TIME)
  2140. {
  2141. //CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because of min time for object %d\n", getMachineOwner()->getID()));
  2142. return true;
  2143. }
  2144. m_approachTimestamp = TheGameLogic->getFrame();
  2145. // if we have a goal object, move to it, otherwise move to goal position
  2146. if (getMachineGoalObject())
  2147. {
  2148. Object* source = getMachineOwner();
  2149. // if our victim's position hasn't changed, don't re-path
  2150. if (!forceRepath && isSamePosition(source->getPosition(), &m_prevVictimPos, getMachineGoalObject()->getPosition() ))
  2151. {
  2152. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because victim in same place for object %d\n", getMachineOwner()->getID()));
  2153. return true;
  2154. }
  2155. Weapon* weapon = source->getCurrentWeapon();
  2156. if (!weapon)
  2157. {
  2158. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because of no weapon for object %d\n", getMachineOwner()->getID()));
  2159. return false;
  2160. }
  2161. // remember where we think our victim is, so if it moves, we can re-path
  2162. Object *victim = getMachineGoalObject();
  2163. m_prevVictimPos = *victim->getPosition();
  2164. if (canPursue(source, weapon, victim))
  2165. {
  2166. return false; // break out, and do the pursuit state.
  2167. }
  2168. setAdjustsDestination(true);
  2169. if (weapon->isContactWeapon())
  2170. {
  2171. // Weapon is basically a contact weapon, so let the attacker pathfind into the target.
  2172. ai->ignoreObstacle(victim);
  2173. setAdjustsDestination(false); // We want to run into the target.
  2174. ai->setPathExtraDistance(10*PATHFIND_CELL_SIZE_F); // We don't want it to slow down.
  2175. }
  2176. m_goalPosition = m_prevVictimPos;
  2177. m_waitingForPath = true;
  2178. Coord3D pos;
  2179. victim->getGeometryInfo().getCenterPosition( *victim->getPosition(), pos );
  2180. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - requestAttackPath() for object %d\n", getMachineOwner()->getID()));
  2181. ai->requestAttackPath(victim->getID(), &pos );
  2182. m_stopIfInRange = false; // we have calculated a position to shoot from, so go there.
  2183. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing after repathing for object %d\n", getMachineOwner()->getID()));
  2184. return true;
  2185. }
  2186. else
  2187. {
  2188. // goal position.
  2189. setAdjustsDestination(true);
  2190. m_stopIfInRange = false; // Attack position is used by missiles, and they hit the position.
  2191. m_goalPosition = *getMachineGoalPosition();
  2192. if (!forceRepath)
  2193. {
  2194. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because we're aiming for a fixed position for object %d\n", getMachineOwner()->getID()));
  2195. return true; // fixed positions don't move.
  2196. }
  2197. // must use computeAttackPath so that min ranges are considered.
  2198. m_waitingForPath = true;
  2199. ai->requestAttackPath(INVALID_ID, &m_goalPosition);
  2200. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing after repathing at a fixed position for object %d\n", getMachineOwner()->getID()));
  2201. return true;
  2202. }
  2203. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing at end of function for object %d\n", getMachineOwner()->getID()));
  2204. return true;
  2205. }
  2206. // ------------------------------------------------------------------------------------------------
  2207. /** CRC */
  2208. // ------------------------------------------------------------------------------------------------
  2209. void AIAttackApproachTargetState::crc( Xfer *xfer )
  2210. {
  2211. AIInternalMoveToState::crc(xfer);
  2212. } // end crc
  2213. // ------------------------------------------------------------------------------------------------
  2214. /** Xfer Method */
  2215. // ------------------------------------------------------------------------------------------------
  2216. void AIAttackApproachTargetState::xfer( Xfer *xfer )
  2217. {
  2218. // version
  2219. XferVersion currentVersion = 1;
  2220. XferVersion version = currentVersion;
  2221. xfer->xferVersion( &version, currentVersion );
  2222. // extend base class
  2223. AIInternalMoveToState::xfer( xfer );
  2224. xfer->xferCoord3D(&m_prevVictimPos);
  2225. xfer->xferUnsignedInt(&m_approachTimestamp);
  2226. xfer->xferBool(&m_follow);
  2227. xfer->xferBool(&m_isAttackingObject);
  2228. xfer->xferBool(&m_stopIfInRange);
  2229. xfer->xferBool(&m_isInitialApproach);
  2230. } // end xfer
  2231. // ------------------------------------------------------------------------------------------------
  2232. /** Load post process */
  2233. // ------------------------------------------------------------------------------------------------
  2234. void AIAttackApproachTargetState::loadPostProcess( void )
  2235. {
  2236. // extend base class
  2237. AIInternalMoveToState::loadPostProcess();
  2238. } // end loadPostProcess
  2239. //----------------------------------------------------------------------------------------------------------
  2240. StateReturnType AIAttackApproachTargetState::onEnter()
  2241. {
  2242. // contained by AIAttackState, so no separate timer
  2243. // urg. hacky. if we are a projectile, turn on precise z-pos.
  2244. //CRCDEBUG_LOG(("AIAttackApproachTargetState::onEnter() - object %d\n", getMachineOwner()->getID()));
  2245. Object* source = getMachineOwner();
  2246. AIUpdateInterface* ai = source->getAI();
  2247. if (source->isKindOf(KINDOF_PROJECTILE))
  2248. {
  2249. if (ai->getCurLocomotor())
  2250. ai->getCurLocomotor()->setUsePreciseZPos(true);
  2251. }
  2252. if (getMachine()->isGoalObjectDestroyed())
  2253. {
  2254. return STATE_SUCCESS; // Already killed victim.
  2255. }
  2256. //If our object is deployed, can't tell him to move!
  2257. //if( source && source->testStatus( OBJECT_STATUS_DEPLOYED ) )
  2258. // {
  2259. // return STATE_SUCCESS;
  2260. // }
  2261. m_prevVictimPos.x = 0.0f;
  2262. m_prevVictimPos.y = 0.0f;
  2263. m_prevVictimPos.z = 0.0f;
  2264. m_approachTimestamp = -MIN_RECOMPUTE_TIME;
  2265. // See if we're close enough.
  2266. Object *victim = getMachineGoalObject();
  2267. if (victim)
  2268. {
  2269. Weapon* weapon = source->getCurrentWeapon();
  2270. if (!weapon)
  2271. {
  2272. return STATE_FAILURE;
  2273. }
  2274. if (weapon->isWithinAttackRange(source, victim))
  2275. {
  2276. Bool viewBlocked = false;
  2277. if (source && victim && ai->isDoingGroundMovement() && !victim->isSignificantlyAboveTerrain())
  2278. {
  2279. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), victim, *victim->getPosition());
  2280. }
  2281. if (!viewBlocked)
  2282. {
  2283. return STATE_SUCCESS;
  2284. }
  2285. }
  2286. // Check here: If we are a player, and we got to this state via an ai command (ie we auto-acquired),
  2287. // we don't want to chase the unit. isAllowedToChase is set when we are in a deploy and attack state (troop crawler).
  2288. // Kris (July 2003): If we are retaliating... don't fail out!
  2289. if( ai->getCurrentStateID() != AI_GUARD_RETALIATE )
  2290. {
  2291. if (source->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN)
  2292. {
  2293. if (ai->getLastCommandSource() == CMD_FROM_AI && !ai->isAllowedToChase() )
  2294. {
  2295. if (!weapon->isContactWeapon())
  2296. {
  2297. return STATE_FAILURE;
  2298. }
  2299. }
  2300. } else {
  2301. // Computer player. Don't chase aircraft, unless we're hunting. jba [8/27/2003]
  2302. Bool hunt = ai->getCurrentStateID() == AI_HUNT;
  2303. if (!hunt && victim->isKindOf(KINDOF_AIRCRAFT) && victim->isAirborneTarget())
  2304. {
  2305. return STATE_FAILURE;
  2306. }
  2307. }
  2308. }
  2309. if (canPursue(source, weapon, victim))
  2310. {
  2311. return STATE_SUCCESS; // break out, and do the pursuit state.
  2312. }
  2313. } else {
  2314. // Attacking a position. For a varitey of reasons, we need to destroy any existing path or we spin. jba. [8/25/2003]
  2315. ai->destroyPath();
  2316. }
  2317. // If we have a turret, start aiming.
  2318. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2319. if (tur != TURRET_INVALID)
  2320. {
  2321. if (m_isAttackingObject)
  2322. {
  2323. ai->setTurretTargetObject(tur, victim, m_isForceAttacking);
  2324. }
  2325. else
  2326. {
  2327. ai->setTurretTargetPosition(tur, getMachineGoalPosition());
  2328. }
  2329. }
  2330. // find a good spot to shoot from
  2331. //CRCDEBUG_LOG(("AIAttackApproachTargetState::onEnter() - calling computePath() for object %d\n", getMachineOwner()->getID()));
  2332. if (computePath() == false)
  2333. return STATE_FAILURE;
  2334. setAdjustsDestination(false);
  2335. StateReturnType ret = AIInternalMoveToState::onEnter();
  2336. setAdjustsDestination(true);
  2337. return ret;
  2338. }
  2339. //----------------------------------------------------------------------------------------------------------
  2340. StateReturnType AIAttackApproachTargetState::updateInternal()
  2341. {
  2342. AIUpdateInterface* ai = getMachineOwner()->getAI();
  2343. //CRCDEBUG_LOG(("AIAttackApproachTargetState::updateInternal() - object %d\n", getMachineOwner()->getID()));
  2344. if (getMachine()->isGoalObjectDestroyed())
  2345. {
  2346. ai->notifyVictimIsDead();
  2347. ai->setCurrentVictim(NULL);
  2348. return STATE_FAILURE;
  2349. }
  2350. m_stopIfInRange = !ai->isAttackPath();
  2351. StateReturnType code = STATE_FAILURE;
  2352. Object* source = getMachineOwner();
  2353. Weapon* weapon = source->getCurrentWeapon();
  2354. Object *victim = getMachineGoalObject();
  2355. if (victim)
  2356. {
  2357. if (source->getControllingPlayer()->getPlayerType() == PLAYER_COMPUTER)
  2358. {
  2359. Bool hunt = ai->getCurrentStateID() == AI_HUNT;
  2360. // Computer player. Don't chase aircraft unless hunting. jba [8/27/2003]
  2361. if (!hunt && victim->isKindOf(KINDOF_AIRCRAFT) && victim->isAirborneTarget())
  2362. {
  2363. return STATE_FAILURE;
  2364. }
  2365. }
  2366. if( victim->testStatus( OBJECT_STATUS_STEALTHED ) && !victim->testStatus( OBJECT_STATUS_DETECTED ) && !victim->testStatus( OBJECT_STATUS_DISGUISED ) )
  2367. {
  2368. return STATE_FAILURE; // If obj is stealthed, can no longer approach.
  2369. }
  2370. ai->setCurrentVictim(victim);
  2371. // Attacking an object.
  2372. if (weapon && weapon->isContactWeapon() && weapon->isWithinAttackRange(source, victim))
  2373. {
  2374. return STATE_SUCCESS;
  2375. }
  2376. if (m_stopIfInRange && weapon && weapon->isWithinAttackRange(source, victim))
  2377. {
  2378. Bool viewBlocked = false;
  2379. if (victim && ai->isDoingGroundMovement() && !victim->isSignificantlyAboveTerrain())
  2380. {
  2381. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), victim, *victim->getPosition());
  2382. }
  2383. if (!viewBlocked)
  2384. {
  2385. return STATE_SUCCESS;
  2386. }
  2387. }
  2388. // find a good spot to shoot from
  2389. //CRCDEBUG_LOG(("AIAttackApproachTargetState::updateInternal() - calling computePath() to victim for object %d\n", getMachineOwner()->getID()));
  2390. if (computePath() == false)
  2391. return STATE_SUCCESS;
  2392. code = AIInternalMoveToState::update();
  2393. if (code != STATE_CONTINUE)
  2394. {
  2395. return STATE_SUCCESS; // Always return state success, as state failure exits the attack.
  2396. // we may need to aim & do another approach if the target moved. jba.
  2397. }
  2398. }
  2399. else
  2400. {
  2401. // Attacking a position.
  2402. // find a good spot to shoot from
  2403. //CRCDEBUG_LOG(("AIAttackApproachTargetState::updateInternal() - calling computePath() to position for object %d\n", getMachineOwner()->getID()));
  2404. if (m_stopIfInRange && weapon && weapon->isWithinAttackRange(source, &m_goalPosition))
  2405. {
  2406. Bool viewBlocked = false;
  2407. if ( ai->isDoingGroundMovement() )
  2408. {
  2409. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), NULL, m_goalPosition);
  2410. }
  2411. if (!viewBlocked)
  2412. {
  2413. return STATE_SUCCESS;
  2414. }
  2415. }
  2416. if (computePath() == false)
  2417. return STATE_FAILURE;
  2418. code = AIInternalMoveToState::update();
  2419. }
  2420. return code;
  2421. }
  2422. //----------------------------------------------------------------------------------------------------------
  2423. StateReturnType AIAttackApproachTargetState::update()
  2424. {
  2425. // contained by AIAttackState, so no separate timer
  2426. StateReturnType code = updateInternal();
  2427. Object* source = getMachineOwner();
  2428. AIUpdateInterface *ai = source->getAI();
  2429. if (m_follow && m_isAttackingObject)
  2430. {
  2431. // Basically, if the object is alive, we continue, in case the target moves.
  2432. Object* victim = getMachineGoalObject();
  2433. if (source && victim && source->isMobile() && !victim->getTemplate()->isKindOf(KINDOF_IMMOBILE))
  2434. {
  2435. if (code != STATE_CONTINUE)
  2436. {
  2437. m_isInitialApproach = false;
  2438. }
  2439. // Object is still alive (and so are we)
  2440. // It could move (and so can we), so just continue & keep checking.
  2441. code = STATE_CONTINUE;
  2442. }
  2443. }
  2444. if (m_isInitialApproach)
  2445. {
  2446. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2447. if (tur != TURRET_INVALID)
  2448. {
  2449. Object *temporaryTarget = ai->getNextMoodTarget( true, false );
  2450. if (temporaryTarget)
  2451. {
  2452. ai->setTurretTargetObject(tur, temporaryTarget, m_isForceAttacking);
  2453. }
  2454. }
  2455. }
  2456. return code;
  2457. }
  2458. //----------------------------------------------------------------------------------------------------------
  2459. void AIAttackApproachTargetState::onExit( StateExitType status )
  2460. {
  2461. // contained by AIAttackState, so no separate timer
  2462. AIInternalMoveToState::onExit( status );
  2463. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2464. Object *obj = getMachineOwner();
  2465. if (ai) {
  2466. ai->ignoreObstacle(NULL);
  2467. // Per JohnA, this state should not be calling ai->destroyPath, because we can have spastic users
  2468. // that click the target repeadedly. This will prevent the unit from stuttering for said spastic
  2469. // users.
  2470. // ai->destroyPath();
  2471. // urg. hacky. if we are a projectile, reset precise z-pos.
  2472. if (getMachineOwner()->isKindOf(KINDOF_PROJECTILE))
  2473. {
  2474. if (ai && ai->getCurLocomotor())
  2475. ai->getCurLocomotor()->setUsePreciseZPos(false);
  2476. }
  2477. if (ai->isDoingGroundMovement()) {
  2478. Real dx = m_goalPosition.x-obj->getPosition()->x;
  2479. Real dy = m_goalPosition.y-obj->getPosition()->y;
  2480. if (dx*dx+dy*dy<PATHFIND_CELL_SIZE_F*PATHFIND_CELL_SIZE_F*0.125)
  2481. {
  2482. // We are doing accurate ground movement, so make sure we end exactly at the goal.
  2483. obj->setPosition(&m_goalPosition);
  2484. }
  2485. }
  2486. }
  2487. m_isInitialApproach = false; // We only want to allow turreted things to fire at enemies during their
  2488. // first approach
  2489. }
  2490. //----------------------------------------------------------------------------------------------------------
  2491. //----------------------------------------------------------------------------------------------------------
  2492. //----------------------------------------------------------------------------------------------------------
  2493. //----------------------------------------------------------------------------------------------------------
  2494. /**
  2495. * Compute a valid spot to fire our weapon from.
  2496. * Result in m_goalPosition.
  2497. * Return false if can't find a good spot.
  2498. */
  2499. Bool AIAttackPursueTargetState::computePath()
  2500. {
  2501. Bool forceRepath = false;
  2502. // if we're immobile we can't possibly approach the target
  2503. if( getMachineOwner()->isMobile() == false )
  2504. return false;
  2505. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2506. if (ai->isBlockedAndStuck())
  2507. {
  2508. return false;
  2509. }
  2510. if (m_waitingForPath) return true;
  2511. if (!forceRepath && ai->getPath()==NULL && !ai->isWaitingForPath())
  2512. {
  2513. forceRepath = true;
  2514. }
  2515. // force minimum time between recomputation
  2516. /// @todo Unify recomputation conditions & account for obj ID so everyone doesnt compute on the same frame (MSB)
  2517. if (!forceRepath && TheGameLogic->getFrame() - m_approachTimestamp < MIN_RECOMPUTE_TIME)
  2518. {
  2519. return true;
  2520. }
  2521. m_approachTimestamp = TheGameLogic->getFrame();
  2522. DEBUG_ASSERTLOG(getMachineGoalObject(), ("***************************Should only be pursuing objects. jba"));
  2523. // if we have a goal object, move to it, otherwise fail & continue to AIAttackApproachTargetState
  2524. if (getMachineGoalObject())
  2525. {
  2526. Object* source = getMachineOwner();
  2527. // if our victim's position hasn't changed, don't re-path
  2528. if (!forceRepath && isSamePosition(source->getPosition(), &m_prevVictimPos, getMachineGoalObject()->getPosition() ))
  2529. return true;
  2530. Weapon* weapon = source->getCurrentWeapon();
  2531. if (!weapon)
  2532. {
  2533. return false;
  2534. }
  2535. if (!canPursue(source, weapon, getMachineGoalObject())) {
  2536. return false;
  2537. }
  2538. // remember where we think our victim is, so if it moves, we can re-path
  2539. Object *victim = getMachineGoalObject();
  2540. m_prevVictimPos = *victim->getPosition();
  2541. setAdjustsDestination(true);
  2542. m_goalPosition = m_prevVictimPos;
  2543. m_waitingForPath = true;
  2544. ai->requestPath(&m_goalPosition, false);
  2545. m_stopIfInRange = false; // we have calculated a position to shoot from, so go there.
  2546. return true;
  2547. }
  2548. return false;
  2549. }
  2550. // ------------------------------------------------------------------------------------------------
  2551. /** CRC */
  2552. // ------------------------------------------------------------------------------------------------
  2553. void AIAttackPursueTargetState::crc( Xfer *xfer )
  2554. {
  2555. AIInternalMoveToState::crc(xfer);
  2556. } // end crc
  2557. // ------------------------------------------------------------------------------------------------
  2558. /** Xfer Method */
  2559. // ------------------------------------------------------------------------------------------------
  2560. void AIAttackPursueTargetState::xfer( Xfer *xfer )
  2561. {
  2562. // version
  2563. XferVersion currentVersion = 1;
  2564. XferVersion version = currentVersion;
  2565. xfer->xferVersion( &version, currentVersion );
  2566. // extend base class
  2567. AIInternalMoveToState::xfer( xfer );
  2568. xfer->xferCoord3D(&m_prevVictimPos);
  2569. xfer->xferUnsignedInt(&m_approachTimestamp);
  2570. xfer->xferBool(&m_follow);
  2571. xfer->xferBool(&m_isAttackingObject);
  2572. xfer->xferBool(&m_stopIfInRange);
  2573. xfer->xferBool(&m_isInitialApproach);
  2574. } // end xfer
  2575. // ------------------------------------------------------------------------------------------------
  2576. /** Load post process */
  2577. // ------------------------------------------------------------------------------------------------
  2578. void AIAttackPursueTargetState::loadPostProcess( void )
  2579. {
  2580. // extend base class
  2581. AIInternalMoveToState::loadPostProcess();
  2582. } // end loadPostProcess
  2583. //----------------------------------------------------------------------------------------------------------
  2584. StateReturnType AIAttackPursueTargetState::onEnter()
  2585. {
  2586. // contained by AIAttackState, so no separate timer
  2587. // If we return STATE_SUCCESS or STATE_FAILURE, we proceed to AIAttackApproachTargetState.
  2588. Object* source = getMachineOwner();
  2589. AIUpdateInterface* ai = source->getAI();
  2590. if (source->isKindOf(KINDOF_PROJECTILE))
  2591. {
  2592. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - is a projectile for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2593. return STATE_SUCCESS; // Projectiles go directly to AIAttackApproachTargetState.
  2594. }
  2595. if (getMachine()->isGoalObjectDestroyed())
  2596. {
  2597. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - goal object is destroyed for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2598. return STATE_SUCCESS; // Already killed victim.
  2599. }
  2600. if (!m_isAttackingObject) {
  2601. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - not attacking for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2602. return STATE_SUCCESS; // only pursue objects - positions don't move.
  2603. }
  2604. setAdjustsDestination(false);
  2605. // Check here: If we are a player, and we got to this state via an ai command (ie we auto-acquired),
  2606. // we don't want to chase the unit.
  2607. // Kris (July 2003): If we are retaliating... don't succeed out!
  2608. if( ai->getCurrentStateID() != AI_GUARD_RETALIATE )
  2609. {
  2610. if (source->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN)
  2611. {
  2612. if (ai->getLastCommandSource() == CMD_FROM_AI)
  2613. {
  2614. return STATE_SUCCESS;
  2615. }
  2616. }
  2617. }
  2618. m_prevVictimPos.x = 0.0f;
  2619. m_prevVictimPos.y = 0.0f;
  2620. m_prevVictimPos.z = 0.0f;
  2621. m_approachTimestamp = -MIN_RECOMPUTE_TIME;
  2622. // See if we're close enough.
  2623. Object *victim = getMachineGoalObject();
  2624. if (victim) {
  2625. Weapon* weapon = source->getCurrentWeapon();
  2626. if (!weapon)
  2627. {
  2628. return STATE_FAILURE;
  2629. }
  2630. if (!canPursue(source, weapon, victim) )
  2631. {
  2632. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - can't pursue for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2633. return STATE_SUCCESS;
  2634. }
  2635. } else {
  2636. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - no victim for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2637. return STATE_SUCCESS; // gotta have a victim.
  2638. }
  2639. // If we have a turret, start aiming.
  2640. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2641. if (tur != TURRET_INVALID)
  2642. {
  2643. ai->setTurretTargetObject(tur, victim, m_isForceAttacking);
  2644. } else {
  2645. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - no turret for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2646. return STATE_SUCCESS; // we only pursue with turrets, as non-turreted weapons can't fire on the run.
  2647. }
  2648. // find a good spot to shoot from
  2649. if (computePath() == false)
  2650. return STATE_SUCCESS;
  2651. return AIInternalMoveToState::onEnter();
  2652. }
  2653. //----------------------------------------------------------------------------------------------------------
  2654. StateReturnType AIAttackPursueTargetState::updateInternal()
  2655. {
  2656. AIUpdateInterface* ai = getMachineOwner()->getAI();
  2657. if (getMachine()->isGoalObjectDestroyed())
  2658. {
  2659. ai->notifyVictimIsDead();
  2660. ai->setCurrentVictim(NULL);
  2661. return STATE_FAILURE;
  2662. }
  2663. m_stopIfInRange = false;
  2664. Object* source = getMachineOwner();
  2665. StateReturnType code = STATE_FAILURE;
  2666. Object *victim = getMachineGoalObject();
  2667. if (victim)
  2668. {
  2669. if( victim->testStatus( OBJECT_STATUS_STEALTHED ) && !victim->testStatus( OBJECT_STATUS_DETECTED ) && !victim->testStatus( OBJECT_STATUS_DISGUISED ) )
  2670. {
  2671. return STATE_FAILURE; // If obj is stealthed, can no longer pursue.
  2672. }
  2673. ai->setCurrentVictim(victim);
  2674. // Attacking an object.
  2675. // find a good spot to shoot from
  2676. if (computePath() == false)
  2677. return STATE_FAILURE;
  2678. code = AIInternalMoveToState::update();
  2679. if (code != STATE_CONTINUE)
  2680. {
  2681. //CRCDEBUG_LOG(("AIAttackPursueTargetState::updateInternal() - failed internal update() for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2682. return STATE_SUCCESS; // Always return state success, as state failure exits the attack.
  2683. // we may need to aim & do another approach if the target moved. jba.
  2684. }
  2685. Weapon* weapon = source->getCurrentWeapon();
  2686. if (!weapon)
  2687. return STATE_FAILURE;
  2688. // If we have a turret, start aiming.
  2689. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2690. if (tur == TURRET_INVALID)
  2691. {
  2692. //CRCDEBUG_LOG(("AIAttackPursueTargetState::updateInternal() - no turret for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2693. return STATE_SUCCESS; // We currently only pursue with a turret weapon.
  2694. }
  2695. Bool viewBlocked = false;
  2696. if (ai->isDoingGroundMovement() && !victim->isSignificantlyAboveTerrain())
  2697. {
  2698. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), victim, *victim->getPosition());
  2699. }
  2700. if (!viewBlocked && victim->getPhysics() && weapon->isWithinAttackRange(source, victim)) {
  2701. // If we have a turret, start aiming.
  2702. ai->setTurretTargetObject(tur, victim, m_isForceAttacking);
  2703. // match speeds;
  2704. m_isInitialApproach = false;
  2705. Real victimSpeed = victim->getPhysics()->getForwardSpeed2D();
  2706. if (weapon->isGoalPosWithinAttackRange(source, source->getPosition(), victim, victim->getPosition())){
  2707. victimSpeed *= 0.95f;
  2708. }
  2709. if (source->canCrushOrSquish(victim)) {
  2710. victimSpeed = FAST_AS_POSSIBLE;
  2711. }
  2712. ai->setDesiredSpeed(victimSpeed);
  2713. // Really intense debug info. jba.
  2714. // DEBUG_LOG(("VS %f, OS %f, goal %f\n", victim->getPhysics()->getForwardSpeed2D(), source->getPhysics()->getForwardSpeed2D(), victimSpeed));
  2715. } else {
  2716. ai->setDesiredSpeed(FAST_AS_POSSIBLE);
  2717. }
  2718. }
  2719. return code;
  2720. }
  2721. //----------------------------------------------------------------------------------------------------------
  2722. StateReturnType AIAttackPursueTargetState::update()
  2723. {
  2724. // contained by AIAttackState, so no separate timer
  2725. StateReturnType code = updateInternal();
  2726. Object* source = getMachineOwner();
  2727. AIUpdateInterface *ai = source->getAI();
  2728. if (m_isInitialApproach)
  2729. {
  2730. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2731. if (tur != TURRET_INVALID)
  2732. {
  2733. Object *temporaryTarget = ai->getNextMoodTarget( true, false );
  2734. if (temporaryTarget)
  2735. {
  2736. ai->setTurretTargetObject(tur, temporaryTarget, m_isForceAttacking);
  2737. }
  2738. }
  2739. }
  2740. return code;
  2741. }
  2742. //----------------------------------------------------------------------------------------------------------
  2743. void AIAttackPursueTargetState::onExit( StateExitType status )
  2744. {
  2745. // contained by AIAttackState, so no separate timer
  2746. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onExit() for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2747. AIInternalMoveToState::onExit( status );
  2748. m_isInitialApproach = false; // We only want to allow turreted things to fire at enemies during their
  2749. // first approach
  2750. }
  2751. //----------------------------------------------------------------------------------------------------------
  2752. //----------------------------------------------------------------------------------------------------------
  2753. //----------------------------------------------------------------------------------------------------------
  2754. //----------------------------------------------------------------------------------------------------------
  2755. Bool AIPickUpCrateState::computePath()
  2756. {
  2757. return AIInternalMoveToState::computePath();
  2758. }
  2759. // ------------------------------------------------------------------------------------------------
  2760. /** CRC */
  2761. // ------------------------------------------------------------------------------------------------
  2762. void AIPickUpCrateState::crc( Xfer *xfer )
  2763. {
  2764. AIInternalMoveToState::crc(xfer);
  2765. } // end crc
  2766. // ------------------------------------------------------------------------------------------------
  2767. /** Xfer Method */
  2768. // ------------------------------------------------------------------------------------------------
  2769. void AIPickUpCrateState::xfer( Xfer *xfer )
  2770. {
  2771. // version
  2772. XferVersion currentVersion = 1;
  2773. XferVersion version = currentVersion;
  2774. xfer->xferVersion( &version, currentVersion );
  2775. // extend base class
  2776. AIInternalMoveToState::xfer( xfer );
  2777. xfer->xferInt(&m_delayCounter);
  2778. xfer->xferCoord3D(&m_goalPosition);
  2779. } // end xfer
  2780. // ------------------------------------------------------------------------------------------------
  2781. /** Load post process */
  2782. // ------------------------------------------------------------------------------------------------
  2783. void AIPickUpCrateState::loadPostProcess( void )
  2784. {
  2785. // extend base class
  2786. AIInternalMoveToState::loadPostProcess();
  2787. } // end loadPostProcess
  2788. //----------------------------------------------------------------------------------------------------------
  2789. StateReturnType AIPickUpCrateState::onEnter()
  2790. {
  2791. Object* goalObj = getMachineGoalObject();
  2792. if (!goalObj) {
  2793. return STATE_FAILURE;
  2794. }
  2795. setAdjustsDestination(true);
  2796. m_goalPosition = *goalObj->getPosition();
  2797. m_delayCounter = 3;
  2798. return STATE_CONTINUE;
  2799. }
  2800. //----------------------------------------------------------------------------------------------------------
  2801. void AIPickUpCrateState::onExit( StateExitType status )
  2802. {
  2803. AIInternalMoveToState::onExit( status );
  2804. }
  2805. //----------------------------------------------------------------------------------------------------------
  2806. StateReturnType AIPickUpCrateState::update()
  2807. {
  2808. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  2809. if (m_delayCounter) {
  2810. m_delayCounter--;
  2811. if (m_delayCounter == 0) {
  2812. return AIInternalMoveToState::onEnter();
  2813. }
  2814. return STATE_CONTINUE;
  2815. }
  2816. // do movement
  2817. StateReturnType status = AIInternalMoveToState::update();
  2818. return status;
  2819. }
  2820. //----------------------------------------------------------------------------------------------------------
  2821. //----------------------------------------------------------------------------------------------------------
  2822. //----------------------------------------------------------------------------------------------------------
  2823. // ------------------------------------------------------------------------------------------------
  2824. /** CRC */
  2825. // ------------------------------------------------------------------------------------------------
  2826. void AIFollowPathState::crc( Xfer *xfer )
  2827. {
  2828. AIInternalMoveToState::crc(xfer);
  2829. } // end crc
  2830. // ------------------------------------------------------------------------------------------------
  2831. /** Xfer Method */
  2832. // ------------------------------------------------------------------------------------------------
  2833. void AIFollowPathState::xfer( Xfer *xfer )
  2834. {
  2835. // version
  2836. XferVersion currentVersion = 1;
  2837. XferVersion version = currentVersion;
  2838. xfer->xferVersion( &version, currentVersion );
  2839. AIInternalMoveToState::xfer(xfer);
  2840. xfer->xferInt(&m_index);
  2841. xfer->xferBool(&m_adjustFinal);
  2842. xfer->xferBool(&m_adjustFinalOverride);
  2843. } // end xfer
  2844. // ------------------------------------------------------------------------------------------------
  2845. /** Load post process */
  2846. // ------------------------------------------------------------------------------------------------
  2847. void AIFollowPathState::loadPostProcess( void )
  2848. {
  2849. AIInternalMoveToState::loadPostProcess();
  2850. } // end loadPostProcess
  2851. //----------------------------------------------------------------------------------------------------------
  2852. StateReturnType AIFollowPathState::onEnter()
  2853. {
  2854. Object *obj = getMachineOwner();
  2855. AIUpdateInterface *ai = obj->getAI();
  2856. m_index = 0;
  2857. const Coord3D *pos = ai->friend_getGoalPathPosition( m_index );
  2858. if (pos == NULL)
  2859. return STATE_FAILURE;
  2860. // set initial movement goal
  2861. m_goalPosition = *pos;
  2862. const Coord3D *nextPos = ai->friend_getGoalPathPosition( m_index+1 );
  2863. m_adjustFinal = true;
  2864. //Assign this value to the AIUpdateInterface so object's can access this value while
  2865. //determine which waypoints to plot in the waypoint renderer.
  2866. ai->friend_setCurrentGoalPathIndex( m_index );
  2867. if (getID() == AI_FOLLOW_EXITPRODUCTION_PATH) {
  2868. ai->setCanPathThroughUnits(true);
  2869. setAdjustsDestination(false);
  2870. m_adjustFinal = true;
  2871. }
  2872. StateReturnType ret = AIInternalMoveToState::onEnter();
  2873. if (obj->getFormationID() != NO_FORMATION_ID) {
  2874. AIGroup *group = ai->getGroup();
  2875. if (group) {
  2876. Real speed = group->getSpeed();
  2877. ai->setDesiredSpeed(speed);
  2878. }
  2879. }
  2880. if (nextPos)
  2881. {
  2882. Coord2D delta;
  2883. delta.x = nextPos->x - pos->x;
  2884. delta.y = nextPos->y - pos->y;
  2885. Real offset = delta.length();
  2886. const Coord3D *followingPos = ai->friend_getGoalPathPosition( m_index+2 );
  2887. if (followingPos) offset += 4*PATHFIND_CELL_SIZE_F;
  2888. ai->setPathExtraDistance(offset);
  2889. // We are in the middle of a path, so don't set the final goal location yet.
  2890. setAdjustsDestination(false);
  2891. }
  2892. else
  2893. {
  2894. setAdjustsDestination(m_adjustFinal);
  2895. ai->setPathExtraDistance(0);
  2896. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  2897. if (obj->isKindOf(KINDOF_PROJECTILE))
  2898. {
  2899. if (ai && ai->getCurLocomotor())
  2900. ai->getCurLocomotor()->setUsePreciseZPos(true);
  2901. }
  2902. }
  2903. return ret;
  2904. }
  2905. //----------------------------------------------------------------------------------------------------------
  2906. void AIFollowPathState::onExit( StateExitType status )
  2907. {
  2908. AIInternalMoveToState::onExit( status );
  2909. // turn off precision-z-pos when we exit, just in case.
  2910. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2911. if (!ai) return;
  2912. ai->setCanPathThroughUnits(false);
  2913. if (ai->getCurLocomotor())
  2914. ai->getCurLocomotor()->setUsePreciseZPos(false);
  2915. //Assign this value to the AIUpdateInterface so object's can access this value while
  2916. //determine which waypoints to plot in the waypoint renderer.
  2917. ai->friend_setCurrentGoalPathIndex( -1 );
  2918. }
  2919. //----------------------------------------------------------------------------------------------------------
  2920. StateReturnType AIFollowPathState::update()
  2921. {
  2922. getMachine()->setGoalPosition(&m_goalPosition);
  2923. // do movement
  2924. StateReturnType status = AIInternalMoveToState::update();
  2925. // if move to has finished, move to next point on path
  2926. if (status == STATE_SUCCESS || status == STATE_FAILURE)
  2927. {
  2928. Object *obj = getMachineOwner();
  2929. AIUpdateInterface *ai = obj->getAI();
  2930. if (status == STATE_FAILURE && m_retryCount>0) {
  2931. // If we failed, & haven't reached retry limit, try again. jba.
  2932. m_retryCount--;
  2933. } else {
  2934. ++m_index;
  2935. }
  2936. const Coord3D *pos = ai->friend_getGoalPathPosition( m_index );
  2937. Bool tooClose=true;
  2938. while (pos && tooClose) {
  2939. Real dx = pos->x - obj->getPosition()->x;
  2940. Real dy = pos->y - obj->getPosition()->y;
  2941. tooClose = false;
  2942. if (sqr(dx) + sqr(dy) < sqr(PATHFIND_CELL_SIZE_F)) {
  2943. tooClose = true;
  2944. }
  2945. if (tooClose) {
  2946. m_index++;
  2947. pos = ai->friend_getGoalPathPosition(m_index);
  2948. }
  2949. }
  2950. //Assign this value to the AIUpdateInterface so object's can access this value while
  2951. //determine which waypoints to plot in the waypoint renderer.
  2952. ai->friend_setCurrentGoalPathIndex( m_index );
  2953. ai->ignoreObstacleID(INVALID_ID); // we have exited whatever object we are leaving, if any. jba.
  2954. if (pos == NULL)
  2955. {
  2956. // reached the end of the path
  2957. return STATE_SUCCESS;
  2958. }
  2959. ai->friend_startingMove();
  2960. // set next movement goal
  2961. m_goalPosition = *pos;
  2962. const Coord3D *nextPos = ai->friend_getGoalPathPosition( m_index+1 );
  2963. if (nextPos)
  2964. {
  2965. Coord2D delta;
  2966. delta.x = nextPos->x - pos->x;
  2967. delta.y = nextPos->y - pos->y;
  2968. Real offset = delta.length();
  2969. const Coord3D *followingPos = ai->friend_getGoalPathPosition( m_index+2 );
  2970. if (followingPos) offset += 4*PATHFIND_CELL_SIZE_F;
  2971. ai->setPathExtraDistance(offset);
  2972. // We are in the middle of a path, so don't set the final goal location yet.
  2973. setAdjustsDestination(false);
  2974. }
  2975. else
  2976. {
  2977. setAdjustsDestination(m_adjustFinal && (m_adjustFinalOverride || ai->isDoingGroundMovement()));
  2978. if (getAdjustsDestination())
  2979. {
  2980. if (!TheAI->pathfinder()->adjustDestination(getMachineOwner(), ai->getLocomotorSet(), &m_goalPosition)) {
  2981. return STATE_FAILURE;
  2982. }
  2983. TheAI->pathfinder()->updateGoal(getMachineOwner(), &m_goalPosition, TheTerrainLogic->getLayerForDestination(&m_goalPosition));
  2984. }
  2985. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  2986. if (obj->isKindOf(KINDOF_PROJECTILE))
  2987. {
  2988. if (ai && ai->getCurLocomotor())
  2989. ai->getCurLocomotor()->setUsePreciseZPos(true);
  2990. }
  2991. }
  2992. computePath();
  2993. return STATE_CONTINUE;
  2994. }
  2995. return status;
  2996. }
  2997. //----------------------------------------------------------------------------------------------------------
  2998. //----------------------------------------------------------------------------------------------------------
  2999. //----------------------------------------------------------------------------------------------------------
  3000. // ------------------------------------------------------------------------------------------------
  3001. /** CRC */
  3002. // ------------------------------------------------------------------------------------------------
  3003. void AIMoveAndEvacuateState::crc( Xfer *xfer )
  3004. {
  3005. AIInternalMoveToState::crc(xfer);
  3006. } // end crc
  3007. // ------------------------------------------------------------------------------------------------
  3008. /** Xfer Method */
  3009. // ------------------------------------------------------------------------------------------------
  3010. void AIMoveAndEvacuateState::xfer( Xfer *xfer )
  3011. {
  3012. // version
  3013. XferVersion currentVersion = 1;
  3014. XferVersion version = currentVersion;
  3015. xfer->xferVersion( &version, currentVersion );
  3016. AIInternalMoveToState::xfer(xfer);
  3017. xfer->xferCoord3D(&m_origin);
  3018. } // end xfer
  3019. // ------------------------------------------------------------------------------------------------
  3020. /** Load post process */
  3021. // ------------------------------------------------------------------------------------------------
  3022. void AIMoveAndEvacuateState::loadPostProcess( void )
  3023. {
  3024. AIInternalMoveToState::loadPostProcess();
  3025. } // end loadPostProcess
  3026. //----------------------------------------------------------------------------------------------------------
  3027. StateReturnType AIMoveAndEvacuateState::onEnter()
  3028. {
  3029. Object *obj = getMachineOwner();
  3030. getMachine()->lock("AIMoveAndEvacuateState::onEnter"); // This state is not user interruptable.
  3031. m_origin = *obj->getPosition();
  3032. setAdjustsDestination(true);
  3033. // if we have a goal object, move to it, otherwise move to goal position
  3034. if (getMachine()->getGoalObject())
  3035. m_goalPosition = *getMachine()->getGoalObject()->getPosition();
  3036. else
  3037. m_goalPosition = *getMachine()->getGoalPosition();
  3038. return AIInternalMoveToState::onEnter();
  3039. }
  3040. //----------------------------------------------------------------------------------------------------------
  3041. StateReturnType AIMoveAndEvacuateState::update()
  3042. {
  3043. Object *obj = getMachine()->getOwner();
  3044. if (obj->isEffectivelyDead())
  3045. {
  3046. return STATE_FAILURE;
  3047. }
  3048. // do movement
  3049. StateReturnType status = AIInternalMoveToState::update();
  3050. if (status != STATE_CONTINUE)
  3051. {
  3052. Object *obj = getMachineOwner();
  3053. if (obj->isEffectivelyDead())
  3054. {
  3055. return STATE_FAILURE;
  3056. }
  3057. AIUpdateInterface *ai = obj->getAI();
  3058. ai->aiEvacuate(FALSE, CMD_FROM_AI);
  3059. obj->getTeam()->setActive();
  3060. }
  3061. return status;
  3062. }
  3063. //----------------------------------------------------------------------------------------------------------
  3064. void AIMoveAndEvacuateState::onExit( StateExitType status )
  3065. {
  3066. getMachine()->unlock();
  3067. getMachine()->setGoalPosition(&m_origin); // In case we follow with a AIMoveAndDeleteState.
  3068. AIInternalMoveToState::onExit( status );
  3069. }
  3070. //----------------------------------------------------------------------------------------------------------
  3071. //----------------------------------------------------------------------------------------------------------
  3072. //----------------------------------------------------------------------------------------------------------
  3073. //-------------------------------------------------------------------------------------------------
  3074. AIAttackMoveToState::AIAttackMoveToState( StateMachine *machine ) : AIMoveToState(machine)
  3075. {
  3076. #ifdef STATE_MACHINE_DEBUG
  3077. setName("AIAttackMoveToState");
  3078. #endif // set up the state
  3079. m_isMoveTo = false;
  3080. m_frameToSleepUntil = 0;
  3081. m_retryCount = ATTACK_RETRY_COUNT;
  3082. m_attackMoveMachine = newInstance(AIAttackMoveStateMachine)(getMachineOwner(), "AIAttackMoveMachine");
  3083. m_attackMoveMachine->initDefaultState();
  3084. }
  3085. //----------------------------------------------------------------------------------------------------------
  3086. AIAttackMoveToState::~AIAttackMoveToState()
  3087. {
  3088. m_attackMoveMachine->deleteInstance();
  3089. }
  3090. // ------------------------------------------------------------------------------------------------
  3091. /** CRC */
  3092. // ------------------------------------------------------------------------------------------------
  3093. void AIAttackMoveToState::crc( Xfer *xfer )
  3094. {
  3095. } // end crc
  3096. // ------------------------------------------------------------------------------------------------
  3097. /** Xfer Method */
  3098. // ------------------------------------------------------------------------------------------------
  3099. void AIAttackMoveToState::xfer( Xfer *xfer )
  3100. {
  3101. // version
  3102. XferVersion currentVersion = 2;
  3103. XferVersion version = currentVersion;
  3104. xfer->xferVersion( &version, currentVersion );
  3105. // extend base class
  3106. AIMoveToState::xfer( xfer );
  3107. if (version>=2) {
  3108. xfer->xferUnsignedInt(&m_frameToSleepUntil);
  3109. xfer->xferInt(&m_retryCount);
  3110. }
  3111. xfer->xferSnapshot(m_attackMoveMachine);
  3112. } // end xfer
  3113. // ------------------------------------------------------------------------------------------------
  3114. /** Load post process */
  3115. // ------------------------------------------------------------------------------------------------
  3116. void AIAttackMoveToState::loadPostProcess( void )
  3117. {
  3118. } // end loadPostProcess
  3119. #ifdef STATE_MACHINE_DEBUG
  3120. //----------------------------------------------------------------------------------------------------------
  3121. AsciiString AIAttackMoveToState::getName( ) const
  3122. {
  3123. AsciiString name = m_name;
  3124. name.concat("/");
  3125. if (m_attackMoveMachine) name.concat(m_attackMoveMachine->getCurrentStateName());
  3126. else name.concat("*NULL m_deployMachine");
  3127. return name;
  3128. }
  3129. #endif
  3130. //----------------------------------------------------------------------------------------------------------
  3131. StateReturnType AIAttackMoveToState::onEnter()
  3132. {
  3133. Object *owner = getMachineOwner();
  3134. AIUpdateInterface *ai = owner->getAI();
  3135. m_attackMoveMachine->clear();
  3136. m_attackMoveMachine->setState( AI_IDLE );
  3137. m_commandSrc = ai->getLastCommandSource();
  3138. m_retryCount = ATTACK_RETRY_COUNT;
  3139. m_frameToSleepUntil = 0;
  3140. return AIMoveToState::onEnter();
  3141. }
  3142. //----------------------------------------------------------------------------------------------------------
  3143. void AIAttackMoveToState::onExit( StateExitType status )
  3144. {
  3145. m_attackMoveMachine->setState(AI_IDLE);
  3146. AIMoveToState::onExit(status);
  3147. }
  3148. //----------------------------------------------------------------------------------------------------------
  3149. StateReturnType AIAttackMoveToState::update()
  3150. {
  3151. Object *owner = getMachineOwner();
  3152. AIUpdateInterface *ai = owner->getAI();
  3153. Bool forceRetargetThisFrame = false;
  3154. Bool shouldRepathThisFrame = false;
  3155. JetAIUpdate *jetAI = ai->getJetAIUpdate();
  3156. if( jetAI && jetAI->isOutOfSpecialReloadAmmo() )
  3157. {
  3158. //We need to return to base to reload!
  3159. return STATE_SUCCESS;
  3160. }
  3161. if (!m_attackMoveMachine->isInIdleState())
  3162. {
  3163. ai->setLocomotorGoalNone();
  3164. owner->clearModelConditionState(MODELCONDITION_MOVING);
  3165. m_attackMoveMachine->updateStateMachine();
  3166. // if the machine is now idling, then we need to attempt to get a new target
  3167. if (m_attackMoveMachine->isInIdleState()) {
  3168. forceRetargetThisFrame = true;
  3169. shouldRepathThisFrame = true;
  3170. ai->friend_setLastCommandSource(m_commandSrc);
  3171. } else {
  3172. return STATE_CONTINUE;
  3173. }
  3174. }
  3175. if (m_attackMoveMachine->isInIdleState())
  3176. {
  3177. // Check to see if we have created a crate we need to pick up.
  3178. Object* crate = ai->checkForCrateToPickup();
  3179. if (crate)
  3180. {
  3181. m_attackMoveMachine->setGoalObject(crate);
  3182. m_attackMoveMachine->setState( AI_PICK_UP_CRATE );
  3183. return STATE_CONTINUE;
  3184. }
  3185. Object* nextObjectToAttack;
  3186. nextObjectToAttack = ai->getNextMoodTarget( !forceRetargetThisFrame, false );
  3187. if (nextObjectToAttack != NULL)
  3188. {
  3189. ai->friend_endingMove();
  3190. m_attackMoveMachine->setGoalObject(nextObjectToAttack);
  3191. m_attackMoveMachine->setState( AI_ATTACK_OBJECT );
  3192. shouldRepathThisFrame = false; // we're about to drop out of this function, but this is semantic emphasis.
  3193. // Note that we picked up this command from the ai.
  3194. ai->friend_setLastCommandSource(CMD_FROM_AI);
  3195. // we don't want an update to take place 'till next frame.
  3196. return STATE_CONTINUE;
  3197. }
  3198. }
  3199. if (m_frameToSleepUntil>TheGameLogic->getFrame()) {
  3200. return STATE_CONTINUE;
  3201. } else if (m_frameToSleepUntil == TheGameLogic->getFrame()) {
  3202. shouldRepathThisFrame = true;
  3203. }
  3204. if (shouldRepathThisFrame)
  3205. {
  3206. AIMoveToState::onEnter();
  3207. forceRepath();
  3208. }
  3209. StateReturnType ret = AIMoveToState::update();
  3210. if (ret != STATE_CONTINUE) {
  3211. if (m_retryCount<1) return ret;
  3212. /* check for close enough. */
  3213. Real distSqr = sqr(owner->getPosition()->x - m_pathGoalPosition.x) + sqr(owner->getPosition()->y-m_pathGoalPosition.y);
  3214. if (distSqr < sqr(ATTACK_CLOSE_ENOUGH_CELLS*PATHFIND_CELL_SIZE_F)) {
  3215. return ret;
  3216. }
  3217. DEBUG_LOG(("AIAttackMoveToState::update Distance from goal %f, retrying.\n", sqrt(distSqr)));
  3218. ret = STATE_CONTINUE;
  3219. m_retryCount--;
  3220. // Sleep 3 seconds. We can attack during these frames, just not move.
  3221. m_frameToSleepUntil = TheGameLogic->getFrame() + 3*LOGICFRAMES_PER_SECOND;
  3222. }
  3223. return ret;
  3224. }
  3225. //----------------------------------------------------------------------------------------------------------
  3226. //----------------------------------------------------------------------------------------------------------
  3227. //----------------------------------------------------------------------------------------------------------
  3228. // ------------------------------------------------------------------------------------------------
  3229. /** CRC */
  3230. // ------------------------------------------------------------------------------------------------
  3231. void AIMoveAndDeleteState::crc( Xfer *xfer )
  3232. {
  3233. AIInternalMoveToState::crc(xfer);
  3234. } // end crc
  3235. // ------------------------------------------------------------------------------------------------
  3236. /** Xfer Method */
  3237. // ------------------------------------------------------------------------------------------------
  3238. void AIMoveAndDeleteState::xfer( Xfer *xfer )
  3239. {
  3240. // version
  3241. XferVersion currentVersion = 1;
  3242. XferVersion version = currentVersion;
  3243. xfer->xferVersion( &version, currentVersion );
  3244. AIInternalMoveToState::xfer(xfer);
  3245. xfer->xferBool(&m_appendGoalPosition);
  3246. } // end xfer
  3247. // ------------------------------------------------------------------------------------------------
  3248. /** Load post process */
  3249. // ------------------------------------------------------------------------------------------------
  3250. void AIMoveAndDeleteState::loadPostProcess( void )
  3251. {
  3252. AIInternalMoveToState::loadPostProcess();
  3253. } // end loadPostProcess
  3254. //----------------------------------------------------------------------------------------------------------
  3255. StateReturnType AIMoveAndDeleteState::onEnter()
  3256. {
  3257. setAdjustsDestination(false);
  3258. getMachine()->lock("AIMoveAndDeleteState::onEnter");
  3259. // if we have a goal object, move to it, otherwise move to goal position
  3260. if (getMachine()->getGoalObject())
  3261. m_goalPosition = *getMachine()->getGoalObject()->getPosition();
  3262. else
  3263. m_goalPosition = *getMachine()->getGoalPosition();
  3264. m_appendGoalPosition = true; // We may be moving off the map.
  3265. return AIInternalMoveToState::onEnter();
  3266. }
  3267. //----------------------------------------------------------------------------------------------------------
  3268. StateReturnType AIMoveAndDeleteState::update()
  3269. {
  3270. Object *obj = getMachine()->getOwner();
  3271. if (obj->isEffectivelyDead())
  3272. {
  3273. return STATE_FAILURE;
  3274. }
  3275. // do movement
  3276. AIUpdateInterface *ai = obj->getAI();
  3277. if (ai->getCurLocomotor())
  3278. {
  3279. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  3280. }
  3281. if (m_appendGoalPosition)
  3282. {
  3283. Path *thePath = ai->getPath();
  3284. if (!ai->isWaitingForPath() && ai->getPath())
  3285. {
  3286. m_goalPosition.z = TheTerrainLogic->getGroundHeight(m_goalPosition.x, m_goalPosition.y);
  3287. thePath->appendNode( &m_goalPosition, LAYER_GROUND);
  3288. m_appendGoalPosition = false; // just did it.
  3289. }
  3290. }
  3291. StateReturnType status = AIInternalMoveToState::update();
  3292. if (status != STATE_CONTINUE)
  3293. {
  3294. Object *obj = getMachineOwner();
  3295. TheGameLogic->destroyObject(obj);
  3296. }
  3297. return status;
  3298. }
  3299. //----------------------------------------------------------------------------------------------------------
  3300. void AIMoveAndDeleteState::onExit( StateExitType status )
  3301. {
  3302. getMachine()->unlock();
  3303. AIInternalMoveToState::onExit( status );
  3304. }
  3305. //----------------------------------------------------------------------------------------------------------
  3306. //----------------------------------------------------------------------------------------------------------
  3307. //----------------------------------------------------------------------------------------------------------
  3308. //----------------------------------------------------------------------------------------------------------
  3309. #define ALLOW_BACKTRACK
  3310. //----------------------------------------------------------------------------------------------------------
  3311. const Waypoint * AIFollowWaypointPathState::getNextWaypoint(void)
  3312. {
  3313. #ifdef ALLOW_BACKTRACK
  3314. Int linkCount = m_currentWaypoint->getNumLinks();
  3315. Int which = GameLogicRandomValue( 0, linkCount-1 );
  3316. const Waypoint *nextWay = m_currentWaypoint->getLink( which );
  3317. m_priorWaypoint = m_currentWaypoint;
  3318. getMachine()->setGoalPosition(m_currentWaypoint->getLocation());// THANKS, JOHN
  3319. return nextWay;
  3320. #else
  3321. if (!hasNextWaypoint()) {
  3322. m_priorWaypoint = m_currentWaypoint;
  3323. return NULL;
  3324. }
  3325. Int skip = -1;
  3326. Int i;
  3327. Int linkCount = m_currentWaypoint->getNumLinks();
  3328. for (i=0; i<linkCount; i++) {
  3329. if (m_priorWaypoint == m_currentWaypoint->getLink(i)) {
  3330. skip = i;
  3331. break;
  3332. }
  3333. }
  3334. Int which = 0;
  3335. if (skip >= 0) {
  3336. which = GameLogicRandomValue( 0, linkCount-2 );
  3337. if (which == skip) which = linkCount-1;
  3338. } else {
  3339. // pick a random link
  3340. which = GameLogicRandomValue( 0, linkCount-1 );
  3341. }
  3342. const Waypoint *nextWay = m_currentWaypoint->getLink( which );
  3343. m_priorWaypoint = m_currentWaypoint;
  3344. return nextWay;
  3345. #endif
  3346. }
  3347. //----------------------------------------------------------------------------------------------------------
  3348. Bool AIFollowWaypointPathState::hasNextWaypoint(void)
  3349. {
  3350. #ifdef ALLOW_BACKTRACK
  3351. return m_currentWaypoint->getNumLinks()>0;
  3352. #else
  3353. if (m_currentWaypoint->getNumLinks()==0) {
  3354. return false; // no links, no next.
  3355. }
  3356. if (m_priorWaypoint==NULL) {
  3357. return m_currentWaypoint->getNumLinks()>0;
  3358. }
  3359. if (m_currentWaypoint->getNumLinks()>1) {
  3360. // Two links, always works.
  3361. return true;
  3362. }
  3363. // We have a prior waypoint, and 1 link.
  3364. if (m_priorWaypoint == m_currentWaypoint->getLink(0)) {
  3365. return false; // don't go back to same waypoint.
  3366. }
  3367. return true;
  3368. #endif
  3369. }
  3370. //----------------------------------------------------------------------------------------------------------
  3371. Real AIFollowWaypointPathState::calcExtraPathDistance(void)
  3372. {
  3373. Real extra = PATHFIND_CELL_SIZE_F/10.0f;
  3374. const Waypoint *curWay = m_currentWaypoint;
  3375. Int limit = 5; // just look ahead 5, in case of circular paths. jba
  3376. while (curWay && limit>0) {
  3377. limit--;
  3378. Int linkCount = curWay->getNumLinks();
  3379. if (linkCount == 0) return extra;
  3380. Int which = 0;
  3381. const Waypoint *nextWay = curWay->getLink( which );
  3382. Coord2D delta;
  3383. delta.x = nextWay->getLocation()->x - curWay->getLocation()->x;
  3384. delta.y = nextWay->getLocation()->y - curWay->getLocation()->y;
  3385. extra += delta.length();
  3386. curWay = nextWay;
  3387. }
  3388. return extra;
  3389. }
  3390. //----------------------------------------------------------------------------------------------------------
  3391. void AIFollowWaypointPathState::computeGoal(Bool useGroupOffsets)
  3392. {
  3393. if (m_currentWaypoint == NULL)
  3394. return;
  3395. Object *obj = getMachineOwner();
  3396. AIUpdateInterface *ai = obj->getAI();
  3397. Coord3D dest = *m_currentWaypoint->getLocation();
  3398. m_goalLayer = LAYER_GROUND; // waypoints are always on the ground.
  3399. if (TheAI->pathfinder()->isPointOnWall(&dest)) {
  3400. // except when they're on the wall. jba.
  3401. dest.z = TheAI->pathfinder()->getWallHeight();
  3402. m_goalLayer = LAYER_WALL;
  3403. }
  3404. ai->setPathExtraDistance(calcExtraPathDistance());
  3405. if (hasNextWaypoint()) {
  3406. // We are in the middle of a path, so don't set the final goal location yet.
  3407. setAdjustsDestination(false);
  3408. } else {
  3409. setAdjustsDestination(true);
  3410. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  3411. if (obj->isKindOf(KINDOF_PROJECTILE))
  3412. {
  3413. if (ai && ai->getCurLocomotor())
  3414. ai->getCurLocomotor()->setUsePreciseZPos(true);
  3415. }
  3416. }
  3417. #define NO_ROTATE_OFFSETS
  3418. #ifdef ROTATE_OFFSETS
  3419. Real dx = (dest.x) - (obj->getPosition()->x - m_groupOffset.x);
  3420. Real dy = (dest.y) - (obj->getPosition()->y - m_groupOffset.y);
  3421. Real angle;
  3422. if (m_priorWaypoint) {
  3423. dx = dest.x - m_priorWaypoint->getLocation()->x;
  3424. dy = dest.y - m_priorWaypoint->getLocation()->y;
  3425. angle = atan2(dy, dx);
  3426. Real deltaAngle = angle - m_angle;
  3427. Real s = sin(deltaAngle);
  3428. Real c = cos(deltaAngle);
  3429. Real x = m_groupOffset.x * c - m_groupOffset.y * s;
  3430. Real y = m_groupOffset.y * c + m_groupOffset.x * s;
  3431. m_groupOffset.x = x;
  3432. m_groupOffset.y = y;
  3433. } else {
  3434. angle = atan2(dy, dx);
  3435. }
  3436. m_angle = angle;
  3437. #endif
  3438. m_goalPosition = dest;
  3439. m_goalPosition.x += m_groupOffset.x;
  3440. m_goalPosition.y += m_groupOffset.y;
  3441. if (m_goalLayer == LAYER_WALL) {
  3442. if (!TheAI->pathfinder()->isPointOnWall(&m_goalPosition)) {
  3443. m_goalPosition = dest;
  3444. }
  3445. } else {
  3446. m_goalPosition.z = TheTerrainLogic->getGroundHeight(m_goalPosition.x, m_goalPosition.y);
  3447. }
  3448. Region3D extent;
  3449. TheTerrainLogic->getMaximumPathfindExtent(&extent);
  3450. if (extent.isInRegionNoZ(&dest)) {
  3451. // The waypoint is on the map. Check & see if the adjusted position is off map [8/28/2003]
  3452. if (!extent.isInRegionNoZ(&m_goalPosition)) {
  3453. // clamp to in region. [8/28/2003]
  3454. if (m_goalPosition.x < extent.lo.x+PATHFIND_CELL_SIZE_F) {
  3455. m_goalPosition.x = extent.lo.x+PATHFIND_CELL_SIZE_F;
  3456. }
  3457. if (m_goalPosition.y < extent.lo.y+PATHFIND_CELL_SIZE_F) {
  3458. m_goalPosition.y = extent.lo.y+PATHFIND_CELL_SIZE_F;
  3459. }
  3460. if (m_goalPosition.x > extent.hi.x-PATHFIND_CELL_SIZE_F) {
  3461. m_goalPosition.x = extent.hi.x-PATHFIND_CELL_SIZE_F;
  3462. }
  3463. if (m_goalPosition.y > extent.hi.y-PATHFIND_CELL_SIZE_F) {
  3464. m_goalPosition.y = extent.hi.y-PATHFIND_CELL_SIZE_F;
  3465. }
  3466. }
  3467. }
  3468. if (!extent.isInRegionNoZ(&m_goalPosition)) {
  3469. setAdjustsDestination(false); // moving off the map.
  3470. ai->getCurLocomotor()->setAllowInvalidPosition(true); // allow it to move off the map.
  3471. m_appendGoalPosition = true; // Moving off the map.
  3472. }
  3473. }
  3474. // ------------------------------------------------------------------------------------------------
  3475. /** CRC */
  3476. // ------------------------------------------------------------------------------------------------
  3477. void AIFollowWaypointPathState::crc( Xfer *xfer )
  3478. {
  3479. AIInternalMoveToState::crc(xfer);
  3480. } // end crc
  3481. // ------------------------------------------------------------------------------------------------
  3482. /** Xfer Method */
  3483. // ------------------------------------------------------------------------------------------------
  3484. void AIFollowWaypointPathState::xfer( Xfer *xfer )
  3485. {
  3486. // version
  3487. XferVersion currentVersion = 1;
  3488. XferVersion version = currentVersion;
  3489. xfer->xferVersion( &version, currentVersion );
  3490. AIInternalMoveToState::xfer(xfer);
  3491. xfer->xferCoord2D(&m_groupOffset);
  3492. xfer->xferReal(&m_angle);
  3493. xfer->xferInt(&m_framesSleeping);
  3494. UnsignedInt id = INVALID_WAYPOINT_ID;
  3495. if (m_currentWaypoint) {
  3496. id = m_currentWaypoint->getID();
  3497. }
  3498. xfer->xferUnsignedInt(&id);
  3499. if (xfer->getXferMode() == XFER_LOAD)
  3500. {
  3501. m_currentWaypoint = TheTerrainLogic->getWaypointByID(id);
  3502. }
  3503. id = INVALID_WAYPOINT_ID;
  3504. if (m_priorWaypoint) {
  3505. id = m_priorWaypoint->getID();
  3506. }
  3507. xfer->xferUnsignedInt(&id);
  3508. if (xfer->getXferMode() == XFER_LOAD)
  3509. {
  3510. m_priorWaypoint = TheTerrainLogic->getWaypointByID(id);
  3511. }
  3512. xfer->xferBool(&m_appendGoalPosition);
  3513. } // end xfer
  3514. // ------------------------------------------------------------------------------------------------
  3515. /** Load post process */
  3516. // ------------------------------------------------------------------------------------------------
  3517. void AIFollowWaypointPathState::loadPostProcess( void )
  3518. {
  3519. AIInternalMoveToState::loadPostProcess();
  3520. } // end loadPostProcess
  3521. //----------------------------------------------------------------------------------------------------------
  3522. StateReturnType AIFollowWaypointPathState::onEnter()
  3523. {
  3524. m_appendGoalPosition = false; // not moving off the map at this point.
  3525. m_priorWaypoint = NULL;
  3526. m_currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  3527. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3528. if (m_currentWaypoint == NULL && !m_moveAsGroup) return STATE_FAILURE;
  3529. getMachine()->setGoalPosition(m_currentWaypoint->getLocation());
  3530. m_framesSleeping = 0;
  3531. m_groupOffset.x = m_groupOffset.y = 0;
  3532. Object *obj = getMachineOwner();
  3533. /* Interesting thought experiment. Didn't work well. jba
  3534. Real distSqrLimit = 9*obj->getGeometryInfo().getMajorRadius()*obj->getGeometryInfo().getMajorRadius();
  3535. const Waypoint *way = m_currentWaypoint;
  3536. Bool doPrecise = false;
  3537. while (way) {
  3538. if (way->getNext()) {
  3539. Real dx = way->getLocation()->x - way->getNext()->getLocation()->x;
  3540. Real dy = way->getLocation()->y - way->getNext()->getLocation()->y;
  3541. Real distSqr = dx*dx + dy*dy;
  3542. if (distSqr < distSqrLimit) {
  3543. doPrecise = true;
  3544. }
  3545. }
  3546. way = way->getNext();
  3547. }
  3548. if (doPrecise && ai->getCurLocomotor()) {
  3549. //ai->getCurLocomotor()->setUltraAccurate(true);
  3550. }
  3551. */
  3552. Real speed = FAST_AS_POSSIBLE;
  3553. if (m_moveAsGroup && m_currentWaypoint) {
  3554. obj->getTeam()->setCurrentWaypoint(m_currentWaypoint);
  3555. AIGroup *group = ai->getGroup();
  3556. if (group) {
  3557. speed = group->getSpeed();
  3558. Coord3D center;
  3559. group->getCenter( &center );
  3560. m_groupOffset.x = obj->getPosition()->x - center.x;
  3561. m_groupOffset.y = obj->getPosition()->y - center.y;
  3562. }
  3563. }
  3564. if (m_currentWaypoint==NULL && m_moveAsGroup) {
  3565. m_currentWaypoint = obj->getTeam()->getCurrentWaypoint();
  3566. }
  3567. // set initial movement goal
  3568. computeGoal(m_moveAsGroup);
  3569. StateReturnType ret = AIInternalMoveToState::onEnter();
  3570. ai->setDesiredSpeed(speed);
  3571. // Update the extra path distance. AIInternalMoveToState::onEnter resets it.
  3572. ai->setPathExtraDistance(calcExtraPathDistance());
  3573. if (hasNextWaypoint()) {
  3574. // We are in the middle of a path, so don't set the final goal location yet.
  3575. setAdjustsDestination(false);
  3576. } else {
  3577. setAdjustsDestination(ai->isDoingGroundMovement());
  3578. if (getAdjustsDestination()) {
  3579. if (!TheAI->pathfinder()->adjustDestination(getMachineOwner(), ai->getLocomotorSet(), &m_goalPosition)) {
  3580. DEBUG_LOG(("Breaking out of follow waypoint path\n"));
  3581. return STATE_FAILURE;
  3582. }
  3583. TheAI->pathfinder()->updateGoal(getMachineOwner(), &m_goalPosition, m_goalLayer);
  3584. }
  3585. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  3586. if (obj->isKindOf(KINDOF_PROJECTILE))
  3587. {
  3588. if (ai && ai->getCurLocomotor())
  3589. ai->getCurLocomotor()->setUsePreciseZPos(true);
  3590. }
  3591. }
  3592. if (ret != STATE_CONTINUE) {
  3593. DEBUG_LOG(("Breaking out of follow waypoint path\n"));
  3594. }
  3595. return ret;
  3596. }
  3597. //----------------------------------------------------------------------------------------------------------
  3598. void AIFollowWaypointPathState::onExit( StateExitType status )
  3599. {
  3600. AIInternalMoveToState::onExit( status );
  3601. // turn off precision-z-pos when we exit, just in case.
  3602. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3603. if (ai && ai->getCurLocomotor()) {
  3604. ai->getCurLocomotor()->setUsePreciseZPos(false);
  3605. ai->getCurLocomotor()->setUltraAccurate(false);
  3606. }
  3607. }
  3608. //----------------------------------------------------------------------------------------------------------
  3609. StateReturnType AIFollowWaypointPathState::update()
  3610. {
  3611. if (m_framesSleeping>0) {
  3612. m_framesSleeping--;
  3613. return STATE_CONTINUE;
  3614. }
  3615. Object *obj = getMachineOwner();
  3616. AIUpdateInterface *ai = obj->getAI();
  3617. getMachine()->setGoalPosition(m_currentWaypoint->getLocation());
  3618. UnsignedInt adjustment = ai->getMoodMatrixActionAdjustment(MM_Action_Move);
  3619. if (m_isFollowWaypointPathState && (adjustment & MAA_Action_To_AttackMove)) {
  3620. if (m_moveAsGroup) {
  3621. ai->aiAttackFollowWaypointPathAsTeam(m_currentWaypoint, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  3622. } else {
  3623. ai->aiAttackFollowWaypointPath(m_currentWaypoint, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  3624. }
  3625. }
  3626. if (m_appendGoalPosition) {
  3627. Path *thePath = ai->getPath();
  3628. if (!ai->isWaitingForPath() && ai->getPath()) {
  3629. //Coord3D pathEnd = *thePath->getLastNode()->getPosition();
  3630. thePath->appendNode(&m_goalPosition, LAYER_GROUND); // waypoints are always on the ground.
  3631. m_appendGoalPosition = false; // just did it.
  3632. }
  3633. }
  3634. if (m_moveAsGroup && m_currentWaypoint != obj->getTeam()->getCurrentWaypoint()) {
  3635. m_priorWaypoint = m_currentWaypoint;
  3636. m_currentWaypoint = obj->getTeam()->getCurrentWaypoint();
  3637. if (m_currentWaypoint == NULL) {
  3638. return STATE_SUCCESS;
  3639. }
  3640. computeGoal(false);
  3641. if (getAdjustsDestination() && ai->isDoingGroundMovement()) {
  3642. if (!TheAI->pathfinder()->adjustDestination(obj, ai->getLocomotorSet(), &m_goalPosition)) {
  3643. if (m_currentWaypoint) {
  3644. DEBUG_LOG(("Breaking out of follow waypoint path %s of %s\n",
  3645. m_currentWaypoint->getName().str(), m_currentWaypoint->getPathLabel1().str()));
  3646. }
  3647. return STATE_FAILURE;
  3648. }
  3649. }
  3650. ai->friend_startingMove();
  3651. computePath();
  3652. if (getAdjustsDestination()) {
  3653. TheAI->pathfinder()->updateGoal(obj, &m_goalPosition, m_goalLayer);
  3654. }
  3655. }
  3656. // do movement
  3657. StateReturnType status = AIInternalMoveToState::update();
  3658. // We may want to allow ourselves to bail out of this one early. In order to do this, we check and
  3659. // see if we're moving as a group, and then if our team is owned by an AI Skirmish player.
  3660. // If it is, then we compute the group centroid, and see if it is within some distance of the
  3661. if (m_moveAsGroup) {
  3662. if (obj->getControllingPlayer()->isSkirmishAIPlayer()) {
  3663. Team *team = obj->getTeam();
  3664. AIGroup *group = TheAI->createGroup();
  3665. team->getTeamAsAIGroup(group);
  3666. Coord3D pos;
  3667. group->getCenter(&pos);
  3668. pos.x -= m_goalPosition.x;
  3669. pos.y -= m_goalPosition.y;
  3670. pos.z = 0;
  3671. Int numInGroup = group->getCount();
  3672. if (pos.length() <= (numInGroup * TheAI->getAiData()->m_skirmishGroupFudgeValue)) {
  3673. // Consider ourselves close enough.
  3674. status = STATE_SUCCESS;
  3675. }
  3676. }
  3677. }
  3678. // if move to has finished, move to next point on waypoint path
  3679. if (status != STATE_CONTINUE)
  3680. {
  3681. m_currentWaypoint = getNextWaypoint();
  3682. //LORENZEN ADDED LORENZEN ADDED LORENZEN ADDED
  3683. Object *obj = getMachineOwner();
  3684. AIUpdateInterface *ai = obj->getAI();
  3685. if ( m_priorWaypoint )
  3686. ai->setPriorWaypointID( m_priorWaypoint->getID() );
  3687. if ( m_currentWaypoint )
  3688. ai->setCurrentWaypointID( m_currentWaypoint->getID() );
  3689. //LORENZEN ADDED LORENZEN ADDED LORENZEN ADDED
  3690. // if there are no links from this waypoint, we're done
  3691. if (m_currentWaypoint==NULL) {
  3692. /// Trigger "end of waypoint path" scripts (jba)
  3693. ai->setCompletedWaypoint(m_priorWaypoint);
  3694. return STATE_SUCCESS;
  3695. }
  3696. if (m_moveAsGroup) {
  3697. obj->getTeam()->setCurrentWaypoint(m_currentWaypoint);
  3698. }
  3699. computeGoal(false);
  3700. if (getAdjustsDestination() && ai->isDoingGroundMovement()) {
  3701. if (!TheAI->pathfinder()->adjustDestination(obj, ai->getLocomotorSet(), &m_goalPosition)) {
  3702. if (m_currentWaypoint) {
  3703. DEBUG_LOG(("Breaking out of follow waypoint path %s of %s\n",
  3704. m_currentWaypoint->getName().str(), m_currentWaypoint->getPathLabel1().str()));
  3705. }
  3706. return STATE_FAILURE;
  3707. }
  3708. }
  3709. ai->friend_startingMove();
  3710. computePath();
  3711. if (getAdjustsDestination()) {
  3712. TheAI->pathfinder()->updateGoal(obj, &m_goalPosition, m_goalLayer);
  3713. }
  3714. return STATE_CONTINUE;
  3715. }
  3716. if (status != STATE_CONTINUE) {
  3717. DEBUG_LOG(("Breaking out of follow waypoint path\n"));
  3718. }
  3719. return status;
  3720. }
  3721. //----------------------------------------------------------------------------------------------------------
  3722. //----------------------------------------------------------------------------------------------------------
  3723. //----------------------------------------------------------------------------------------------------------
  3724. //----------------------------------------------------------------------------------------------------------
  3725. // ------------------------------------------------------------------------------------------------
  3726. /** CRC */
  3727. // ------------------------------------------------------------------------------------------------
  3728. void AIFollowWaypointPathExactState::crc( Xfer *xfer )
  3729. {
  3730. AIInternalMoveToState::crc(xfer);
  3731. } // end crc
  3732. // ------------------------------------------------------------------------------------------------
  3733. /** Xfer Method */
  3734. // ------------------------------------------------------------------------------------------------
  3735. void AIFollowWaypointPathExactState::xfer( Xfer *xfer )
  3736. {
  3737. // version
  3738. XferVersion currentVersion = 1;
  3739. XferVersion version = currentVersion;
  3740. xfer->xferVersion( &version, currentVersion );
  3741. AIInternalMoveToState::xfer(xfer);
  3742. UnsignedInt id = INVALID_WAYPOINT_ID;
  3743. if (m_lastWaypoint) {
  3744. id = m_lastWaypoint->getID();
  3745. }
  3746. xfer->xferUnsignedInt(&id);
  3747. if (xfer->getXferMode() == XFER_LOAD)
  3748. {
  3749. m_lastWaypoint = TheTerrainLogic->getWaypointByID(id);
  3750. }
  3751. } // end xfer
  3752. // ------------------------------------------------------------------------------------------------
  3753. /** Load post process */
  3754. // ------------------------------------------------------------------------------------------------
  3755. void AIFollowWaypointPathExactState::loadPostProcess( void )
  3756. {
  3757. AIInternalMoveToState::loadPostProcess();
  3758. } // end loadPostProcess
  3759. //----------------------------------------------------------------------------------------------------------
  3760. StateReturnType AIFollowWaypointPathExactState::onEnter()
  3761. {
  3762. const Waypoint *currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  3763. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3764. if (currentWaypoint == NULL) return STATE_FAILURE;
  3765. getMachine()->setGoalPosition(currentWaypoint->getLocation());
  3766. Coord2D groupOffset;
  3767. groupOffset.x = groupOffset.y = 0;
  3768. Object *obj = getMachineOwner();
  3769. Real speed = FAST_AS_POSSIBLE;
  3770. if (m_moveAsGroup) {
  3771. AIGroup *group = ai->getGroup();
  3772. if (group) {
  3773. speed = group->getSpeed();
  3774. Coord3D center;
  3775. group->getCenter( &center );
  3776. groupOffset.x = obj->getPosition()->x - center.x;
  3777. groupOffset.y = obj->getPosition()->y - center.y;
  3778. }
  3779. }
  3780. ai->setCanPathThroughUnits(true);
  3781. setAdjustsDestination(false);
  3782. // set initial movement goal
  3783. StateReturnType ret = AIInternalMoveToState::onEnter();
  3784. ai->setPathFromWaypoint(currentWaypoint, &groupOffset);
  3785. m_lastWaypoint = currentWaypoint;
  3786. ai->getCurLocomotor()->setAllowInvalidPosition(true); // allow it to move off the map.
  3787. //Kris: October 4, 2002 -- Commented out by guidance of John A.
  3788. // Artist couldn't load his map, and turned out that it was because
  3789. // there was a waypoint path that pointed to itself (2 point path).
  3790. // John said that this code only needs "a" point, not the "last" point.
  3791. //while (m_lastWaypoint && m_lastWaypoint->getLink(0)) {
  3792. // m_lastWaypoint = m_lastWaypoint->getLink(0);
  3793. //}
  3794. ai->setDesiredSpeed(speed);
  3795. return ret;
  3796. }
  3797. //----------------------------------------------------------------------------------------------------------
  3798. void AIFollowWaypointPathExactState::onExit( StateExitType status )
  3799. {
  3800. AIInternalMoveToState::onExit( status );
  3801. // turn off precision-z-pos when we exit, just in case.
  3802. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3803. if (ai) {
  3804. ai->setCompletedWaypoint(m_lastWaypoint);
  3805. ai->setCanPathThroughUnits(false);
  3806. ai->getCurLocomotor()->setAllowInvalidPosition(false); // turn off allow it to move off the map.
  3807. }
  3808. }
  3809. //----------------------------------------------------------------------------------------------------------
  3810. StateReturnType AIFollowWaypointPathExactState::update()
  3811. {
  3812. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3813. if (ai) ai->setCanPathThroughUnits(true);
  3814. // do movement
  3815. StateReturnType status = AIInternalMoveToState::update();
  3816. return status;
  3817. }
  3818. //-------------------------------------------------------------------------------------------------
  3819. //-------------------------------------------------------------------------------------------------
  3820. //-------------------------------------------------------------------------------------------------
  3821. //-------------------------------------------------------------------------------------------------
  3822. //-------------------------------------------------------------------------------------------------
  3823. //-------------------------------------------------------------------------------------------------
  3824. AIAttackFollowWaypointPathState::AIAttackFollowWaypointPathState ( StateMachine *machine, Bool asGroup ) :
  3825. AIFollowWaypointPathState ( machine, asGroup, false )
  3826. {
  3827. #ifdef STATE_MACHINE_DEBUG
  3828. setName("AIAttackFollowWaypointPathState");
  3829. #endif
  3830. m_attackFollowMachine = newInstance(AIAttackMoveStateMachine)(getMachineOwner(), "AIAttackFollowMachine");
  3831. m_attackFollowMachine->initDefaultState();
  3832. }
  3833. //-------------------------------------------------------------------------------------------------
  3834. AIAttackFollowWaypointPathState::~AIAttackFollowWaypointPathState()
  3835. {
  3836. m_attackFollowMachine->deleteInstance();
  3837. }
  3838. // ------------------------------------------------------------------------------------------------
  3839. /** CRC */
  3840. // ------------------------------------------------------------------------------------------------
  3841. void AIAttackFollowWaypointPathState::crc( Xfer *xfer )
  3842. {
  3843. } // end crc
  3844. // ------------------------------------------------------------------------------------------------
  3845. /** Xfer Method */
  3846. // ------------------------------------------------------------------------------------------------
  3847. void AIAttackFollowWaypointPathState::xfer( Xfer *xfer )
  3848. {
  3849. // version
  3850. XferVersion currentVersion = 1;
  3851. XferVersion version = currentVersion;
  3852. xfer->xferVersion( &version, currentVersion );
  3853. // extend base class
  3854. AIFollowWaypointPathState::xfer( xfer );
  3855. xfer->xferSnapshot(m_attackFollowMachine);
  3856. } // end xfer
  3857. // ------------------------------------------------------------------------------------------------
  3858. /** Load post process */
  3859. // ------------------------------------------------------------------------------------------------
  3860. void AIAttackFollowWaypointPathState::loadPostProcess( void )
  3861. {
  3862. } // end loadPostProcess
  3863. #ifdef STATE_MACHINE_DEBUG
  3864. //----------------------------------------------------------------------------------------------------------
  3865. AsciiString AIAttackFollowWaypointPathState::getName( ) const
  3866. {
  3867. AsciiString name = m_name;
  3868. name.concat("/");
  3869. if (m_attackFollowMachine) name.concat(m_attackFollowMachine->getCurrentStateName());
  3870. else name.concat("*NULL m_attackFollowMachine");
  3871. return name;
  3872. }
  3873. #endif
  3874. //-------------------------------------------------------------------------------------------------
  3875. StateReturnType AIAttackFollowWaypointPathState ::onEnter()
  3876. {
  3877. m_attackFollowMachine->clear();
  3878. m_attackFollowMachine->setState( AI_IDLE );
  3879. return AIFollowWaypointPathState::onEnter();
  3880. }
  3881. //-------------------------------------------------------------------------------------------------
  3882. StateReturnType AIAttackFollowWaypointPathState::update()
  3883. {
  3884. Object *owner = getMachineOwner();
  3885. AIUpdateInterface *ai = owner->getAI();
  3886. Bool forceRetargetThisFrame = false;
  3887. Bool shouldRepathThisFrame = false;
  3888. if (!m_attackFollowMachine->isInIdleState())
  3889. {
  3890. ai->setLocomotorGoalNone();
  3891. owner->clearModelConditionState(MODELCONDITION_MOVING);
  3892. m_attackFollowMachine->updateStateMachine();
  3893. // if the machine is now idling, then we need to attempt to get a new target
  3894. if (m_attackFollowMachine->isInIdleState())
  3895. {
  3896. forceRetargetThisFrame = true;
  3897. shouldRepathThisFrame = true;
  3898. }
  3899. else
  3900. {
  3901. return STATE_CONTINUE;
  3902. }
  3903. }
  3904. if (m_attackFollowMachine->isInIdleState())
  3905. {
  3906. // Check to see if we have created a crate we need to pick up.
  3907. Object* crate = ai->checkForCrateToPickup();
  3908. if (crate)
  3909. {
  3910. m_attackFollowMachine->setGoalObject(crate);
  3911. m_attackFollowMachine->setState( AI_PICK_UP_CRATE );
  3912. return STATE_CONTINUE;
  3913. }
  3914. Object* nextObjectToAttack;
  3915. {
  3916. nextObjectToAttack = ai->getNextMoodTarget( !forceRetargetThisFrame, false );
  3917. }
  3918. if (nextObjectToAttack != NULL)
  3919. {
  3920. m_attackFollowMachine->setGoalObject(nextObjectToAttack);
  3921. m_attackFollowMachine->setState( AI_ATTACK_OBJECT );
  3922. shouldRepathThisFrame = false; // we're about to drop out of this function, but this is semantic emphasis.
  3923. // we don't want an update to take place 'till next frame.
  3924. return STATE_CONTINUE;
  3925. }
  3926. }
  3927. if (shouldRepathThisFrame)
  3928. {
  3929. // Update the goal waypoint if we've moved along the path.
  3930. computeGoal(m_moveAsGroup);
  3931. computePath();
  3932. }
  3933. return AIFollowWaypointPathState::update();
  3934. }
  3935. //-------------------------------------------------------------------------------------------------
  3936. void AIAttackFollowWaypointPathState ::onExit( StateExitType status )
  3937. {
  3938. m_attackFollowMachine->setState(AI_IDLE);
  3939. AIFollowWaypointPathState::onExit(status);
  3940. }
  3941. //----------------------------------------------------------------------------------------------------------
  3942. //----------------------------------------------------------------------------------------------------------
  3943. //----------------------------------------------------------------------------------------------------------
  3944. //----------------------------------------------------------------------------------------------------------
  3945. //----------------------------------------------------------------------------------------------------------
  3946. /**
  3947. * Wander along a waypoint path.
  3948. */
  3949. // ------------------------------------------------------------------------------------------------
  3950. /** CRC */
  3951. // ------------------------------------------------------------------------------------------------
  3952. void AIWanderState::crc( Xfer *xfer )
  3953. {
  3954. AIFollowWaypointPathState::crc(xfer);
  3955. } // end crc
  3956. // ------------------------------------------------------------------------------------------------
  3957. /** Xfer Method */
  3958. // ------------------------------------------------------------------------------------------------
  3959. void AIWanderState::xfer( Xfer *xfer )
  3960. {
  3961. // version
  3962. XferVersion currentVersion = 1;
  3963. XferVersion version = currentVersion;
  3964. xfer->xferVersion( &version, currentVersion );
  3965. AIFollowWaypointPathState::xfer(xfer);
  3966. xfer->xferInt(&m_waitFrames);
  3967. xfer->xferInt(&m_timer);
  3968. } // end xfer
  3969. // ------------------------------------------------------------------------------------------------
  3970. /** Load post process */
  3971. // ------------------------------------------------------------------------------------------------
  3972. void AIWanderState::loadPostProcess( void )
  3973. {
  3974. AIFollowWaypointPathState::loadPostProcess();
  3975. } // end loadPostProcess
  3976. // ------------------------------------------------------------------------------------------------
  3977. // ------------------------------------------------------------------------------------------------
  3978. StateReturnType AIWanderState::onEnter()
  3979. {
  3980. m_currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  3981. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3982. m_priorWaypoint = NULL;
  3983. if (m_currentWaypoint == NULL || ai==NULL)
  3984. return STATE_FAILURE;
  3985. m_groupOffset.x = m_groupOffset.y = 0;
  3986. Locomotor* curLoco = ai->getCurLocomotor();
  3987. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  3988. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  3989. if (delta<1) delta = 1;
  3990. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3991. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3992. }
  3993. m_timer = 0;
  3994. m_waitFrames = 10 + (getMachineOwner()->getID() & 0x7);
  3995. // set initial movement goal
  3996. computeGoal(false);
  3997. StateReturnType ret = AIInternalMoveToState::onEnter();
  3998. ai->setPathExtraDistance(calcExtraPathDistance());
  3999. return ret;
  4000. }
  4001. //----------------------------------------------------------------------------------------------------------
  4002. StateReturnType AIWanderState::update()
  4003. {
  4004. // do movement
  4005. Object *obj = getMachineOwner();
  4006. StateReturnType status = AIInternalMoveToState::update();
  4007. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED)) {
  4008. m_timer--;
  4009. if (m_timer<0) {
  4010. m_timer = m_waitFrames;
  4011. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  4012. if (enemy) {
  4013. return STATE_FAILURE;
  4014. }
  4015. }
  4016. }
  4017. // if move to has finished, move to next point on waypoint path
  4018. if (status != STATE_CONTINUE)
  4019. {
  4020. AIUpdateInterface *ai = obj->getAI();
  4021. m_currentWaypoint = getNextWaypoint();
  4022. // if there are no links from this waypoint, we're done
  4023. if (m_currentWaypoint == NULL) {
  4024. /// Trigger "end of waypoint path" scripts (jba)
  4025. ai->setCompletedWaypoint(m_priorWaypoint);
  4026. return STATE_SUCCESS;
  4027. }
  4028. Locomotor* curLoco = ai->getCurLocomotor();
  4029. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  4030. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  4031. if (delta<1) delta = 1;
  4032. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4033. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4034. }
  4035. computeGoal(false);
  4036. computePath();
  4037. return STATE_CONTINUE;
  4038. }
  4039. // Never leave this state until told to.
  4040. return STATE_CONTINUE;
  4041. }
  4042. //----------------------------------------------------------------------------------------------------------
  4043. void AIWanderState::onExit( StateExitType status )
  4044. {
  4045. AIFollowWaypointPathState::onExit( status );
  4046. }
  4047. //----------------------------------------------------------------------------------------------------------
  4048. //----------------------------------------------------------------------------------------------------------
  4049. //----------------------------------------------------------------------------------------------------------
  4050. //----------------------------------------------------------------------------------------------------------
  4051. //----------------------------------------------------------------------------------------------------------
  4052. /**
  4053. * Wander around a point.
  4054. */
  4055. // ------------------------------------------------------------------------------------------------
  4056. /** CRC */
  4057. // ------------------------------------------------------------------------------------------------
  4058. void AIWanderInPlaceState::crc( Xfer *xfer )
  4059. {
  4060. AIInternalMoveToState::crc(xfer);
  4061. } // end crc
  4062. // ------------------------------------------------------------------------------------------------
  4063. /** Xfer Method */
  4064. // ------------------------------------------------------------------------------------------------
  4065. void AIWanderInPlaceState::xfer( Xfer *xfer )
  4066. {
  4067. // version
  4068. XferVersion currentVersion = 1;
  4069. XferVersion version = currentVersion;
  4070. xfer->xferVersion( &version, currentVersion );
  4071. AIInternalMoveToState::xfer(xfer);
  4072. xfer->xferCoord3D(&m_origin);
  4073. xfer->xferInt(&m_waitFrames);
  4074. xfer->xferInt(&m_timer);
  4075. } // end xfer
  4076. // ------------------------------------------------------------------------------------------------
  4077. /** LoadPostProcess */
  4078. // ------------------------------------------------------------------------------------------------
  4079. void AIWanderInPlaceState::loadPostProcess( void )
  4080. {
  4081. AIInternalMoveToState::loadPostProcess();
  4082. } // end loadPostProcess
  4083. // ------------------------------------------------------------------------------------------------
  4084. StateReturnType AIWanderInPlaceState::onEnter()
  4085. {
  4086. m_origin = *getMachineOwner()->getPosition();
  4087. AIUpdateInterface *ai = getMachineOwner()->getAI();
  4088. if (ai) {
  4089. ai->chooseLocomotorSet(LOCOMOTORSET_WANDER);
  4090. }
  4091. Int delta = 3;
  4092. if (ai->getCurLocomotor()) {
  4093. delta = REAL_TO_INT_FLOOR( (ai->getCurLocomotor()->getWanderAboutPointRadius()/PATHFIND_CELL_SIZE_F) + 0.5f);
  4094. }
  4095. Coord3D offset;
  4096. offset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4097. offset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4098. m_goalPosition = m_origin;
  4099. m_goalPosition.x += offset.x;
  4100. m_goalPosition.y += offset.y;
  4101. m_timer = 0;
  4102. m_waitFrames = 10 + (getMachineOwner()->getID() & 0x7);
  4103. StateReturnType ret = AIInternalMoveToState::onEnter();
  4104. return ret;
  4105. }
  4106. //----------------------------------------------------------------------------------------------------------
  4107. StateReturnType AIWanderInPlaceState::update()
  4108. {
  4109. // do movement
  4110. StateReturnType status = AIInternalMoveToState::update();
  4111. Object *obj = getMachineOwner();
  4112. AIUpdateInterface *ai = getMachineOwner()->getAI();
  4113. if (!ai) return STATE_FAILURE;
  4114. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED)) {
  4115. m_timer--;
  4116. if (m_timer<0) {
  4117. m_timer = m_waitFrames;
  4118. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  4119. if (enemy) {
  4120. return STATE_FAILURE;
  4121. }
  4122. }
  4123. }
  4124. // if move to has finished, move to next point on waypoint path
  4125. if (status != STATE_CONTINUE)
  4126. {
  4127. Int delta = 3;
  4128. if (ai->getCurLocomotor()) {
  4129. delta = REAL_TO_INT_FLOOR( (ai->getCurLocomotor()->getWanderAboutPointRadius()/PATHFIND_CELL_SIZE_F) + 0.5f);
  4130. }
  4131. Coord3D offset;
  4132. offset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4133. offset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4134. m_goalPosition = m_origin;
  4135. m_goalPosition.x += offset.x;
  4136. m_goalPosition.y += offset.y;
  4137. AIInternalMoveToState::onEnter();
  4138. return STATE_CONTINUE;
  4139. }
  4140. // Never leave this state until told to.
  4141. return STATE_CONTINUE;
  4142. }
  4143. //----------------------------------------------------------------------------------------------------------
  4144. void AIWanderInPlaceState::onExit( StateExitType status )
  4145. {
  4146. AIInternalMoveToState::onExit( status );
  4147. }
  4148. //----------------------------------------------------------------------------------------------------------
  4149. //----------------------------------------------------------------------------------------------------------
  4150. //----------------------------------------------------------------------------------------------------------
  4151. //----------------------------------------------------------------------------------------------------------
  4152. // ------------------------------------------------------------------------------------------------
  4153. /** CRC */
  4154. // ------------------------------------------------------------------------------------------------
  4155. void AIPanicState::crc( Xfer *xfer )
  4156. {
  4157. AIFollowWaypointPathState::crc(xfer);
  4158. } // end crc
  4159. // ------------------------------------------------------------------------------------------------
  4160. /** Xfer Method */
  4161. // ------------------------------------------------------------------------------------------------
  4162. void AIPanicState::xfer( Xfer *xfer )
  4163. {
  4164. // version
  4165. XferVersion currentVersion = 1;
  4166. XferVersion version = currentVersion;
  4167. xfer->xferVersion( &version, currentVersion );
  4168. AIFollowWaypointPathState::xfer(xfer);
  4169. xfer->xferInt(&m_waitFrames);
  4170. xfer->xferInt(&m_timer);
  4171. } // end xfer
  4172. // ------------------------------------------------------------------------------------------------
  4173. /** Load post process */
  4174. // ------------------------------------------------------------------------------------------------
  4175. void AIPanicState::loadPostProcess( void )
  4176. {
  4177. AIFollowWaypointPathState::loadPostProcess();
  4178. } // end loadPostProcess
  4179. /**
  4180. * Panic and run screaming along a waypoint path.
  4181. */
  4182. StateReturnType AIPanicState::onEnter()
  4183. {
  4184. m_currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  4185. Object *obj = getMachineOwner();
  4186. AIUpdateInterface *ai = obj->getAI();
  4187. if (m_currentWaypoint == NULL)
  4188. return STATE_FAILURE;
  4189. // set initial movement goal
  4190. Locomotor* curLoco = ai->getCurLocomotor();
  4191. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  4192. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  4193. if (delta<1) delta = 1;
  4194. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4195. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4196. }
  4197. computeGoal(false);
  4198. StateReturnType ret = AIInternalMoveToState::onEnter();
  4199. m_timer = 0;
  4200. m_waitFrames = 10 + (getMachineOwner()->getID() & 0x7);
  4201. // Update the extra path distance. AIInternalMoveToState::onEnter resets it.
  4202. ai->setPathExtraDistance(calcExtraPathDistance());
  4203. if (obj)
  4204. {
  4205. obj->setModelConditionState(MODELCONDITION_PANICKING);
  4206. }
  4207. return ret;
  4208. }
  4209. //----------------------------------------------------------------------------------------------------------
  4210. StateReturnType AIPanicState::update()
  4211. {
  4212. // do movement
  4213. StateReturnType status = AIInternalMoveToState::update();
  4214. Object *obj = getMachineOwner();
  4215. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED)) {
  4216. m_timer--;
  4217. if (m_timer<0) {
  4218. m_timer = m_waitFrames;
  4219. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  4220. if (enemy) {
  4221. return STATE_FAILURE;
  4222. }
  4223. }
  4224. }
  4225. // if move to has finished, move to next point on waypoint path
  4226. if (status == STATE_SUCCESS)
  4227. {
  4228. Object *obj = getMachineOwner();
  4229. AIUpdateInterface *ai = obj->getAI();
  4230. m_currentWaypoint = getNextWaypoint();
  4231. // if there are no links from this waypoint, we're done
  4232. if (m_currentWaypoint == NULL) {
  4233. /// Trigger "end of waypoint path" scripts (jba)
  4234. ai->setCompletedWaypoint(m_priorWaypoint);
  4235. return STATE_SUCCESS;
  4236. }
  4237. Locomotor* curLoco = ai->getCurLocomotor();
  4238. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  4239. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  4240. if (delta<1) delta = 1;
  4241. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4242. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4243. }
  4244. computeGoal(false);
  4245. computePath();
  4246. return STATE_CONTINUE;
  4247. }
  4248. // Never leave this state until told to.
  4249. return STATE_CONTINUE;
  4250. }
  4251. //----------------------------------------------------------------------------------------------------------
  4252. void AIPanicState::onExit( StateExitType status )
  4253. {
  4254. Object *obj = getMachineOwner();
  4255. obj->clearModelConditionState(MODELCONDITION_PANICKING);
  4256. AIInternalMoveToState::onExit( status );
  4257. }
  4258. //----------------------------------------------------------------------------------------------------------
  4259. //----------------------------------------------------------------------------------------------------------
  4260. //----------------------------------------------------------------------------------------------------------
  4261. // ------------------------------------------------------------------------------------------------
  4262. /** CRC */
  4263. // ------------------------------------------------------------------------------------------------
  4264. void AIAttackAimAtTargetState::crc( Xfer *xfer )
  4265. {
  4266. } // end crc
  4267. // ------------------------------------------------------------------------------------------------
  4268. /** Xfer Method */
  4269. // ------------------------------------------------------------------------------------------------
  4270. void AIAttackAimAtTargetState::xfer( Xfer *xfer )
  4271. {
  4272. // version
  4273. XferVersion currentVersion = 1;
  4274. XferVersion version = currentVersion;
  4275. xfer->xferVersion( &version, currentVersion );
  4276. xfer->xferBool(&m_canTurnInPlace);
  4277. xfer->xferBool(&m_setLocomotor);
  4278. } // end xfer
  4279. // ------------------------------------------------------------------------------------------------
  4280. /** Load post process */
  4281. // ------------------------------------------------------------------------------------------------
  4282. void AIAttackAimAtTargetState::loadPostProcess( void )
  4283. {
  4284. } // end loadPostProcess
  4285. //----------------------------------------------------------------------------------------------------------
  4286. StateReturnType AIAttackAimAtTargetState::onEnter()
  4287. {
  4288. // contained by AIAttackState, so no separate timer
  4289. Object* source = getMachineOwner();
  4290. Weapon* weapon = source->getCurrentWeapon();
  4291. Object* victim = getMachineGoalObject();
  4292. const Coord3D* targetPos = getMachineGoalPosition();
  4293. AIUpdateInterface* sourceAI = source->getAI();
  4294. AIUpdateInterface* victimAI = victim ? victim->getAI() : NULL;
  4295. Locomotor* curLoco = sourceAI->getCurLocomotor();
  4296. m_canTurnInPlace = curLoco ? curLoco->getMinSpeed() == 0.0f : false;
  4297. // if (!victim)
  4298. // return STATE_CONTINUE; // Just continue till we get a victim.
  4299. // Ick. This was originally a safety to a single line that required victim, and was never meant
  4300. // as an early return to all cases. We now want to use preattack frames on ground position targets
  4301. Bool inFiringRange = FALSE;
  4302. //If the object is garrisoning a building, then we want to force the object
  4303. //to move to the best fire point, check if it's in firing range, and if not
  4304. //move it back so another unit with longer range can!
  4305. Object *containedBy = source->getContainedBy();
  4306. ContainModuleInterface *contain = containedBy ? containedBy->getContain() : NULL;
  4307. if( containedBy && weapon && contain && contain->isEnclosingContainerFor( source ) )
  4308. { // non enclosing garrison containers do not use firepoints. Lorenzen, 6/11/03
  4309. if (victim)
  4310. {
  4311. inFiringRange = contain->attemptBestFirePointPosition( source, weapon, victim );
  4312. }
  4313. else
  4314. {
  4315. inFiringRange = contain->attemptBestFirePointPosition( source, weapon, targetPos );
  4316. }
  4317. }
  4318. else if( victim && weapon )
  4319. inFiringRange = weapon->isWithinAttackRange( source, victim );
  4320. else if( weapon )
  4321. inFiringRange = weapon->isWithinAttackRange( source, targetPos );//See, I can be attacking the ground. Perfectly valid.
  4322. else
  4323. return STATE_FAILURE; // can't happen.
  4324. // add ourself as a targeter BEFORE calling isTemporarilyPreventingAimSuccess().
  4325. if (victimAI)
  4326. victimAI->addTargeter(source->getID(), true);
  4327. if( sourceAI->areTurretsLinked() )
  4328. {
  4329. //Order all turrets to attack.
  4330. for( Int i = 0; i < MAX_TURRETS; i++ )
  4331. {
  4332. if( m_isAttackingObject )
  4333. {
  4334. sourceAI->setTurretTargetObject( (WhichTurretType)i, victim, m_isForceAttacking );
  4335. }
  4336. else
  4337. {
  4338. sourceAI->setTurretTargetPosition( (WhichTurretType)i, getMachineGoalPosition() );
  4339. }
  4340. }
  4341. }
  4342. else
  4343. {
  4344. WhichTurretType tur = sourceAI->getWhichTurretForCurWeapon();
  4345. if (tur != TURRET_INVALID)
  4346. {
  4347. //Order specific turret to attack.
  4348. if (m_isAttackingObject)
  4349. {
  4350. sourceAI->setTurretTargetObject(tur, victim, m_isForceAttacking);
  4351. }
  4352. else
  4353. {
  4354. sourceAI->setTurretTargetPosition(tur, getMachineGoalPosition());
  4355. }
  4356. }
  4357. else
  4358. {
  4359. // GS moved contact weapon check in here, because Success can never be given to a unit in this state
  4360. // using a turret to attack. Check out ::update and you will see.
  4361. Bool preventing = victimAI && victimAI->isTemporarilyPreventingAimSuccess();
  4362. // Contact weapons don't aim. They just go boom. jba.
  4363. if( weapon && weapon->isContactWeapon() && inFiringRange && !preventing )
  4364. return STATE_SUCCESS;
  4365. }
  4366. }
  4367. m_setLocomotor = false;
  4368. source->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IS_AIMING_WEAPON ) );
  4369. return STATE_CONTINUE;
  4370. }
  4371. //----------------------------------------------------------------------------------------------------------
  4372. /**
  4373. * Orient the machine's owner to face towards the given target
  4374. */
  4375. StateReturnType AIAttackAimAtTargetState::update()
  4376. {
  4377. // contained by AIAttackState, so no separate timer
  4378. Object* source = getMachineOwner();
  4379. AIUpdateInterface* sourceAI = source->getAI();
  4380. if (!source->hasAnyWeapon())
  4381. return STATE_FAILURE;
  4382. Object* victim = getMachineGoalObject();
  4383. if (m_isAttackingObject)
  4384. {
  4385. if (!victim || victim->isEffectivelyDead())
  4386. return STATE_FAILURE; // can't aim at dead things
  4387. }
  4388. WhichTurretType tur = sourceAI->getWhichTurretForCurWeapon();
  4389. if (tur != TURRET_INVALID)
  4390. {
  4391. if (m_isAttackingObject)
  4392. {
  4393. sourceAI->setTurretTargetObject(tur, victim, m_isForceAttacking);
  4394. }
  4395. else
  4396. {
  4397. sourceAI->setTurretTargetPosition(tur, getMachineGoalPosition());
  4398. }
  4399. // if we have a turret, but it is incapable of turning, turn ourself.
  4400. // (gotta do this for units like the Comanche, which have fake "turrets"
  4401. // solely to allow for attacking-on-the-move...)
  4402. if (sourceAI->getTurretTurnRate(tur) != 0.0f)
  4403. {
  4404. // The Body can never return Success if the weapon is on the turret, or else we end
  4405. // up shooting the current weapon (which is on the turret) in the wrong direction.
  4406. // We always say Continue, so the Turret can do its own Aiming state.
  4407. // if (m_isAttackingObject && source->canCrushOrSquish(victim)) {
  4408. // return STATE_SUCCESS;
  4409. // }
  4410. return STATE_CONTINUE;
  4411. }
  4412. // else fall thru!
  4413. }
  4414. // no else here!
  4415. {
  4416. Real relAngle = m_isAttackingObject ?
  4417. ThePartitionManager->getRelativeAngle2D( source, victim ) :
  4418. ThePartitionManager->getRelativeAngle2D( source, getMachineGoalPosition() );
  4419. const Real REL_THRESH = 0.035f; // about 2 degrees. (getRelativeAngle2D is current only accurate to about 1.25 degrees)
  4420. Weapon* weapon = source->getCurrentWeapon();
  4421. Real aimDelta = weapon ? weapon->getAimDelta() : 0.0f;
  4422. if (aimDelta < REL_THRESH)
  4423. {
  4424. aimDelta = REL_THRESH;
  4425. }
  4426. //DEBUG_LOG(("AIM: desired %f, actual %f, delta %f, aimDelta %f, goalpos %f %f\n",rad2deg(obj->getOrientation() + relAngle),rad2deg(obj->getOrientation()),rad2deg(relAngle),rad2deg(aimDelta),victim->getPosition()->x,victim->getPosition()->y));
  4427. if (m_canTurnInPlace)
  4428. {
  4429. if (fabs(relAngle) > aimDelta)
  4430. {
  4431. Real desiredAngle = source->getOrientation() + relAngle;
  4432. sourceAI->setLocomotorGoalOrientation(desiredAngle);
  4433. m_setLocomotor = true;
  4434. }
  4435. }
  4436. else
  4437. {
  4438. sourceAI->setLocomotorGoalPositionExplicit(m_isAttackingObject ? *victim->getPosition() : *getMachineGoalPosition());
  4439. }
  4440. if (fabs(relAngle) < aimDelta /*&& !m_preAttackFrames*/ )
  4441. {
  4442. AIUpdateInterface* victimAI = victim ? victim->getAI() : NULL;
  4443. // add ourself as a targeter BEFORE calling isTemporarilyPreventingAimSuccess().
  4444. // we do this every time thru, just in case we get into a squabble with our turret-ai
  4445. // over whether or not we are a targeter... (srj)
  4446. if (victimAI)
  4447. victimAI->addTargeter(source->getID(), true);
  4448. Bool preventing = victimAI && victimAI->isTemporarilyPreventingAimSuccess();
  4449. if (preventing)
  4450. {
  4451. return STATE_CONTINUE;
  4452. }
  4453. else
  4454. {
  4455. return STATE_SUCCESS;
  4456. }
  4457. }
  4458. }
  4459. if (source->isDisabledByType(DISABLED_HELD))
  4460. {
  4461. // We are contained by something (transport, building). This means we can't
  4462. // actually move to the location and if we are firing on a specific target
  4463. // and that target is no longer in range, then we need to abort the state
  4464. // so it can fire on other targets.
  4465. // Are we still in range?
  4466. Weapon *weapon = source->getCurrentWeapon();
  4467. // NO BAD WRONG!!! How can this be the one spot to convert an Object to a center pos? We have
  4468. // an attack object check for a reason! The center and the edge can be very far apart.
  4469. // const Coord3D *pos = m_isAttackingObject ? victim->getPosition() : getMachineGoalPosition();
  4470. Bool inRange = FALSE;
  4471. if( m_isAttackingObject )
  4472. inRange = weapon ? weapon->isWithinAttackRange(source, victim) : FALSE;
  4473. else
  4474. inRange = weapon ? weapon->isWithinAttackRange(source, getMachineGoalPosition()) : FALSE;
  4475. if( !weapon || !inRange )
  4476. {
  4477. // We're no longer in range, so exit with failure so we can automatically
  4478. // reacquire a closer target if possible.
  4479. return STATE_FAILURE;
  4480. }
  4481. }
  4482. return STATE_CONTINUE;
  4483. }
  4484. //----------------------------------------------------------------------------------------------------------
  4485. void AIAttackAimAtTargetState::onExit( StateExitType status )
  4486. {
  4487. // contained by AIAttackState, so no separate timer
  4488. if (m_canTurnInPlace)
  4489. {
  4490. AIUpdateInterface* sourceAI = getMachineOwner()->getAI();
  4491. // Tell the ai we are done moving, if we set the locomotor goal.
  4492. if (sourceAI && m_setLocomotor)
  4493. sourceAI->setLocomotorGoalNone();
  4494. }
  4495. else
  4496. {
  4497. // don't do the loco call, or else we will "wiggle"... we already have an appropriate goal
  4498. }
  4499. getMachineOwner()->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IS_AIMING_WEAPON ) );
  4500. //getMachineOwner()->clearModelConditionState( MODELCONDITION_PREATTACK );
  4501. }
  4502. //----------------------------------------------------------------------------------------------------------
  4503. //----------------------------------------------------------------------------------------------------------
  4504. //----------------------------------------------------------------------------------------------------------
  4505. //----------------------------------------------------------------------------------------------------------
  4506. /**
  4507. * Start firing.
  4508. */
  4509. StateReturnType AIAttackFireWeaponState::onEnter()
  4510. {
  4511. // contained by AIAttackState, so no separate timer
  4512. DEBUG_ASSERTCRASH(m_att != NULL, ("m_att may not be null"));
  4513. Object *obj = getMachineOwner();
  4514. AIUpdateInterface *ai = obj->getAI();
  4515. // Passive stuff will approach but not attack, so we check here (after approach is complete)
  4516. UnsignedInt adjust = ai->getMoodMatrixActionAdjustment(MM_Action_Attack);
  4517. if ((adjust & MAA_Action_Ok) == 0)
  4518. {
  4519. return STATE_FAILURE;
  4520. }
  4521. Object *victim = getMachineGoalObject();
  4522. if (victim && obj->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget) {
  4523. if (obj->getTeam()->getTeamTargetObject()==NULL) {
  4524. obj->getTeam()->setTeamTargetObject(victim);
  4525. }
  4526. }
  4527. obj->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IS_FIRING_WEAPON ) );
  4528. obj->preFireCurrentWeapon( getMachineGoalObject() );
  4529. return STATE_CONTINUE;
  4530. }
  4531. //----------------------------------------------------------------------------------------------------------
  4532. /**
  4533. * Fire the owner's weapon once and exit.
  4534. */
  4535. StateReturnType AIAttackFireWeaponState::update()
  4536. {
  4537. // contained by AIAttackState, so no separate timer
  4538. Object *obj = getMachineOwner();
  4539. Object* victim = getMachineGoalObject();
  4540. if (m_att->isAttackingObject())
  4541. {
  4542. // if our target is dead, go ahead and stop.
  4543. if (!victim || victim->isEffectivelyDead())
  4544. return STATE_FAILURE;
  4545. }
  4546. WeaponSlotType wslot;
  4547. Weapon* weapon = obj->getCurrentWeapon(&wslot);
  4548. if (!weapon)
  4549. {
  4550. return STATE_FAILURE;
  4551. }
  4552. WeaponStatus status = weapon->getStatus();
  4553. if (status == PRE_ATTACK)
  4554. {
  4555. return STATE_CONTINUE;
  4556. }
  4557. else if (status != READY_TO_FIRE)
  4558. {
  4559. return STATE_FAILURE;
  4560. }
  4561. /**
  4562. this is the weird case where we have multi turrets, and turret 'a' wants
  4563. to fire, but someone has changed the current weapon to be one not on him.
  4564. rather than addressing the situation, we just punt and wait for it to clear
  4565. up on its own.
  4566. */
  4567. if (m_att && !m_att->isWeaponSlotOkToFire(wslot))
  4568. {
  4569. return STATE_FAILURE;
  4570. }
  4571. // must adjust the state BEFORE calling fireWeapon, for FX to work correctly...
  4572. obj->setFiringConditionForCurrentWeapon();
  4573. if (m_att->isAttackingObject())
  4574. {
  4575. // Since it is very late in the project, and there is no call for such code...
  4576. // there is currently no support here for linked turrets, as regards Attacking Objects (victims)
  4577. // If the concept of linked turrets is further developed then God help you, and put more code right here
  4578. // that lookl like the //LINKED TURRETS// block, below
  4579. obj->fireCurrentWeapon(victim);
  4580. //Kris: October 21, 2003 - Patch 1.01
  4581. //Fixes cases where some units couldn't transfer their attack to a different object. One example was Colonel Burton attacking
  4582. //any GLA structure. When the structure was destroyed becoming a hole, Burton would stop attacking. Even though there is code
  4583. //to transfer attackers (AIUpdateInterface::transferAttack), it is unable to modify our current victim in our attack state
  4584. //machine. When we move immediately to the aim state in the same frame as the transfer (after this call in fact), the victim
  4585. //was still pointing to the building and not the hole we transferred to. This code fixes that.
  4586. if( victim != obj->getAI()->getCurrentVictim() )
  4587. {
  4588. getMachine()->setGoalObject( obj->getAI()->getCurrentVictim() );
  4589. }
  4590. // clear this, just in case.
  4591. obj->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IGNORING_STEALTH ) );
  4592. Real continueRange = weapon->getContinueAttackRange();
  4593. if (
  4594. continueRange > 0.0f &&
  4595. victim &&
  4596. (victim->isDestroyed() || victim->isEffectivelyDead() || (victim->isKindOf(KINDOF_MINE) && victim->testStatus(OBJECT_STATUS_MASKED)))
  4597. )
  4598. {
  4599. const Coord3D* originalVictimPos = m_att ? m_att->getOriginalVictimPos() : NULL;
  4600. if (originalVictimPos)
  4601. {
  4602. // note that it is important to use getLastCommandSource here; this allows
  4603. // dozers that were ordered to clear mines by the human to continue to autoacquire,
  4604. // but not if they were ordered by ai.
  4605. AIUpdateInterface* ai = obj->getAI();
  4606. CommandSourceType lastCmdSource = ai ? ai->getLastCommandSource() : CMD_FROM_AI;
  4607. PartitionFilterSamePlayer filterPlayer( victim->getControllingPlayer() );
  4608. PartitionFilterSameMapStatus filterMapStatus(obj);
  4609. PartitionFilterPossibleToAttack filterAttack(ATTACK_NEW_TARGET, obj, lastCmdSource);
  4610. PartitionFilter *filters[] = { &filterAttack, &filterPlayer, &filterMapStatus, NULL };
  4611. // note that we look around originalVictimPos, *not* the current victim's pos.
  4612. victim = ThePartitionManager->getClosestObject( originalVictimPos, continueRange, FROM_CENTER_2D, filters );// could be null. this is ok.
  4613. if (victim)
  4614. {
  4615. getMachine()->setGoalObject(victim);
  4616. m_att->notifyNewVictimChosen(victim);
  4617. }
  4618. }
  4619. }
  4620. }
  4621. else
  4622. {
  4623. if( getMachineOwner()->getAI()->areTurretsLinked() ) //LINKED TURRETS
  4624. {// it doesn;t matter which weapon slot is locked, current or whatever
  4625. for ( Int slot = PRIMARY_WEAPON; slot < WEAPONSLOT_COUNT ; slot++ )
  4626. {// were firing with all barrels
  4627. Weapon *weapon = obj->getWeaponInWeaponSlot( (WeaponSlotType)slot );
  4628. if ( weapon )
  4629. {
  4630. if ( weapon->fireWeapon(obj, getMachineGoalPosition()) ) //fire() returns 'reloaded'
  4631. obj->releaseWeaponLock(LOCKED_TEMPORARILY);// unlock, 'cause we're loaded
  4632. obj->notifyFiringTrackerShotFired(weapon, INVALID_ID);
  4633. }
  4634. }
  4635. }
  4636. else
  4637. obj->fireCurrentWeapon(getMachineGoalPosition());
  4638. // clear this, just in case.
  4639. obj->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IGNORING_STEALTH ) );
  4640. }
  4641. m_att->notifyFired();
  4642. return STATE_SUCCESS;
  4643. }
  4644. //----------------------------------------------------------------------------------------------------------
  4645. /**
  4646. Stop firing.
  4647. */
  4648. void AIAttackFireWeaponState::onExit( StateExitType status )
  4649. {
  4650. // contained by AIAttackState, so no separate timer
  4651. Object *obj = getMachineOwner();
  4652. obj->clearStatus( MAKE_OBJECT_STATUS_MASK2( OBJECT_STATUS_IS_FIRING_WEAPON, OBJECT_STATUS_IGNORING_STEALTH ) );
  4653. // this can occur if we start a preattack (eg, bayonet)
  4654. // and the target moves out range before we can actually "fire"...
  4655. // leaving us thinking we're still "pre attacking". cancel this state
  4656. // to avoid confusion. (srj)
  4657. Weapon* weapon = obj->getCurrentWeapon();
  4658. if (weapon && weapon->getStatus() == PRE_ATTACK)
  4659. {
  4660. weapon->setPreAttackFinishedFrame(0);
  4661. }
  4662. }
  4663. //----------------------------------------------------------------------------------------------------------
  4664. //----------------------------------------------------------------------------------------------------------
  4665. //----------------------------------------------------------------------------------------------------------
  4666. //----------------------------------------------------------------------------------------------------------
  4667. /**
  4668. * Do nothing for a period of time.
  4669. */
  4670. StateReturnType AIWaitState::update()
  4671. {
  4672. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  4673. return STATE_CONTINUE;
  4674. }
  4675. //----------------------------------------------------------------------------------------------------------
  4676. //----------------------------------------------------------------------------------------------------------
  4677. //----------------------------------------------------------------------------------------------------------
  4678. //----------------------------------------------------------------------------------------------------------
  4679. AIAttackState::AIAttackState( StateMachine *machine, Bool follow, Bool attackingObject, Bool forceAttacking, AttackExitConditionsInterface* attackParameters) :
  4680. State( machine , "AIAttackState"),
  4681. m_attackMachine(NULL),
  4682. m_attackParameters(attackParameters),
  4683. m_lockedWeaponOnEnter(NULL),
  4684. m_follow(follow),
  4685. m_isAttackingObject(attackingObject),
  4686. m_isForceAttacking(forceAttacking),
  4687. m_victimTeam( NULL )
  4688. {
  4689. m_originalVictimPos.zero();
  4690. #ifdef STATE_MACHINE_DEBUG
  4691. if (machine->getWantsDebugOutput()) {
  4692. DEBUG_LOG(("Creating attack state follow %d, attacking object %d, force attacking %d\n",
  4693. follow, attackingObject, forceAttacking));
  4694. }
  4695. #endif
  4696. }
  4697. //----------------------------------------------------------------------------------------------------------
  4698. AIAttackState::~AIAttackState()
  4699. {
  4700. // nope, don't do this, since we may well still have it targeted
  4701. // even though we're leaving this state.
  4702. // turn it off when we do setCurrentVictim(NULL).
  4703. //addSelfAsTargeter(false);
  4704. if (m_attackMachine)
  4705. {
  4706. m_attackMachine->halt();
  4707. m_attackMachine->deleteInstance();
  4708. }
  4709. }
  4710. // ------------------------------------------------------------------------------------------------
  4711. /** CRC */
  4712. // ------------------------------------------------------------------------------------------------
  4713. void AIAttackState::crc( Xfer *xfer )
  4714. {
  4715. } // end crc
  4716. // ------------------------------------------------------------------------------------------------
  4717. /** Xfer Method */
  4718. // ------------------------------------------------------------------------------------------------
  4719. void AIAttackState::xfer( Xfer *xfer )
  4720. {
  4721. // version
  4722. XferVersion currentVersion = 1;
  4723. XferVersion version = currentVersion;
  4724. xfer->xferVersion( &version, currentVersion );
  4725. Bool hasMachine = m_attackMachine!=NULL;
  4726. xfer->xferBool(&hasMachine);
  4727. xfer->xferCoord3D(&m_originalVictimPos);
  4728. if (hasMachine && m_attackMachine==NULL) {
  4729. // create new state machine for attack behavior
  4730. m_attackMachine = newInstance(AttackStateMachine)(getMachineOwner(), this, "AIAttackMachine", m_follow, m_isAttackingObject, m_isForceAttacking );
  4731. }
  4732. if (hasMachine) {
  4733. xfer->xferSnapshot(m_attackMachine); ///< state sub-machine for attack behavior
  4734. }
  4735. /* Not saved or loaded - passed in on creation.
  4736. Bool m_follow;
  4737. Bool m_isAttackingObject; // if false, attacking position
  4738. AttackExitConditionsInterface* m_attackParameters; ///< these are not owned by this, and will not be deleted on destruction
  4739. Bool m_isForceAttacking
  4740. */
  4741. } // end xfer
  4742. // ------------------------------------------------------------------------------------------------
  4743. /** Load post process */
  4744. // ------------------------------------------------------------------------------------------------
  4745. void AIAttackState::loadPostProcess( void )
  4746. {
  4747. Object* victim = getMachineGoalObject();
  4748. if (victim)
  4749. {
  4750. m_victimTeam = victim->getTeam();
  4751. }
  4752. Object* source = getMachineOwner();
  4753. m_lockedWeaponOnEnter = source->isCurWeaponLocked() ? source->getCurrentWeapon() : NULL;
  4754. } // end loadPostProcess
  4755. #ifdef STATE_MACHINE_DEBUG
  4756. //----------------------------------------------------------------------------------------------------------
  4757. AsciiString AIAttackState::getName( ) const
  4758. {
  4759. AsciiString name = m_name;
  4760. name.concat("/");
  4761. if (m_attackMachine) name.concat(m_attackMachine->getCurrentStateName());
  4762. else name.concat("*NULL m_attackMachine");
  4763. return name;
  4764. }
  4765. #endif
  4766. //----------------------------------------------------------------------------------------------------------
  4767. Bool AIAttackState::chooseWeapon()
  4768. {
  4769. Object* victim = getMachineGoalObject();
  4770. if (m_isAttackingObject && !victim)
  4771. return FALSE;
  4772. Object* source = getMachineOwner();
  4773. AIUpdateInterface *ai = source->getAI();
  4774. Bool found = FALSE;
  4775. // if (victim) // Pardon? We still need to pick a weapon if we are attacking the ground.
  4776. // {
  4777. found = source->chooseBestWeaponForTarget(victim, PREFER_MOST_DAMAGE, ai->getLastCommandSource());
  4778. //DEBUG_ASSERTLOG(found, ("unable to autochoose any weapon for %s\n",source->getTemplate()->getName().str()));
  4779. // }
  4780. // Check if we need to update because of the weapon choice switch.
  4781. source->adjustModelConditionForWeaponStatus();
  4782. return found;
  4783. }
  4784. //----------------------------------------------------------------------------------------------------------
  4785. void AIAttackState::notifyNewVictimChosen(Object* victim)
  4786. {
  4787. // do NOT update m_originalVictimPos here. It's a new victim, not the original!
  4788. getMachine()->setGoalObject(victim);
  4789. if (m_attackMachine)
  4790. m_attackMachine->setGoalObject(victim);
  4791. }
  4792. //----------------------------------------------------------------------------------------------------------
  4793. /**
  4794. * Begin an attack on the machine's goal object.
  4795. * To do this complex behavior, instantiate another state machine as a "sub-machine" of
  4796. * the attack state.
  4797. */
  4798. DECLARE_PERF_TIMER(AIAttackState)
  4799. StateReturnType AIAttackState::onEnter()
  4800. {
  4801. USE_PERF_TIMER(AIAttackState)
  4802. //CRCDEBUG_LOG(("AIAttackState::onEnter() - start for object %d\n", getMachineOwner()->getID()));
  4803. Object* source = getMachineOwner();
  4804. AIUpdateInterface *ai = source->getAI();
  4805. // if we are in sleep mode, we will not attack
  4806. if ((ai->getMoodMatrixActionAdjustment(MM_Action_Attack) & MAA_Action_Ok) == 0)
  4807. return STATE_SUCCESS;
  4808. // if we've met the conditions specified by m_attackParameters, we consider ourselves "successful."
  4809. if (m_attackParameters && m_attackParameters->shouldExit(getMachine()))
  4810. return STATE_SUCCESS;
  4811. //Kris: Jan 12, 2005
  4812. //Don't allow units under construction to attack! The selection/action manager system was responsible for preventing this
  4813. //from ever happening, but failed in two cases which I fixed. This is an extra check to mitigate cheats.
  4814. if( source->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  4815. {
  4816. return STATE_FAILURE;
  4817. }
  4818. // if all of our weapons are out of ammo, can't attack.
  4819. // (this can happen for units which never auto-reload, like the Raptor)
  4820. if (source->isOutOfAmmo() && !source->isKindOf(KINDOF_PROJECTILE))
  4821. return STATE_FAILURE;
  4822. // create new state machine for attack behavior
  4823. //CRCDEBUG_LOG(("AIAttackState::onEnter() - constructing state machine for object %d\n", getMachineOwner()->getID()));
  4824. m_attackMachine = newInstance(AttackStateMachine)(source, this, "AIAttackMachine", m_follow, m_isAttackingObject, m_isForceAttacking );
  4825. #ifdef STATE_MACHINE_DEBUG
  4826. m_attackMachine->setDebugOutput(getMachine()->getWantsDebugOutput());
  4827. #endif
  4828. // tell the attack machine who the victim of the attack is
  4829. if (m_isAttackingObject)
  4830. {
  4831. Object* victim = getMachineGoalObject();
  4832. if (victim == NULL || victim->isEffectivelyDead())
  4833. {
  4834. ai->notifyVictimIsDead();
  4835. return STATE_FAILURE; // we have nothing to attack!
  4836. }
  4837. m_victimTeam = victim->getTeam();
  4838. m_attackMachine->setGoalObject( victim );
  4839. m_originalVictimPos = *victim->getPosition();
  4840. }
  4841. else
  4842. {
  4843. m_attackMachine->setGoalPosition(getMachineGoalPosition());
  4844. m_originalVictimPos = *getMachineGoalPosition();
  4845. }
  4846. // Something can happen to make none of our weapons work. Return failure, or we will start shooting
  4847. // our Primary (default pick) regardless of legality.
  4848. Bool weaponPicked = chooseWeapon();
  4849. if( !weaponPicked )
  4850. return STATE_FAILURE;
  4851. Weapon* curWeapon = source->getCurrentWeapon();
  4852. if (curWeapon)
  4853. {
  4854. curWeapon->setMaxShotCount(NO_MAX_SHOTS_LIMIT);
  4855. // icky special case for ignoring stealth units we might be targeting, that are currently stealthed. (srj)
  4856. if (curWeapon->getContinueAttackRange() > 0.0f)
  4857. source->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IGNORING_STEALTH ) );
  4858. }
  4859. m_lockedWeaponOnEnter = source->isCurWeaponLocked() ? curWeapon : NULL;
  4860. StateReturnType retType = m_attackMachine->initDefaultState();
  4861. if( retType == STATE_CONTINUE )
  4862. {
  4863. source->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_IS_ATTACKING ) );
  4864. source->setModelConditionState( MODELCONDITION_ATTACKING );
  4865. }
  4866. return retType;
  4867. }
  4868. //----------------------------------------------------------------------------------------------------------
  4869. /**
  4870. * Execute one frame of "attack enemy" behavior.
  4871. */
  4872. StateReturnType AIAttackState::update()
  4873. {
  4874. USE_PERF_TIMER(AIAttackState)
  4875. // if we've met the conditions specified by m_attackParameters, we consider ourselves "successful."
  4876. if (m_attackParameters && m_attackParameters->shouldExit(getMachine()))
  4877. {
  4878. return STATE_SUCCESS;
  4879. }
  4880. Object* source = getMachineOwner();
  4881. // if all of our weapons are out of ammo, can't attack.
  4882. // (this can happen for units which never auto-reload, like the Raptor)
  4883. if (source->isOutOfAmmo() && !source->isKindOf(KINDOF_PROJECTILE))
  4884. {
  4885. return STATE_FAILURE;
  4886. }
  4887. if (m_isAttackingObject)
  4888. {
  4889. Object* victim = getMachineGoalObject();
  4890. if (victim == NULL || victim->isEffectivelyDead())
  4891. {
  4892. source->getAI()->notifyVictimIsDead();
  4893. return STATE_SUCCESS; // my, that was easy
  4894. }
  4895. if (victim)
  4896. {
  4897. source->getAI()->setCurrentVictim(victim);
  4898. }
  4899. if( victim->getTeam() != m_victimTeam )
  4900. {
  4901. // If, while I have been attacking my victim, it has lost its ability to attack
  4902. //(a recently de-garrisoned building) I should bail here...
  4903. // We are not sure whether the problem occurs here or sometime before, but this is an edge case failsafe for it
  4904. // Steven calls this hack 'greasy,' and I agreesy.-Lorenzen
  4905. AIUpdateInterface *ai = source->getAI();
  4906. if (ai)
  4907. {
  4908. if( !victim->getStatusBits().test( OBJECT_STATUS_CAN_ATTACK ) )
  4909. {
  4910. if ( victim->getContain() != NULL )
  4911. {
  4912. if (victim->getContain()->isGarrisonable() && (victim->getContain()->getContainCount() == 0) )
  4913. {
  4914. if ( source->getRelationship( victim ) == NEUTRAL )
  4915. {
  4916. ai->friend_setGoalObject(NULL);
  4917. if (victim==source->getTeam()->getTeamTargetObject()) {
  4918. source->getTeam()->setTeamTargetObject(NULL);
  4919. }
  4920. ai->notifyVictimIsDead(); // well, not "dead", but longer attackable
  4921. return STATE_FAILURE;
  4922. }
  4923. }
  4924. }
  4925. }
  4926. }
  4927. //The team of the victim has changed since we began attacking it. Evaluate
  4928. //whether or not we should keep attacking it.
  4929. // order matters: we want to know if I consider it to be an enemy, not vice versa
  4930. if( source->getRelationship( victim ) != ENEMIES)
  4931. {
  4932. ai->friend_setGoalObject(NULL);
  4933. if (victim==source->getTeam()->getTeamTargetObject()) {
  4934. source->getTeam()->setTeamTargetObject(NULL);
  4935. }
  4936. ai->notifyVictimIsDead(); // well, not "dead", but longer attackable
  4937. return STATE_FAILURE;
  4938. }
  4939. }
  4940. if (victim != m_attackMachine->getGoalObject())
  4941. {
  4942. // Our parent machine has changed the goal. We need to reset to the new goal. jba.
  4943. m_attackMachine->setGoalObject( victim );
  4944. }
  4945. }
  4946. // re-evaluate our weapon choice every frame, so the sub-states don't have to.
  4947. // Something can happen to make none of our weapons work. Return failure, or we will start shooting
  4948. // our Primary (default pick) regardless of legality.
  4949. Bool weaponPicked = chooseWeapon();
  4950. if( !weaponPicked )
  4951. return STATE_FAILURE;
  4952. Weapon* curWeapon = source->getCurrentWeapon();
  4953. // if we entered with a locked weapon (ie, a special weapon), then we will
  4954. // only keep attacking as long as that weapon remains the cur weapon...
  4955. // if anything ever changes that weapon, we exit attack mode immediately.
  4956. if (m_lockedWeaponOnEnter != NULL && m_lockedWeaponOnEnter != curWeapon)
  4957. return STATE_FAILURE;
  4958. // we've shot as many times as we are allowed to
  4959. if (curWeapon == NULL || curWeapon->getMaxShotCount() <= 0)
  4960. return STATE_FAILURE;
  4961. /**
  4962. * Run the attack state sub-machine.
  4963. * If the attack state machine returns anything other than CONTINUE,
  4964. * it has finished. Propagating the return code will cause
  4965. * the containing state machine to do the right thing.
  4966. * Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  4967. * sleeps, we still need to be called every frame.
  4968. */
  4969. return CONVERT_SLEEP_TO_CONTINUE(m_attackMachine->updateStateMachine());
  4970. }
  4971. //----------------------------------------------------------------------------------------------------------
  4972. void AIAttackState::onExit( StateExitType status )
  4973. {
  4974. USE_PERF_TIMER(AIAttackState)
  4975. // nope, don't do this, since we may well still have it targeted
  4976. // even though we're leaving this state. turn it off when we
  4977. // turn it off when we do setCurrentVictim(NULL).
  4978. //addSelfAsTargeter(false);
  4979. // destroy the attack machine
  4980. if (m_attackMachine)
  4981. {
  4982. m_attackMachine->deleteInstance();
  4983. m_attackMachine = NULL;
  4984. }
  4985. Object *obj = getMachineOwner();
  4986. obj->clearStatus( MAKE_OBJECT_STATUS_MASK4( OBJECT_STATUS_IS_FIRING_WEAPON,
  4987. OBJECT_STATUS_IS_AIMING_WEAPON,
  4988. OBJECT_STATUS_IS_ATTACKING,
  4989. OBJECT_STATUS_IGNORING_STEALTH ) );
  4990. obj->clearModelConditionState( MODELCONDITION_ATTACKING );
  4991. obj->clearLeechRangeModeForAllWeapons();
  4992. AIUpdateInterface *ai = obj->getAI();
  4993. if (ai)
  4994. {
  4995. //ai->notifyVictimIsDead(); no, do NOT do this here.
  4996. ai->setCurrentVictim(NULL);
  4997. for (int i = 0; i < MAX_TURRETS; ++i)
  4998. ai->setTurretTargetObject((WhichTurretType)i, NULL, NULL);
  4999. ai->friend_setGoalObject(NULL);
  5000. }
  5001. }
  5002. //-------------------------------------------------------------------------------------------------
  5003. //-------------------------------------------------------------------------------------------------
  5004. //-------------------------------------------------------------------------------------------------
  5005. //-----------------------------------------------------------------------------------------------------------
  5006. class AIAttackThenIdleStateMachine : public StateMachine
  5007. {
  5008. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( AIAttackThenIdleStateMachine, "AIAttackThenIdleStateMachine" );
  5009. public:
  5010. AIAttackThenIdleStateMachine( Object *owner, AsciiString name );
  5011. protected:
  5012. // snapshot interface .
  5013. virtual void crc( Xfer *xfer );
  5014. virtual void xfer( Xfer *xfer );
  5015. virtual void loadPostProcess();
  5016. };
  5017. // ------------------------------------------------------------------------------------------------
  5018. /** CRC */
  5019. // ------------------------------------------------------------------------------------------------
  5020. void AIAttackThenIdleStateMachine::crc( Xfer *xfer )
  5021. {
  5022. StateMachine::crc(xfer);
  5023. } // end crc
  5024. // ------------------------------------------------------------------------------------------------
  5025. /** Xfer Method */
  5026. // ------------------------------------------------------------------------------------------------
  5027. void AIAttackThenIdleStateMachine::xfer( Xfer *xfer )
  5028. {
  5029. XferVersion cv = 1;
  5030. XferVersion v = cv;
  5031. xfer->xferVersion( &v, cv );
  5032. StateMachine::xfer(xfer);
  5033. } // end xfer
  5034. // ------------------------------------------------------------------------------------------------
  5035. /** Load post process */
  5036. // ------------------------------------------------------------------------------------------------
  5037. void AIAttackThenIdleStateMachine::loadPostProcess( void )
  5038. {
  5039. StateMachine::loadPostProcess();
  5040. } // end loadPostProcess
  5041. //-----------------------------------------------------------------------------------------------------------
  5042. AIAttackThenIdleStateMachine::AIAttackThenIdleStateMachine(Object *owner, AsciiString name) : StateMachine(owner, name)
  5043. {
  5044. // order matters: first state is the default state.
  5045. defineState( AI_ATTACK_OBJECT, newInstance(AIAttackState)(this, false, true, false, NULL ), AI_IDLE, AI_IDLE );
  5046. defineState( AI_PICK_UP_CRATE, newInstance(AIPickUpCrateState)( this ), AI_IDLE, AI_IDLE );
  5047. defineState( AI_IDLE, newInstance(AIIdleState)( this, AIIdleState::DO_NOT_LOOK_FOR_TARGETS ), AI_IDLE, AI_IDLE );
  5048. }
  5049. //----------------------------------------------------------------------------------------------------------
  5050. AIAttackThenIdleStateMachine::~AIAttackThenIdleStateMachine()
  5051. {
  5052. }
  5053. //----------------------------------------------------------------------------------------------------------
  5054. //----------------------------------------------------------------------------------------------------------
  5055. //----------------------------------------------------------------------------------------------------------
  5056. //----------------------------------------------------------------------------------------------------------
  5057. AIAttackSquadState::~AIAttackSquadState()
  5058. {
  5059. if (m_attackSquadMachine) {
  5060. m_attackSquadMachine->halt();
  5061. m_attackSquadMachine->deleteInstance();
  5062. }
  5063. }
  5064. // ------------------------------------------------------------------------------------------------
  5065. /** CRC */
  5066. // ------------------------------------------------------------------------------------------------
  5067. void AIAttackSquadState::crc( Xfer *xfer )
  5068. {
  5069. } // end crc
  5070. // ------------------------------------------------------------------------------------------------
  5071. /** Xfer Method */
  5072. // ------------------------------------------------------------------------------------------------
  5073. void AIAttackSquadState::xfer( Xfer *xfer )
  5074. {
  5075. // version
  5076. XferVersion currentVersion = 1;
  5077. XferVersion version = currentVersion;
  5078. xfer->xferVersion( &version, currentVersion );
  5079. Bool hasMachine = m_attackSquadMachine!=NULL;
  5080. xfer->xferBool(&hasMachine);
  5081. if (hasMachine && m_attackSquadMachine==NULL) {
  5082. // create new state machine for attack behavior
  5083. m_attackSquadMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackMachine" );
  5084. }
  5085. if (hasMachine) {
  5086. xfer->xferSnapshot(m_attackSquadMachine);
  5087. }
  5088. } // end xfer
  5089. // ------------------------------------------------------------------------------------------------
  5090. /** Load post process */
  5091. // ------------------------------------------------------------------------------------------------
  5092. void AIAttackSquadState::loadPostProcess( void )
  5093. {
  5094. } // end loadPostProcess
  5095. #ifdef STATE_MACHINE_DEBUG
  5096. //----------------------------------------------------------------------------------------------------------
  5097. AsciiString AIAttackSquadState::getName( ) const
  5098. {
  5099. AsciiString name = m_name;
  5100. name.concat("/");
  5101. if (m_attackSquadMachine) name.concat(m_attackSquadMachine->getCurrentStateName());
  5102. else name.concat("*NULL m_attackSquadMachine");
  5103. return name;
  5104. }
  5105. #endif
  5106. //----------------------------------------------------------------------------------------------------------
  5107. /**
  5108. * Begin an attack on the machine's goal team.
  5109. * To do this, we use a sub attack machine.
  5110. */
  5111. StateReturnType AIAttackSquadState::onEnter( void )
  5112. {
  5113. // create new state machine for attack behavior
  5114. m_attackSquadMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackMachine" );
  5115. Object *victim = chooseVictim();
  5116. // tell the attack machine who the victim of the attack is
  5117. m_attackSquadMachine->setGoalObject( victim );
  5118. // initial state of attack state machine
  5119. return m_attackSquadMachine->initDefaultState();
  5120. }
  5121. //----------------------------------------------------------------------------------------------------------
  5122. /**
  5123. * Execute one frame of "attack enemy" behavior.
  5124. */
  5125. StateReturnType AIAttackSquadState::update( void )
  5126. {
  5127. if( !m_attackSquadMachine )
  5128. {
  5129. return STATE_FAILURE;
  5130. }
  5131. /*
  5132. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  5133. sleeps, we still need to be called every frame.
  5134. */
  5135. StateReturnType attackStatus = CONVERT_SLEEP_TO_CONTINUE(m_attackSquadMachine->updateStateMachine());
  5136. // if we're in attack state,
  5137. if (m_attackSquadMachine->getCurrentStateID() != AI_IDLE)
  5138. {
  5139. return attackStatus;
  5140. }
  5141. // Check to see if we have created a crate we need to pick up.
  5142. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5143. Object* crate = ai->checkForCrateToPickup();
  5144. if (crate)
  5145. {
  5146. m_attackSquadMachine->setGoalObject(crate);
  5147. m_attackSquadMachine->setState( AI_PICK_UP_CRATE );
  5148. return STATE_CONTINUE;
  5149. }
  5150. // choose a new target and start over.
  5151. Object *victim = chooseVictim();
  5152. if (!victim)
  5153. {
  5154. return STATE_SUCCESS;
  5155. }
  5156. m_attackSquadMachine->setGoalObject( victim );
  5157. m_attackSquadMachine->setState(AI_ATTACK_OBJECT);
  5158. return STATE_CONTINUE;
  5159. }
  5160. //----------------------------------------------------------------------------------------------------------
  5161. void AIAttackSquadState::onExit( StateExitType status )
  5162. {
  5163. if( m_attackSquadMachine )
  5164. {
  5165. // destroy the attack machine
  5166. m_attackSquadMachine->deleteInstance();
  5167. m_attackSquadMachine = NULL;
  5168. }
  5169. }
  5170. //----------------------------------------------------------------------------------------------------------
  5171. Object *AIAttackSquadState::chooseVictim(void)
  5172. {
  5173. Squad *victimSquad = ((AIStateMachine*)getMachine())->getGoalSquad();
  5174. if (!victimSquad)
  5175. {
  5176. return NULL;
  5177. }
  5178. Object *owner = getMachineOwner();
  5179. AIUpdateInterface *ai = owner->getAI();
  5180. UnsignedInt moodVal = ai->getMoodMatrixValue();
  5181. if (moodVal & MM_Controller_AI)
  5182. {
  5183. if (moodVal & MM_Mood_Sleep)
  5184. {
  5185. return NULL;
  5186. }
  5187. if (moodVal & MM_Mood_Passive)
  5188. {
  5189. BodyModuleInterface *bmi = owner->getBodyModule();
  5190. if (!bmi) {
  5191. return NULL;
  5192. }
  5193. const DamageInfo *di = bmi->getLastDamageInfo();
  5194. if (!di)
  5195. {
  5196. return NULL;
  5197. }
  5198. return TheGameLogic->findObjectByID(di->in.m_sourceID);
  5199. }
  5200. }
  5201. GameDifficulty difficulty = owner->getControllingPlayer()->getPlayerDifficulty();
  5202. const CommandSourceType cmdSource = ai->getLastCommandSource();
  5203. if (cmdSource == CMD_FROM_PLAYER)
  5204. {
  5205. // if a player did this, we want to always give them the Seek and obliterate method.
  5206. difficulty = DIFFICULTY_HARD;
  5207. }
  5208. if (TheScriptEngine->getChooseVictimAlwaysUsesNormal())
  5209. {
  5210. difficulty = DIFFICULTY_NORMAL;
  5211. }
  5212. switch(difficulty)
  5213. {
  5214. case DIFFICULTY_EASY:
  5215. {
  5216. // pick a random unit
  5217. VecObjectPtr objects = victimSquad->getLiveObjects();
  5218. Int numUnits = objects.size();
  5219. if (numUnits == 0)
  5220. {
  5221. return NULL;
  5222. }
  5223. Int unitToAttack = GameLogicRandomValue(0, numUnits - 1);
  5224. return objects[unitToAttack];
  5225. break;
  5226. }
  5227. case DIFFICULTY_NORMAL:
  5228. {
  5229. // pick the closest unit
  5230. PartitionFilterAcceptOnSquad f1(victimSquad);
  5231. PartitionFilterSameMapStatus filterMapStatus(getMachineOwner());
  5232. PartitionFilter *filters[] = { &f1, &filterMapStatus, NULL };
  5233. Object *victim = ThePartitionManager->getClosestObject(getMachineOwner(), HUGE_DIST, FROM_CENTER_2D, filters, NULL, NULL);
  5234. return victim;
  5235. break;
  5236. }
  5237. case DIFFICULTY_HARD:
  5238. {
  5239. // everyone picks the same unit
  5240. VecObjectPtr objects = victimSquad->getLiveObjects();
  5241. if (objects.size() > 0)
  5242. {
  5243. return objects[0];
  5244. }
  5245. return NULL;
  5246. break;
  5247. }
  5248. };
  5249. return NULL;
  5250. }
  5251. //----------------------------------------------------------------------------------------------------------
  5252. //----------------------------------------------------------------------------------------------------------
  5253. //----------------------------------------------------------------------------------------------------------
  5254. //----------------------------------------------------------------------------------------------------------
  5255. AIDockState::~AIDockState()
  5256. {
  5257. if (m_dockMachine) {
  5258. m_dockMachine->halt();
  5259. m_dockMachine->deleteInstance();
  5260. }
  5261. }
  5262. // ------------------------------------------------------------------------------------------------
  5263. /** CRC */
  5264. // ------------------------------------------------------------------------------------------------
  5265. void AIDockState::crc( Xfer *xfer )
  5266. {
  5267. } // end crc
  5268. // ------------------------------------------------------------------------------------------------
  5269. /** Xfer Method */
  5270. // ------------------------------------------------------------------------------------------------
  5271. void AIDockState::xfer( Xfer *xfer )
  5272. {
  5273. // version
  5274. XferVersion currentVersion = 1;
  5275. XferVersion version = currentVersion;
  5276. xfer->xferVersion( &version, currentVersion );
  5277. Bool hasMachine = m_dockMachine!=NULL;
  5278. xfer->xferBool(&hasMachine);
  5279. if (hasMachine && m_dockMachine==NULL) {
  5280. // create new state machine for attack behavior
  5281. m_dockMachine = newInstance(AIDockMachine)( getMachineOwner());
  5282. }
  5283. if (hasMachine) {
  5284. xfer->xferSnapshot(m_dockMachine);
  5285. }
  5286. xfer->xferBool(&m_usingPrecisionMovement);
  5287. } // end xfer
  5288. // ------------------------------------------------------------------------------------------------
  5289. /** Load post process */
  5290. // ------------------------------------------------------------------------------------------------
  5291. void AIDockState::loadPostProcess( void )
  5292. {
  5293. } // end loadPostProcess
  5294. #ifdef STATE_MACHINE_DEBUG
  5295. //----------------------------------------------------------------------------------------------------------
  5296. AsciiString AIDockState::getName( ) const
  5297. {
  5298. AsciiString name = m_name;
  5299. name.concat("/");
  5300. if (m_dockMachine) name.concat(m_dockMachine->getCurrentStateName());
  5301. else name.concat("*NULL m_dockMachine");
  5302. return name;
  5303. }
  5304. #endif
  5305. //----------------------------------------------------------------------------------------------
  5306. /**
  5307. * Dock with the GoalObject.
  5308. * When we enter the AI_DOCK state, create a docking state machine
  5309. * that implements the details of the docking behavior.
  5310. */
  5311. StateReturnType AIDockState::onEnter()
  5312. {
  5313. // who are we docking with?
  5314. Object *dockWithMe = getMachineGoalObject();
  5315. if (dockWithMe == NULL)
  5316. {
  5317. // we have nothing to dock with!
  5318. DEBUG_LOG(("No goal in AIDockState::onEnter - exiting.\n"));
  5319. return STATE_FAILURE;
  5320. }
  5321. DockUpdateInterface *dock = NULL;
  5322. dock = dockWithMe->getDockUpdateInterface();
  5323. // if we have nothing to dock with, fail
  5324. if (dock == NULL) {
  5325. DEBUG_LOG(("Goal is not a dock in AIDockState::onEnter - exiting.\n"));
  5326. return STATE_FAILURE;
  5327. }
  5328. // tell the pathfinder to ignore the object we are docking with, so it doesn't block us
  5329. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5330. if( ai )
  5331. {
  5332. ai->ignoreObstacle( dockWithMe );
  5333. }
  5334. // create new state machine for attack behavior
  5335. m_dockMachine = newInstance(AIDockMachine)( getMachineOwner());
  5336. // tell the docking machine what it is docking with
  5337. m_dockMachine->setGoalObject( dockWithMe );
  5338. // now that essential parameters are set, set the machine's initial state
  5339. return m_dockMachine->initDefaultState( );
  5340. }
  5341. /**
  5342. * For whatever reason, we are leaving the AI_DOCK state.
  5343. * Destroy the docking sub-machine.
  5344. */
  5345. void AIDockState::onExit( StateExitType status )
  5346. {
  5347. // destroy the dock machine
  5348. if (m_dockMachine) {
  5349. m_dockMachine->halt();// GS, you have to halt before you delete to do cleanup.
  5350. m_dockMachine->deleteInstance();
  5351. m_dockMachine = NULL;
  5352. } else {
  5353. DEBUG_LOG(("Dock exited immediately\n"));
  5354. }
  5355. // stop ignoring our goal object
  5356. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5357. if (ai)
  5358. {
  5359. ai->setCanPathThroughUnits(false);
  5360. ai->ignoreObstacle( NULL );
  5361. }
  5362. }
  5363. /**
  5364. * We are in the AI_DOCK state, execute the docking behavior.
  5365. */
  5366. StateReturnType AIDockState::update()
  5367. {
  5368. /**
  5369. * Run the docking state sub-machine.
  5370. * If the dock state machine returns anything other than CONTINUE,
  5371. * it has finished. propagating the return code will cause
  5372. * the containing state machine to do the right thing.
  5373. */
  5374. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5375. if (ai)
  5376. {
  5377. ai->setCanPathThroughUnits(true);
  5378. //if (ai->isBlockedAndStuck()) {
  5379. //DEBUG_LOG(("Blocked and stuck.\n"));
  5380. //}
  5381. //if (ai->getNumFramesBlocked()>5) {
  5382. //DEBUG_LOG(("Blocked %d frames\n", ai->getNumFramesBlocked()));
  5383. //}
  5384. }
  5385. /*
  5386. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  5387. sleeps, we still need to be called every frame.
  5388. */
  5389. return CONVERT_SLEEP_TO_CONTINUE(m_dockMachine->updateStateMachine());
  5390. }
  5391. //----------------------------------------------------------------------------------------------------------
  5392. //----------------------------------------------------------------------------------------------------------
  5393. //----------------------------------------------------------------------------------------------------------
  5394. // ------------------------------------------------------------------------------------------------
  5395. /** CRC */
  5396. // ------------------------------------------------------------------------------------------------
  5397. void AIEnterState::crc( Xfer *xfer )
  5398. {
  5399. AIInternalMoveToState::crc(xfer);
  5400. } // end crc
  5401. // ------------------------------------------------------------------------------------------------
  5402. /** Xfer Method */
  5403. // ------------------------------------------------------------------------------------------------
  5404. void AIEnterState::xfer( Xfer *xfer )
  5405. {
  5406. // version
  5407. XferVersion currentVersion = 1;
  5408. XferVersion version = currentVersion;
  5409. xfer->xferVersion( &version, currentVersion );
  5410. AIInternalMoveToState::xfer(xfer);
  5411. xfer->xferObjectID(&m_entryToClear);
  5412. } // end xfer
  5413. // ------------------------------------------------------------------------------------------------
  5414. /** Load post process */
  5415. // ------------------------------------------------------------------------------------------------
  5416. void AIEnterState::loadPostProcess( void )
  5417. {
  5418. AIInternalMoveToState::loadPostProcess();
  5419. } // end loadPostProcess
  5420. //----------------------------------------------------------------------------------------------------------
  5421. StateReturnType AIEnterState::onEnter()
  5422. {
  5423. m_entryToClear = INVALID_ID;
  5424. Object* obj = getMachineOwner();
  5425. Object* goal = getMachineGoalObject();
  5426. if (goal)
  5427. {
  5428. if( !TheActionManager->canEnterObject( obj, goal, obj->getAI()->getLastCommandSource(), CHECK_CAPACITY ) )
  5429. return STATE_FAILURE;
  5430. m_goalPosition = *goal->getPosition();
  5431. ContainModuleInterface* contain = goal->getContain();
  5432. if (contain)
  5433. {
  5434. contain->onObjectWantsToEnterOrExit(obj, WANTS_TO_ENTER);
  5435. m_entryToClear = goal->getID();
  5436. }
  5437. }
  5438. else
  5439. {
  5440. return STATE_FAILURE;
  5441. }
  5442. // tell the pathfinder to ignore the enterable object
  5443. AIUpdateInterface *ai = obj->getAI();
  5444. ai->ignoreObstacle( getMachineGoalObject() );
  5445. if (ai->getCurLocomotor())
  5446. {
  5447. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  5448. }
  5449. setAdjustsDestination(false);
  5450. return AIInternalMoveToState::onEnter();
  5451. }
  5452. //----------------------------------------------------------------------------------------------------------
  5453. void AIEnterState::onExit( StateExitType status )
  5454. {
  5455. Object* obj = getMachineOwner();
  5456. AIInternalMoveToState::onExit( status );
  5457. // tell the pathfinder to stop ignoring the object
  5458. AIUpdateInterface *ai = obj->getAI();
  5459. if (ai)
  5460. {
  5461. ai->ignoreObstacle( NULL );
  5462. if (ai->getCurLocomotor())
  5463. {
  5464. ai->getCurLocomotor()->setAllowInvalidPosition(false);
  5465. }
  5466. }
  5467. // use this, rather than getMachineGoalObject, in case the goal
  5468. // is killed while we were waiting...
  5469. if (m_entryToClear != INVALID_ID)
  5470. {
  5471. Object* goal = TheGameLogic->findObjectByID(m_entryToClear);
  5472. if (goal)
  5473. {
  5474. ContainModuleInterface* contain = goal->getContain();
  5475. if (contain)
  5476. {
  5477. contain->onObjectWantsToEnterOrExit(obj, WANTS_NEITHER);
  5478. }
  5479. }
  5480. }
  5481. }
  5482. //----------------------------------------------------------------------------------------------------------
  5483. StateReturnType AIEnterState::update()
  5484. {
  5485. // update the goal position to coincide with the GoalObject
  5486. Object* obj = getMachineOwner();
  5487. Object* goal = getMachineGoalObject();
  5488. if (goal)
  5489. {
  5490. // if our goal is contained by something else, give up. this is for the following bug:
  5491. // -- tell some rangers to enter a humvee
  5492. // -- tell the humvee to enter a chinook
  5493. // -- fly the chinook around; the rangers follow the chinook like dopes
  5494. // this just bails in this case. (srj)
  5495. if (goal->getContainedBy() != NULL && goal->isAboveTerrain() && !obj->isAboveTerrain())
  5496. {
  5497. return STATE_FAILURE;
  5498. }
  5499. m_goalPosition = *goal->getPosition();
  5500. obj->getAI()->friend_setGoalObject(goal);
  5501. if (!TheActionManager->canEnterObject(obj, goal, obj->getAI()->getLastCommandSource(), CHECK_CAPACITY))
  5502. {
  5503. /*
  5504. special-case: if it's an enemy, try attacking it instead. this is to address this bug: (srj)
  5505. Bug: Units stop instead of attacking if building they were trying to garrison is taken by enemy units first.
  5506. 1. any game/any faction
  5507. 2. build infantry units that can garrison neutral buildings
  5508. 3. have infantry units garrison a neutral building, before they garrison the building have some enemy units garrison it first.
  5509. Expected result: Based on test plan: Instead of just stopping when enemy units garrison building first, they should continue and attack the building.
  5510. */
  5511. if( obj->getRelationship(goal) == ENEMIES && obj->getAI() )
  5512. {
  5513. CanAttackResult result = TheActionManager->getCanAttackObject(obj, goal, obj->getAI()->getLastCommandSource(), ATTACK_NEW_TARGET);
  5514. if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  5515. {
  5516. obj->getAI()->aiAttackObject(goal, NO_MAX_SHOTS_LIMIT, obj->getAI()->getLastCommandSource());
  5517. // weird but true. return state_continue, because if we're here, we're actually an attack state
  5518. // since we just changed the state, it doesn't really matter what we return here.
  5519. return STATE_CONTINUE;
  5520. }
  5521. return STATE_FAILURE;
  5522. }
  5523. return STATE_FAILURE;
  5524. }
  5525. // If we are held, then we must have entered the goal.
  5526. if( getMachineOwner()->isDisabledByType( DISABLED_HELD ) )
  5527. {
  5528. return STATE_SUCCESS;
  5529. }
  5530. }
  5531. else
  5532. {
  5533. return STATE_FAILURE;
  5534. }
  5535. StateReturnType code = AIInternalMoveToState::update();
  5536. // if it's airborne, wait for it to land
  5537. if (code == STATE_SUCCESS && goal->isAboveTerrain() && !obj->isAboveTerrain())
  5538. {
  5539. code = STATE_CONTINUE;
  5540. }
  5541. if (code == STATE_SUCCESS)
  5542. {
  5543. // Make sure we entered the container.
  5544. // srj sez: I don't think we want to restrict this to HELD items. See the intro of GLA02.map
  5545. // for an example of guys-off-the-border-but-not-held who need this check.
  5546. //if( obj->isDisabledByType( DISABLED_HELD ) )
  5547. {
  5548. if (goal)
  5549. {
  5550. // we didn't enter. See if we're close.
  5551. Real dx = (obj->getPosition()->x - goal->getPosition()->x);
  5552. Real dy = (obj->getPosition()->y - goal->getPosition()->y);
  5553. Real radius = goal->getGeometryInfo().getMinorRadius();
  5554. if (goal->getGeometryInfo().getGeomType()!=GEOMETRY_BOX) {
  5555. radius = goal->getGeometryInfo().getMajorRadius();
  5556. }
  5557. Bool closeEnough = dx*dx+dy*dy < sqr(radius);
  5558. if (closeEnough) {
  5559. // Grab the container and force ourselves into it.
  5560. // This case is primarily to handle transports on the map border for scripted setup.
  5561. // The partition manager doesn't generate collisions in the border area, so we have to
  5562. // add ourselves. jba.
  5563. ContainModuleInterface* contain = goal->getContain();
  5564. if (contain)
  5565. {
  5566. contain->addToContain(obj);
  5567. }
  5568. }
  5569. }
  5570. }
  5571. }
  5572. return code;
  5573. }
  5574. //----------------------------------------------------------------------------------------------------------
  5575. //----------------------------------------------------------------------------------------------------------
  5576. //----------------------------------------------------------------------------------------------------------
  5577. // ------------------------------------------------------------------------------------------------
  5578. /** CRC */
  5579. // ------------------------------------------------------------------------------------------------
  5580. void AIExitState::crc( Xfer *xfer )
  5581. {
  5582. } // end crc
  5583. // ------------------------------------------------------------------------------------------------
  5584. /** Xfer Method */
  5585. // ------------------------------------------------------------------------------------------------
  5586. void AIExitState::xfer( Xfer *xfer )
  5587. {
  5588. // version
  5589. XferVersion currentVersion = 1;
  5590. XferVersion version = currentVersion;
  5591. xfer->xferVersion( &version, currentVersion );
  5592. xfer->xferObjectID(&m_entryToClear);
  5593. } // end xfer
  5594. // ------------------------------------------------------------------------------------------------
  5595. /** Load post process */
  5596. // ------------------------------------------------------------------------------------------------
  5597. void AIExitState::loadPostProcess( void )
  5598. {
  5599. } // end loadPostProcess
  5600. //----------------------------------------------------------------------------------------------------------
  5601. StateReturnType AIExitState::onEnter()
  5602. {
  5603. m_entryToClear = INVALID_ID;
  5604. Object* obj = getMachineOwner();
  5605. Object* goal = getMachineGoalObject();
  5606. if (goal)
  5607. {
  5608. ContainModuleInterface* contain = goal->getContain();
  5609. if (contain)
  5610. {
  5611. contain->onObjectWantsToEnterOrExit(obj, WANTS_TO_EXIT);
  5612. m_entryToClear = goal->getID();
  5613. }
  5614. return STATE_CONTINUE;
  5615. }
  5616. else
  5617. {
  5618. return STATE_FAILURE;
  5619. }
  5620. }
  5621. //----------------------------------------------------------------------------------------------------------
  5622. StateReturnType AIExitState::update()
  5623. {
  5624. // update the goal position to coincide with the GoalObject
  5625. Object* obj = getMachineOwner();
  5626. Object* goal = getMachineGoalObject();
  5627. if (goal)
  5628. {
  5629. AIUpdateInterface* goalAI = goal->getAI();
  5630. if (goalAI && goalAI->getAiFreeToExit(obj) == WAIT_TO_EXIT)
  5631. return STATE_CONTINUE;
  5632. DEBUG_ASSERTCRASH(obj, ("obj must not be null here"));
  5633. //GS. The goal of unified ExitInterfaces dies a horrible death. I can't ask Object for the exit,
  5634. // as removeFromContain is only in the Contain type. I'm spliting the names in shame.
  5635. ExitInterface* goalExitInterface = goal->getContain() ? goal->getContain()->getContainExitInterface() : NULL;
  5636. if( goalExitInterface == NULL )
  5637. return STATE_FAILURE;
  5638. if( goalExitInterface->isExitBusy() )
  5639. return STATE_CONTINUE;// Just wait a sec.
  5640. ExitDoorType exitDoor = goalExitInterface ? goalExitInterface->reserveDoorForExit(obj->getTemplate(), obj) : DOOR_NONE_NEEDED;
  5641. if (exitDoor == DOOR_NONE_AVAILABLE)
  5642. return STATE_FAILURE;
  5643. goalExitInterface->exitObjectViaDoor(obj, exitDoor);
  5644. if( getMachine()->getCurrentStateID() != getID() )
  5645. return STATE_CONTINUE;// Not sucess, because exitViaDoor has changed us to FollowPath, and if we say Success, our machine will think FollowPath succeeded
  5646. else
  5647. return STATE_SUCCESS;
  5648. }
  5649. else
  5650. {
  5651. return STATE_FAILURE;
  5652. }
  5653. }
  5654. //----------------------------------------------------------------------------------------------------------
  5655. void AIExitState::onExit( StateExitType status )
  5656. {
  5657. Object* obj = getMachineOwner();
  5658. // use this, rather than getMachineGoalObject, in case the goal
  5659. // is killed while we were waiting...
  5660. if (m_entryToClear != INVALID_ID)
  5661. {
  5662. Object* goal = TheGameLogic->findObjectByID(m_entryToClear);
  5663. if (goal)
  5664. {
  5665. ContainModuleInterface* contain = goal->getContain();
  5666. if (contain)
  5667. {
  5668. contain->onObjectWantsToEnterOrExit(obj, WANTS_NEITHER);
  5669. }
  5670. }
  5671. }
  5672. }
  5673. //----------------------------------------------------------------------------------------------------------
  5674. //----------------------------------------------------------------------------------------------------------
  5675. //----------------------------------------------------------------------------------------------------------
  5676. // ------------------------------------------------------------------------------------------------
  5677. /** CRC */
  5678. // ------------------------------------------------------------------------------------------------
  5679. void AIExitInstantlyState::crc( Xfer *xfer )
  5680. {
  5681. } // end crc
  5682. // ------------------------------------------------------------------------------------------------
  5683. /** Xfer Method */
  5684. // ------------------------------------------------------------------------------------------------
  5685. void AIExitInstantlyState::xfer( Xfer *xfer )
  5686. {
  5687. // version
  5688. XferVersion currentVersion = 1;
  5689. XferVersion version = currentVersion;
  5690. xfer->xferVersion( &version, currentVersion );
  5691. xfer->xferObjectID(&m_entryToClear);
  5692. } // end xfer
  5693. // ------------------------------------------------------------------------------------------------
  5694. /** Load post process */
  5695. // ------------------------------------------------------------------------------------------------
  5696. void AIExitInstantlyState::loadPostProcess( void )
  5697. {
  5698. } // end loadPostProcess
  5699. //----------------------------------------------------------------------------------------------------------
  5700. StateReturnType AIExitInstantlyState::onEnter()
  5701. {
  5702. m_entryToClear = INVALID_ID;
  5703. Object* obj = getMachineOwner();
  5704. Object* goal = getMachineGoalObject();
  5705. if (goal)
  5706. {
  5707. ContainModuleInterface* contain = goal->getContain();
  5708. if (contain)
  5709. {
  5710. contain->onObjectWantsToEnterOrExit(obj, WANTS_TO_EXIT);
  5711. m_entryToClear = goal->getID();
  5712. }
  5713. DEBUG_ASSERTCRASH(obj, ("obj must not be null here"));
  5714. //GS. The goal of unified ExitInterfaces dies a horrible death. I can't ask Object for the exit,
  5715. // as removeFromContain is only in the Contain type. I'm spliting the names in shame.
  5716. ExitInterface* goalExitInterface = goal->getContain() ? goal->getContain()->getContainExitInterface() : NULL;
  5717. if( goalExitInterface == NULL )
  5718. return STATE_FAILURE;
  5719. goalExitInterface->exitObjectViaDoor( obj, DOOR_1 );
  5720. return STATE_CONTINUE;// Not success, because exitViaDoor has changed us to FollowPath, and if we say Success, our machine will think FollowPath succeeded
  5721. }
  5722. else
  5723. {
  5724. return STATE_FAILURE;
  5725. }
  5726. }
  5727. //----------------------------------------------------------------------------------------------------------
  5728. StateReturnType AIExitInstantlyState::update()
  5729. {
  5730. if( getMachine()->getCurrentStateID() != getID() )
  5731. {
  5732. return STATE_CONTINUE;// Not success, because exitViaDoor has changed us to FollowPath, and if we say Success, our machine will think FollowPath succeeded
  5733. }
  5734. return STATE_SUCCESS;
  5735. }
  5736. //----------------------------------------------------------------------------------------------------------
  5737. void AIExitInstantlyState::onExit( StateExitType status )
  5738. {
  5739. Object* obj = getMachineOwner();
  5740. // use this, rather than getMachineGoalObject, in case the goal
  5741. // is killed while we were waiting...
  5742. if (m_entryToClear != INVALID_ID)
  5743. {
  5744. Object* goal = TheGameLogic->findObjectByID(m_entryToClear);
  5745. if (goal)
  5746. {
  5747. ContainModuleInterface* contain = goal->getContain();
  5748. if (contain)
  5749. {
  5750. contain->onObjectWantsToEnterOrExit(obj, WANTS_NEITHER);
  5751. }
  5752. }
  5753. }
  5754. }
  5755. //----------------------------------------------------------------------------------------------------------
  5756. //----------------------------------------------------------------------------------------------------------
  5757. //----------------------------------------------------------------------------------------------------------
  5758. //----------------------------------------------------------------------------------------------------------
  5759. AIGuardState::~AIGuardState()
  5760. {
  5761. if (m_guardMachine) {
  5762. m_guardMachine->halt();
  5763. m_guardMachine->deleteInstance();
  5764. }
  5765. }
  5766. #ifdef STATE_MACHINE_DEBUG
  5767. //----------------------------------------------------------------------------------------------------------
  5768. AsciiString AIGuardState::getName( ) const
  5769. {
  5770. AsciiString name = m_name;
  5771. name.concat("/");
  5772. if (m_guardMachine) name.concat(m_guardMachine->getCurrentStateName());
  5773. else name.concat("*NULL guardMachine");
  5774. return name;
  5775. }
  5776. #endif
  5777. // ------------------------------------------------------------------------------------------------
  5778. /** CRC */
  5779. // ------------------------------------------------------------------------------------------------
  5780. void AIGuardState::crc( Xfer *xfer )
  5781. {
  5782. } // end crc
  5783. // ------------------------------------------------------------------------------------------------
  5784. /** Xfer Method */
  5785. // ------------------------------------------------------------------------------------------------
  5786. void AIGuardState::xfer( Xfer *xfer )
  5787. {
  5788. // version
  5789. XferVersion currentVersion = 1;
  5790. XferVersion version = currentVersion;
  5791. xfer->xferVersion( &version, currentVersion );
  5792. Bool hasMachine = m_guardMachine!=NULL;
  5793. xfer->xferBool(&hasMachine);
  5794. if (hasMachine && m_guardMachine==NULL) {
  5795. // create new state machine for guard behavior
  5796. m_guardMachine = newInstance(AIGuardMachine)( getMachineOwner());
  5797. }
  5798. if (hasMachine) {
  5799. xfer->xferSnapshot(m_guardMachine);
  5800. }
  5801. } // end xfer
  5802. // ------------------------------------------------------------------------------------------------
  5803. /** Load post process */
  5804. // ------------------------------------------------------------------------------------------------
  5805. void AIGuardState::loadPostProcess( void )
  5806. {
  5807. } // end loadPostProcess
  5808. //----------------------------------------------------------------------------------------------------------
  5809. //Is our guard state in an attack sub-state?
  5810. Bool AIGuardState::isAttack() const
  5811. {
  5812. if( m_guardMachine )
  5813. {
  5814. return m_guardMachine->isInAttackState();
  5815. }
  5816. return FALSE;
  5817. }
  5818. //----------------------------------------------------------------------------------------------------------
  5819. //Is our guard state in guard-idle?
  5820. Bool AIGuardState::isGuardIdle() const
  5821. {
  5822. if( m_guardMachine )
  5823. {
  5824. return m_guardMachine->isInGuardIdleState();
  5825. }
  5826. return FALSE;
  5827. }
  5828. //----------------------------------------------------------------------------------------------------------
  5829. /**
  5830. * Guard location.
  5831. */
  5832. StateReturnType AIGuardState::onEnter()
  5833. {
  5834. Object *obj = getMachineOwner();
  5835. AIUpdateInterface *ai = obj->getAI();
  5836. m_guardMachine = newInstance(AIGuardMachine)( getMachineOwner());
  5837. // tell the guarding machine what it is guarding with
  5838. switch(ai->getGuardTargetType())
  5839. {
  5840. case GUARDTARGET_LOCATION: m_guardMachine->setTargetPositionToGuard( ai->getGuardLocation() ); break;
  5841. case GUARDTARGET_OBJECT: m_guardMachine->setTargetToGuard( TheGameLogic->findObjectByID(ai->getGuardObject()) ); break;
  5842. case GUARDTARGET_AREA: m_guardMachine->setAreaToGuard( ai->getAreaToGuard() ); break;
  5843. }
  5844. m_guardMachine->setGuardMode(ai->getGuardMode());
  5845. // now that essential parameters are set, set the machine's initial state
  5846. if (m_guardMachine->initDefaultState() == STATE_FAILURE)
  5847. return STATE_FAILURE;
  5848. return m_guardMachine->setState(AI_GUARD_RETURN);
  5849. obj->getControllingPlayer()->getAcademyStats()->recordGuardAbilityUsed();
  5850. }
  5851. //----------------------------------------------------------------------------------------------------------
  5852. void AIGuardState::onExit( StateExitType status )
  5853. {
  5854. m_guardMachine->deleteInstance();
  5855. m_guardMachine = NULL;
  5856. Object *obj = getMachineOwner();
  5857. obj->getAI()->clearGuardTargetType();
  5858. }
  5859. //----------------------------------------------------------------------------------------------------------
  5860. StateReturnType AIGuardState::update()
  5861. {
  5862. //DEBUG_LOG(("AIGuardState frame %d: %08lx\n",TheGameLogic->getFrame(),getMachineOwner()));
  5863. if (m_guardMachine == NULL)
  5864. {
  5865. return STATE_FAILURE; // We actually already exited.
  5866. }
  5867. // if all of our weapons are out of ammo, can't attack.
  5868. // (this can happen for units which never auto-reload, like the Raptor)
  5869. Object* owner = getMachineOwner();
  5870. if( owner->getAI()->getJetAIUpdate() && owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE) && !owner->getTemplate()->isEnterGuard())
  5871. {
  5872. DEBUG_CRASH(("Hmm, this should probably never happen, since this case should be intercepted by JetAIUpdate\n"));
  5873. return STATE_FAILURE;
  5874. }
  5875. getMachine()->lock("AIGuardState::update"); // We don't want to switch out of guard during the update.
  5876. StateReturnType ret = m_guardMachine->updateStateMachine();
  5877. getMachine()->unlock();
  5878. return ret;
  5879. }
  5880. //----------------------------------------------------------------------------------------------------------
  5881. //----------------------------------------------------------------------------------------------------------
  5882. //----------------------------------------------------------------------------------------------------------
  5883. //----------------------------------------------------------------------------------------------------------
  5884. AIGuardRetaliateState::~AIGuardRetaliateState()
  5885. {
  5886. if (m_guardRetaliateMachine) {
  5887. m_guardRetaliateMachine->halt();
  5888. m_guardRetaliateMachine->deleteInstance();
  5889. }
  5890. }
  5891. #ifdef STATE_MACHINE_DEBUG
  5892. //----------------------------------------------------------------------------------------------------------
  5893. AsciiString AIGuardRetaliateState::getName( ) const
  5894. {
  5895. AsciiString name = m_name;
  5896. name.concat("/");
  5897. if( m_guardRetaliateMachine )
  5898. {
  5899. name.concat(m_guardRetaliateMachine->getCurrentStateName());
  5900. }
  5901. else
  5902. {
  5903. name.concat("*NULL guardRetaliateMachine");
  5904. }
  5905. return name;
  5906. }
  5907. #endif
  5908. // ------------------------------------------------------------------------------------------------
  5909. /** CRC */
  5910. // ------------------------------------------------------------------------------------------------
  5911. void AIGuardRetaliateState::crc( Xfer *xfer )
  5912. {
  5913. } // end crc
  5914. // ------------------------------------------------------------------------------------------------
  5915. /** Xfer Method */
  5916. // ------------------------------------------------------------------------------------------------
  5917. void AIGuardRetaliateState::xfer( Xfer *xfer )
  5918. {
  5919. // version
  5920. XferVersion currentVersion = 1;
  5921. XferVersion version = currentVersion;
  5922. xfer->xferVersion( &version, currentVersion );
  5923. Bool hasMachine = m_guardRetaliateMachine!=NULL;
  5924. xfer->xferBool(&hasMachine);
  5925. if (hasMachine && m_guardRetaliateMachine==NULL)
  5926. {
  5927. // create new state machine for guard behavior
  5928. m_guardRetaliateMachine = newInstance(AIGuardRetaliateMachine)( getMachineOwner());
  5929. }
  5930. if (hasMachine)
  5931. {
  5932. xfer->xferSnapshot(m_guardRetaliateMachine);
  5933. }
  5934. } // end xfer
  5935. // ------------------------------------------------------------------------------------------------
  5936. /** Load post process */
  5937. // ------------------------------------------------------------------------------------------------
  5938. void AIGuardRetaliateState::loadPostProcess( void )
  5939. {
  5940. } // end loadPostProcess
  5941. //----------------------------------------------------------------------------------------------------------
  5942. //Is our retaliate state in an attack sub-state?
  5943. Bool AIGuardRetaliateState::isAttack() const
  5944. {
  5945. if( m_guardRetaliateMachine )
  5946. {
  5947. return m_guardRetaliateMachine->isInAttackState();
  5948. }
  5949. return FALSE;
  5950. }
  5951. //----------------------------------------------------------------------------------------------------------
  5952. /**
  5953. * Guard location.
  5954. */
  5955. StateReturnType AIGuardRetaliateState::onEnter()
  5956. {
  5957. Object *obj = getMachineOwner();
  5958. AIUpdateInterface *ai = obj->getAI();
  5959. m_guardRetaliateMachine = newInstance(AIGuardRetaliateMachine)( getMachineOwner());
  5960. #ifdef STATE_MACHINE_DEBUG
  5961. m_guardRetaliateMachine->setDebugOutput(getMachine()->getWantsDebugOutput());
  5962. #endif
  5963. // tell the guarding machine what it is guarding with
  5964. m_guardRetaliateMachine->setTargetPositionToGuard( ai->getGoalPosition() );
  5965. Object *goalObject = ai->getGoalObject();
  5966. if( goalObject )
  5967. {
  5968. m_guardRetaliateMachine->setNemesisID( goalObject->getID() );
  5969. }
  5970. // now that essential parameters are set, set the machine's initial state
  5971. return m_guardRetaliateMachine->initDefaultState();
  5972. }
  5973. //----------------------------------------------------------------------------------------------------------
  5974. void AIGuardRetaliateState::onExit( StateExitType status )
  5975. {
  5976. m_guardRetaliateMachine->deleteInstance();
  5977. m_guardRetaliateMachine = NULL;
  5978. Object *obj = getMachineOwner();
  5979. obj->getAI()->clearGuardTargetType();
  5980. }
  5981. //----------------------------------------------------------------------------------------------------------
  5982. StateReturnType AIGuardRetaliateState::update()
  5983. {
  5984. //DEBUG_LOG(("AIGuardRetaliateState frame %d: %08lx\n",TheGameLogic->getFrame(),getMachineOwner()));
  5985. if (m_guardRetaliateMachine == NULL)
  5986. {
  5987. return STATE_FAILURE; // We actually already exited.
  5988. }
  5989. // if all of our weapons are out of ammo, can't attack.
  5990. // (this can happen for units which never auto-reload, like the Raptor)
  5991. Object* owner = getMachineOwner();
  5992. if( owner->getAI()->getJetAIUpdate() && owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE) && !owner->getTemplate()->isEnterGuard())
  5993. {
  5994. DEBUG_CRASH(("Hmm, this should probably never happen, since this case should be intercepted by JetAIUpdate\n"));
  5995. return STATE_FAILURE;
  5996. }
  5997. StateReturnType ret = m_guardRetaliateMachine->updateStateMachine();
  5998. return ret;
  5999. }
  6000. //----------------------------------------------------------------------------------------------------------
  6001. //----------------------------------------------------------------------------------------------------------
  6002. //----------------------------------------------------------------------------------------------------------
  6003. //----------------------------------------------------------------------------------------------------------
  6004. AITunnelNetworkGuardState::~AITunnelNetworkGuardState()
  6005. {
  6006. if (m_guardMachine) {
  6007. m_guardMachine->halt();
  6008. m_guardMachine->deleteInstance();
  6009. }
  6010. }
  6011. #ifdef STATE_MACHINE_DEBUG
  6012. //----------------------------------------------------------------------------------------------------------
  6013. AsciiString AITunnelNetworkGuardState::getName( ) const
  6014. {
  6015. AsciiString name = m_name;
  6016. name.concat("/");
  6017. if (m_guardMachine) name.concat(m_guardMachine->getCurrentStateName());
  6018. else name.concat("*NULL guardMachine");
  6019. return name;
  6020. }
  6021. #endif
  6022. // ------------------------------------------------------------------------------------------------
  6023. /** CRC */
  6024. // ------------------------------------------------------------------------------------------------
  6025. void AITunnelNetworkGuardState::crc( Xfer *xfer )
  6026. {
  6027. } // end crc
  6028. // ------------------------------------------------------------------------------------------------
  6029. /** Xfer Method */
  6030. // ------------------------------------------------------------------------------------------------
  6031. void AITunnelNetworkGuardState::xfer( Xfer *xfer )
  6032. {
  6033. // version
  6034. XferVersion currentVersion = 1;
  6035. XferVersion version = currentVersion;
  6036. xfer->xferVersion( &version, currentVersion );
  6037. Bool hasMachine = m_guardMachine!=NULL;
  6038. xfer->xferBool(&hasMachine);
  6039. if (hasMachine && m_guardMachine==NULL) {
  6040. // create new state machine for guard behavior
  6041. m_guardMachine = newInstance(AITNGuardMachine)( getMachineOwner());
  6042. }
  6043. if (hasMachine) {
  6044. xfer->xferSnapshot(m_guardMachine);
  6045. }
  6046. } // end xfer
  6047. // ------------------------------------------------------------------------------------------------
  6048. /** Load post process */
  6049. // ------------------------------------------------------------------------------------------------
  6050. void AITunnelNetworkGuardState::loadPostProcess( void )
  6051. {
  6052. } // end loadPostProcess
  6053. //----------------------------------------------------------------------------------------------------------
  6054. //Is our guard tunnel network state in an attack sub-state?
  6055. Bool AITunnelNetworkGuardState::isAttack() const
  6056. {
  6057. if( m_guardMachine )
  6058. {
  6059. return m_guardMachine->isInAttackState();
  6060. }
  6061. return FALSE;
  6062. }
  6063. //----------------------------------------------------------------------------------------------------------
  6064. /**
  6065. * Guard location.
  6066. */
  6067. StateReturnType AITunnelNetworkGuardState::onEnter()
  6068. {
  6069. Object *obj = getMachineOwner();
  6070. AIUpdateInterface *ai = obj->getAI();
  6071. m_guardMachine = newInstance(AITNGuardMachine)( getMachineOwner());
  6072. // tell the guarding machine what it is guarding with
  6073. m_guardMachine->setTargetPositionToGuard( ai->getGuardLocation() );
  6074. m_guardMachine->setGuardMode(ai->getGuardMode());
  6075. // now that essential parameters are set, set the machine's initial state
  6076. if (m_guardMachine->initDefaultState() == STATE_FAILURE)
  6077. return STATE_FAILURE;
  6078. return m_guardMachine->setState(AI_GUARD_RETURN);
  6079. }
  6080. //----------------------------------------------------------------------------------------------------------
  6081. void AITunnelNetworkGuardState::onExit( StateExitType status )
  6082. {
  6083. m_guardMachine->deleteInstance();
  6084. m_guardMachine = NULL;
  6085. Object *obj = getMachineOwner();
  6086. obj->getAI()->clearGuardTargetType();
  6087. }
  6088. //----------------------------------------------------------------------------------------------------------
  6089. StateReturnType AITunnelNetworkGuardState::update()
  6090. {
  6091. //DEBUG_LOG(("AITunnelNetworkGuardState frame %d: %08lx\n",TheGameLogic->getFrame(),getMachineOwner()));
  6092. if (m_guardMachine == NULL)
  6093. {
  6094. return STATE_FAILURE; // We actually already exited.
  6095. }
  6096. // if all of our weapons are out of ammo, can't attack.
  6097. // (this can happen for units which never auto-reload, like the Raptor)
  6098. Object* owner = getMachineOwner();
  6099. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  6100. {
  6101. DEBUG_CRASH(("Hmm, this should probably never happen, since this case should be intercepted by JetAIUpdate\n"));
  6102. return STATE_FAILURE;
  6103. }
  6104. getMachine()->lock("AITunnelNetworkGuardState::update"); // We don't want to switch out of guard during the update.
  6105. StateReturnType ret = m_guardMachine->updateStateMachine();
  6106. getMachine()->unlock();
  6107. return ret;
  6108. }
  6109. //-------------------------------------------------------------------------------------------------
  6110. //-------------------------------------------------------------------------------------------------
  6111. //-------------------------------------------------------------------------------------------------
  6112. //----------------------------------------------------------------------------------------------------------
  6113. //----------------------------------------------------------------------------------------------------------
  6114. //----------------------------------------------------------------------------------------------------------
  6115. //----------------------------------------------------------------------------------------------------------
  6116. AIHuntState::~AIHuntState()
  6117. {
  6118. if (m_huntMachine)
  6119. {
  6120. m_huntMachine->halt();
  6121. m_huntMachine->deleteInstance();
  6122. }
  6123. }
  6124. // ------------------------------------------------------------------------------------------------
  6125. /** CRC */
  6126. // ------------------------------------------------------------------------------------------------
  6127. void AIHuntState::crc( Xfer *xfer )
  6128. {
  6129. } // end crc
  6130. // ------------------------------------------------------------------------------------------------
  6131. /** Xfer Method */
  6132. // ------------------------------------------------------------------------------------------------
  6133. void AIHuntState::xfer( Xfer *xfer )
  6134. {
  6135. // version
  6136. XferVersion currentVersion = 1;
  6137. XferVersion version = currentVersion;
  6138. xfer->xferVersion( &version, currentVersion );
  6139. Bool hasMachine = m_huntMachine!=NULL;
  6140. xfer->xferBool(&hasMachine);
  6141. if (hasMachine && m_huntMachine==NULL) {
  6142. // create new state machine for hunt behavior
  6143. m_huntMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  6144. }
  6145. if (hasMachine) {
  6146. xfer->xferSnapshot(m_huntMachine);
  6147. }
  6148. xfer->xferUnsignedInt(&m_nextEnemyScanTime);
  6149. } // end xfer
  6150. // ------------------------------------------------------------------------------------------------
  6151. /** Load post process */
  6152. // ------------------------------------------------------------------------------------------------
  6153. void AIHuntState::loadPostProcess( void )
  6154. {
  6155. } // end loadPostProcess
  6156. //----------------------------------------------------------------------------------------------------------
  6157. //Is our hunt state in an attack sub-state?
  6158. Bool AIHuntState::isAttack() const
  6159. {
  6160. if( m_huntMachine )
  6161. {
  6162. return m_huntMachine->isInAttackState();
  6163. }
  6164. return FALSE;
  6165. }
  6166. //----------------------------------------------------------------------------------------------------------
  6167. /**
  6168. * Hunt (seek and destroy).
  6169. */
  6170. StateReturnType AIHuntState::onEnter()
  6171. {
  6172. // create new state machine for hunt behavior
  6173. m_huntMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  6174. // first time thru, use a random amount so that everyone doesn't scan on the same frame,
  6175. // to avoid "spikes".
  6176. UnsignedInt sleepTime = GameLogicRandomValue(0, ENEMY_SCAN_RATE);
  6177. UnsignedInt now = TheGameLogic->getFrame();
  6178. m_nextEnemyScanTime = now + sleepTime;
  6179. // initial state of hunt state machine
  6180. return m_huntMachine->initDefaultState();
  6181. }
  6182. //----------------------------------------------------------------------------------------------------------
  6183. void AIHuntState::onExit( StateExitType status )
  6184. {
  6185. // destroy the hunt machine
  6186. m_huntMachine->deleteInstance();
  6187. m_huntMachine = NULL;
  6188. Object *obj = getMachineOwner();
  6189. if (obj)
  6190. {
  6191. obj->releaseWeaponLock(LOCKED_TEMPORARILY); // release any temporary locks.
  6192. }
  6193. }
  6194. #ifdef STATE_MACHINE_DEBUG
  6195. //----------------------------------------------------------------------------------------------------------
  6196. AsciiString AIHuntState::getName( ) const
  6197. {
  6198. AsciiString name = m_name;
  6199. name.concat("/");
  6200. if (m_huntMachine) name.concat(m_huntMachine->getCurrentStateName());
  6201. else name.concat("*NULL huntMachine");
  6202. return name;
  6203. }
  6204. #endif
  6205. //----------------------------------------------------------------------------------------------------------
  6206. StateReturnType AIHuntState::update()
  6207. {
  6208. // look around for better victims every so often
  6209. UnsignedInt now = TheGameLogic->getFrame();
  6210. if (now >= m_nextEnemyScanTime)
  6211. {
  6212. Object* owner = getMachineOwner();
  6213. // if all of our weapons are out of ammo, can't hunt.
  6214. // (this can happen for units which never auto-reload, like the Raptor)
  6215. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  6216. return STATE_FAILURE;
  6217. // Check to see if we have created a crate we need to pick up.
  6218. AIUpdateInterface *ai = owner->getAI();
  6219. Object* crate = ai->checkForCrateToPickup();
  6220. if (crate)
  6221. {
  6222. m_huntMachine->setGoalObject(crate);
  6223. m_huntMachine->setState( AI_PICK_UP_CRATE );
  6224. return STATE_CONTINUE;
  6225. }
  6226. m_nextEnemyScanTime = now + ENEMY_SCAN_RATE;
  6227. const AttackPriorityInfo *info = NULL;
  6228. info = ai->getAttackInfo();
  6229. // Check if team auto targets same victim.
  6230. Object* teamVictim = NULL;
  6231. if (owner->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget)
  6232. {
  6233. teamVictim = owner->getTeam()->getTeamTargetObject();
  6234. }
  6235. Object* victim = NULL;
  6236. if (teamVictim && info==NULL)
  6237. {
  6238. victim = teamVictim;
  6239. }
  6240. else
  6241. {
  6242. // do NOT do line of sight check - we want to find everything
  6243. victim = TheAI->findClosestEnemy( owner, 9999.9f, AI::CAN_ATTACK, info );
  6244. if (victim==NULL && owner->getControllingPlayer() && owner->getControllingPlayer()->getUnitsShouldHunt()) {
  6245. // If we are doing an all hunt, try hunting without the attack priority info. jba.
  6246. victim = TheAI->findClosestEnemy(owner, 9999.9f, AI::CAN_ATTACK, NULL);
  6247. }
  6248. if (owner->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget)
  6249. {
  6250. // Check priorities.
  6251. if (teamVictim && info) {
  6252. if (victim==NULL) {
  6253. DEBUG_LOG(("Couldnt' find victim. hmm."));
  6254. victim = teamVictim;
  6255. }
  6256. Int teamVictimPriority = info->getPriority(teamVictim->getTemplate());
  6257. Int victimPriority;
  6258. if( victim )
  6259. victimPriority = info->getPriority(victim->getTemplate());
  6260. else
  6261. victimPriority = 0;
  6262. if (teamVictimPriority>=victimPriority) {
  6263. victim = teamVictim;
  6264. }
  6265. }
  6266. owner->getTeam()->setTeamTargetObject(victim);
  6267. }
  6268. }
  6269. m_huntMachine->setGoalObject( victim );
  6270. if (m_huntMachine->getCurrentStateID() == AI_IDLE && victim)
  6271. {
  6272. m_huntMachine->setState( AI_ATTACK_OBJECT );
  6273. }
  6274. if (owner->getControllingPlayer() && owner->getControllingPlayer()->getUnitsShouldHunt()==FALSE) {
  6275. // If we are not doing an all hunt, then exit hunt state - no more victims.
  6276. if (m_huntMachine->getCurrentStateID() == AI_IDLE && victim==NULL) {
  6277. return STATE_SUCCESS; // we killed everything :) jba.
  6278. }
  6279. }
  6280. }
  6281. getMachine()->lock("AIHuntState::update"); // The idle state in the sub machine can sometimes acquire targets.
  6282. // It is important to not switch out of this state via a sub machine call. jba.
  6283. /*
  6284. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  6285. sleeps, we still need to be called every frame.
  6286. */
  6287. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  6288. StateReturnType ret = CONVERT_SLEEP_TO_CONTINUE(m_huntMachine->updateStateMachine());
  6289. getMachine()->unlock();
  6290. return ret;
  6291. }
  6292. //----------------------------------------------------------------------------------------------------------
  6293. //----------------------------------------------------------------------------------------------------------
  6294. //----------------------------------------------------------------------------------------------------------
  6295. //----------------------------------------------------------------------------------------------------------
  6296. AIAttackAreaState::~AIAttackAreaState()
  6297. {
  6298. if (m_attackMachine) {
  6299. m_attackMachine->halt();
  6300. m_attackMachine->deleteInstance();
  6301. }
  6302. }
  6303. // ------------------------------------------------------------------------------------------------
  6304. /** CRC */
  6305. // ------------------------------------------------------------------------------------------------
  6306. void AIAttackAreaState::crc( Xfer *xfer )
  6307. {
  6308. } // end crc
  6309. // ------------------------------------------------------------------------------------------------
  6310. /** Xfer Method */
  6311. // ------------------------------------------------------------------------------------------------
  6312. void AIAttackAreaState::xfer( Xfer *xfer )
  6313. {
  6314. // version
  6315. XferVersion currentVersion = 1;
  6316. XferVersion version = currentVersion;
  6317. xfer->xferVersion( &version, currentVersion );
  6318. Bool hasMachine = m_attackMachine!=NULL;
  6319. xfer->xferBool(&hasMachine);
  6320. if (hasMachine && m_attackMachine==NULL) {
  6321. // create new state machine for hunt behavior
  6322. m_attackMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  6323. }
  6324. if (hasMachine) {
  6325. xfer->xferSnapshot(m_attackMachine);
  6326. }
  6327. xfer->xferUnsignedInt(&m_nextEnemyScanTime);
  6328. } // end xfer
  6329. // ------------------------------------------------------------------------------------------------
  6330. /** Load post process */
  6331. // ------------------------------------------------------------------------------------------------
  6332. void AIAttackAreaState::loadPostProcess( void )
  6333. {
  6334. } // end loadPostProcess
  6335. #ifdef STATE_MACHINE_DEBUG
  6336. //----------------------------------------------------------------------------------------------------------
  6337. AsciiString AIAttackAreaState::getName( ) const
  6338. {
  6339. AsciiString name = m_name;
  6340. name.concat("/");
  6341. if (m_attackMachine) name.concat(m_attackMachine->getCurrentStateName());
  6342. else name.concat("*NULL m_attackMachine");
  6343. return name;
  6344. }
  6345. #endif
  6346. //----------------------------------------------------------------------------------------------------------
  6347. StateReturnType AIAttackAreaState::onEnter()
  6348. {
  6349. // create new state machine for hunt behavior
  6350. m_attackMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  6351. // first time thru, use a random amount so that everyone doesn't scan on the same frame,
  6352. // to avoid "spikes".
  6353. UnsignedInt now = TheGameLogic->getFrame();
  6354. m_nextEnemyScanTime = now + GameLogicRandomValue(0, ENEMY_SCAN_RATE);
  6355. // initial state of hunt state machine
  6356. return m_attackMachine->initDefaultState();
  6357. }
  6358. //----------------------------------------------------------------------------------------------------------
  6359. void AIAttackAreaState::onExit( StateExitType status )
  6360. {
  6361. // destroy the hunt machine
  6362. m_attackMachine->deleteInstance();
  6363. m_attackMachine = NULL;
  6364. }
  6365. //----------------------------------------------------------------------------------------------------------
  6366. StateReturnType AIAttackAreaState::update()
  6367. {
  6368. // look around for better victims every so often
  6369. UnsignedInt now = TheGameLogic->getFrame();
  6370. if (now >= m_nextEnemyScanTime)
  6371. {
  6372. Object* owner = getMachineOwner();
  6373. // if all of our weapons are out of ammo, can't hunt.
  6374. // (this can happen for units which never auto-reload, like the Raptor)
  6375. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  6376. return STATE_FAILURE;
  6377. // first time thru, add a random amount so that everyone doesn't scan on the same frame,
  6378. // to avoid "spikes". Note that this implementation ensures that this unit checks immediately
  6379. // upon entering this state, then wait a possibly-longer-than-usual time (due to randomness),
  6380. // then settle into a regular schedule.
  6381. m_nextEnemyScanTime = now + ENEMY_SCAN_RATE;
  6382. AIUpdateInterface *ai = owner->getAI();
  6383. if (ai->getAreaToGuard() == NULL)
  6384. return STATE_FAILURE;
  6385. const AttackPriorityInfo *info = NULL;
  6386. info = ai->getAttackInfo();
  6387. PartitionFilterPolygonTrigger polyFilter(ai->getAreaToGuard());
  6388. // do NOT do line of sight check - we want to find everything
  6389. Object *victim = TheAI->findClosestEnemy( owner, 9999.9f, AI::CAN_ATTACK, info, &polyFilter );
  6390. m_attackMachine->setGoalObject( victim );
  6391. if (m_attackMachine->getCurrentStateID() == AI_IDLE && victim)
  6392. {
  6393. m_attackMachine->setState( AI_ATTACK_OBJECT );
  6394. }
  6395. if (victim==NULL) {
  6396. return STATE_SUCCESS;
  6397. }
  6398. }
  6399. getMachine()->lock("AIAttackAreaState::update"); // The idle state in the sub machine can sometimes acquire targets.
  6400. // It is important to not switch out of this state via a sub machine call. jba.
  6401. /*
  6402. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  6403. sleeps, we still need to be called every frame.
  6404. */
  6405. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  6406. StateReturnType ret = CONVERT_SLEEP_TO_CONTINUE(m_attackMachine->updateStateMachine());
  6407. getMachine()->unlock();
  6408. return ret;
  6409. }
  6410. //----------------------------------------------------------------------------------------------------------
  6411. //----------------------------------------------------------------------------------------------------------
  6412. //----------------------------------------------------------------------------------------------------------
  6413. // ------------------------------------------------------------------------------------------------
  6414. /** CRC */
  6415. // ------------------------------------------------------------------------------------------------
  6416. void AIFaceState::crc( Xfer *xfer )
  6417. {
  6418. } // end crc
  6419. // ------------------------------------------------------------------------------------------------
  6420. /** Xfer Method */
  6421. // ------------------------------------------------------------------------------------------------
  6422. void AIFaceState::xfer( Xfer *xfer )
  6423. {
  6424. // version
  6425. XferVersion currentVersion = 1;
  6426. XferVersion version = currentVersion;
  6427. xfer->xferVersion( &version, currentVersion );
  6428. xfer->xferBool(&m_canTurnInPlace);
  6429. } // end xfer
  6430. // ------------------------------------------------------------------------------------------------
  6431. /** Load post process */
  6432. // ------------------------------------------------------------------------------------------------
  6433. void AIFaceState::loadPostProcess( void )
  6434. {
  6435. // empty. jba.
  6436. } // end loadPostProcess
  6437. //----------------------------------------------------------------------------------------------------------
  6438. StateReturnType AIFaceState::onEnter()
  6439. {
  6440. Object* source = getMachineOwner();
  6441. AIUpdateInterface* ai = source->getAI();
  6442. Locomotor* curLoco = ai->getCurLocomotor();
  6443. m_canTurnInPlace = curLoco ? curLoco->getMinSpeed() == 0.0f : false;
  6444. Object* target = getMachineGoalObject();
  6445. if (m_obj && target == NULL )
  6446. {
  6447. // Nothing to face...
  6448. return STATE_FAILURE;
  6449. }
  6450. return STATE_CONTINUE;
  6451. }
  6452. //----------------------------------------------------------------------------------------------------------
  6453. void AIFaceState::onExit( StateExitType status )
  6454. {
  6455. }
  6456. //----------------------------------------------------------------------------------------------------------
  6457. StateReturnType AIFaceState::update()
  6458. {
  6459. Object *obj = getMachineOwner();
  6460. AIUpdateInterface *ai = obj->getAI();
  6461. const Coord3D* pos = getMachineGoalPosition();
  6462. if (m_obj)
  6463. {
  6464. Object *target = getMachineGoalObject();
  6465. if (!target)
  6466. {
  6467. // Nothing to face.
  6468. return STATE_FAILURE;
  6469. }
  6470. pos = target->getPosition();
  6471. }
  6472. Real relAngle = ThePartitionManager->getRelativeAngle2D( obj, pos );
  6473. const Real REL_THRESH = 0.035f; // about 2 degrees. (getRelativeAngle2D is current only accurate to about 1.25 degrees)
  6474. if( fabs( relAngle ) < REL_THRESH )
  6475. {
  6476. return STATE_SUCCESS;
  6477. }
  6478. // turnDelta = yawRate() NO, do not get this, it is not useful. (srj)
  6479. if (m_canTurnInPlace)
  6480. {
  6481. Real desiredAngle = obj->getOrientation() + relAngle;
  6482. ai->setLocomotorGoalOrientation( desiredAngle );
  6483. }
  6484. else
  6485. {
  6486. ai->setLocomotorGoalPositionExplicit(*pos);
  6487. }
  6488. return STATE_CONTINUE;
  6489. }