AIStates.cpp 234 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931
  1. /*
  2. ** Command & Conquer Generals(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/AITNGuard.h"
  48. #include "GameLogic/AIStateMachine.h"
  49. #include "GameLogic/AIPathfind.h"
  50. #include "GameLogic/Locomotor.h"
  51. #include "GameLogic/Module/AIUpdate.h"
  52. #include "GameLogic/Module/BodyModule.h"
  53. #include "GameLogic/Module/ContainModule.h"
  54. #include "GameLogic/Module/PhysicsUpdate.h"
  55. #include "GameLogic/Module/StealthUpdate.h"
  56. #include "GameLogic/PartitionManager.h"
  57. #include "GameLogic/PolygonTrigger.h"
  58. #include "GameLogic/ScriptEngine.h"
  59. #include "GameLogic/Squad.h"
  60. #include "GameLogic/TurretAI.h"
  61. #include "GameLogic/Weapon.h"
  62. #ifdef _INTERNAL
  63. // for occasional debugging...
  64. //#pragma optimize("", off)
  65. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  66. #endif
  67. static Bool cannotPossiblyAttackObject( State *thisState, void* userData );
  68. //----------------------------------------------------------------------------------------------------------
  69. AICommandParms::AICommandParms(AICommandType cmd, CommandSourceType cmdSource) :
  70. m_cmd(cmd),
  71. m_cmdSource(cmdSource),
  72. m_obj(NULL),
  73. m_otherObj(NULL),
  74. m_team(NULL),
  75. m_waypoint(NULL),
  76. m_polygon(NULL),
  77. m_intValue(0),
  78. m_commandButton(NULL),
  79. m_path(NULL)
  80. {
  81. m_pos.zero();
  82. m_coords.clear();
  83. }
  84. //----------------------------------------------------------------------------------------------------------
  85. void AICommandParmsStorage::store(const AICommandParms& parms)
  86. {
  87. m_cmd = parms.m_cmd;
  88. m_cmdSource = parms.m_cmdSource;
  89. m_pos = parms.m_pos;
  90. m_obj = parms.m_obj ? parms.m_obj->getID() : INVALID_ID;
  91. m_otherObj = parms.m_otherObj ? parms.m_otherObj->getID() : INVALID_ID;
  92. m_teamName = parms.m_team ? parms.m_team->getName() : AsciiString::TheEmptyString;
  93. m_coords = parms.m_coords;
  94. m_waypoint = parms.m_waypoint;
  95. m_polygon = parms.m_polygon;
  96. m_intValue = parms.m_intValue; /// misc usage
  97. m_damage = parms.m_damage;
  98. m_commandButton = parms.m_commandButton;
  99. m_path = parms.m_path; /// @todo srj -- probably need a better way to safely save/restore this
  100. }
  101. //----------------------------------------------------------------------------------------------------------
  102. void AICommandParmsStorage::reconstitute(AICommandParms& parms) const
  103. {
  104. parms.m_cmd = m_cmd;
  105. parms.m_cmdSource = m_cmdSource;
  106. parms.m_pos = m_pos;
  107. parms.m_obj = TheGameLogic->findObjectByID(m_obj);
  108. parms.m_otherObj = TheGameLogic->findObjectByID(m_otherObj);
  109. parms.m_team = TheTeamFactory->findTeam(m_teamName);
  110. parms.m_coords = m_coords;
  111. parms.m_waypoint = m_waypoint;
  112. parms.m_polygon = m_polygon;
  113. parms.m_intValue = m_intValue;
  114. parms.m_damage = m_damage;
  115. parms.m_commandButton = m_commandButton;
  116. parms.m_path = m_path; /// @todo srj -- probably need a better way to safely save/restore this
  117. }
  118. //----------------------------------------------------------------------------------------------------------
  119. void AICommandParmsStorage::doXfer(Xfer *xfer)
  120. {
  121. xfer->xferUser(&m_cmd, sizeof(m_cmd));
  122. xfer->xferUser(&m_cmd, sizeof(m_cmdSource));
  123. xfer->xferCoord3D(&m_pos);
  124. xfer->xferObjectID(&m_obj);
  125. xfer->xferObjectID(&m_otherObj);
  126. xfer->xferAsciiString(&m_teamName);
  127. Int numCoords = m_coords.size();
  128. xfer->xferInt(&numCoords);
  129. Int i;
  130. if (xfer->getXferMode() == XFER_LOAD)
  131. {
  132. for (i=0; i<numCoords; i++) {
  133. Coord3D pos;
  134. xfer->xferCoord3D(&pos);
  135. m_coords.push_back(pos);
  136. }
  137. } else {
  138. for (i=0; i<numCoords; i++) {
  139. Coord3D pos = m_coords[i];
  140. xfer->xferCoord3D(&pos);
  141. }
  142. }
  143. UnsignedInt id = INVALID_WAYPOINT_ID;
  144. if (m_waypoint) {
  145. id = m_waypoint->getID();
  146. }
  147. xfer->xferUnsignedInt(&id);
  148. if (xfer->getXferMode() == XFER_LOAD && id!= INVALID_WAYPOINT_ID)
  149. {
  150. m_waypoint = TheTerrainLogic->getWaypointByID(id);
  151. }
  152. AsciiString triggerName;
  153. if (m_polygon) triggerName = m_polygon->getTriggerName();
  154. xfer->xferAsciiString(&triggerName);
  155. if (xfer->getXferMode() == XFER_LOAD)
  156. {
  157. if (triggerName.isNotEmpty()) {
  158. m_polygon = TheTerrainLogic->getTriggerAreaByName(triggerName);
  159. }
  160. }
  161. xfer->xferInt(&m_intValue);
  162. xfer->xferSnapshot(&m_damage);
  163. AsciiString cmdName;
  164. if (m_commandButton) {
  165. cmdName = m_commandButton->getName();
  166. }
  167. xfer->xferAsciiString(&cmdName);
  168. if (cmdName.isNotEmpty() && m_commandButton==NULL) {
  169. m_commandButton = TheControlBar->findCommandButton(cmdName);
  170. }
  171. Bool hasPath = m_path!=NULL;
  172. xfer->xferBool(&hasPath);
  173. if (hasPath && m_path==NULL) {
  174. m_path = newInstance(Path);
  175. }
  176. if (hasPath) {
  177. xfer->xferSnapshot(m_path);
  178. }
  179. }
  180. //----------------------------------------------------------------------------------------------------------
  181. /**
  182. * Compare two positions to see if they are logically equal
  183. * @todo Move this somewhere more useful (MSB)
  184. */
  185. static Bool isSamePosition( const Coord3D *ourPos, const Coord3D *prevTargetPos, const Coord3D *curTargetPos )
  186. {
  187. Coord3D diff;
  188. // for pathfinding purposes, only care about 2d pos. (srj)
  189. diff.x = curTargetPos->x - prevTargetPos->x;
  190. diff.y = curTargetPos->y - prevTargetPos->y;
  191. Coord3D toTarget;
  192. // for pathfinding purposes, only care about 2d pos. (srj)
  193. toTarget.x = curTargetPos->x - ourPos->x;
  194. toTarget.y = curTargetPos->y - ourPos->y;
  195. // Tolerance is (dist/10)squared.
  196. const Real TOLERANCE_FACTOR = 1.0f / (10.0f * 10.0f);
  197. Real toleranceSqr = (toTarget.x*toTarget.x+toTarget.y*toTarget.y) * TOLERANCE_FACTOR;
  198. if (diff.x * diff.x + diff.y * diff.y > toleranceSqr)
  199. return false;
  200. return true;
  201. }
  202. //----------------------------------------------------------------------------------------------------------
  203. //----------------------------------------------------------------------------------------------------------
  204. // ------------------------------------------------------------------------------------------------
  205. /** CRC */
  206. // ------------------------------------------------------------------------------------------------
  207. void AttackStateMachine::crc( Xfer *xfer )
  208. {
  209. StateMachine::crc(xfer);
  210. } // end crc
  211. // ------------------------------------------------------------------------------------------------
  212. /** Xfer Method */
  213. // ------------------------------------------------------------------------------------------------
  214. void AttackStateMachine::xfer( Xfer *xfer )
  215. {
  216. XferVersion cv = 1;
  217. XferVersion v = cv;
  218. xfer->xferVersion( &v, cv );
  219. StateMachine::xfer(xfer);
  220. } // end xfer
  221. // ------------------------------------------------------------------------------------------------
  222. /** Load post process */
  223. // ------------------------------------------------------------------------------------------------
  224. void AttackStateMachine::loadPostProcess( void )
  225. {
  226. StateMachine::loadPostProcess();
  227. } // end loadPostProcess
  228. //----------------------------------------------------------------------------------------------------------
  229. static Bool inWeaponRangeObject(State *thisState, void* userData);
  230. //----------------------------------------------------------------------------------------------------------
  231. /**
  232. * Create an AI state machine. Define all of the states the machine
  233. * can possibly be in, and set the initial (default) state.
  234. */
  235. AttackStateMachine::AttackStateMachine( Object *obj, AIAttackState* att, AsciiString name, Bool follow, Bool attackingObject, Bool forceAttacking )
  236. : StateMachine( obj, name )
  237. {
  238. // we want to use the CONTINUE mode (not NEW) since we already have acquired the target.
  239. static const StateConditionInfo objectConditionsNormal[] =
  240. {
  241. StateConditionInfo(outOfWeaponRangeObject, AttackStateMachine::CHASE_TARGET, NULL),
  242. StateConditionInfo(wantToSquishTarget, AttackStateMachine::CHASE_TARGET, NULL),
  243. StateConditionInfo(cannotPossiblyAttackObject, EXIT_MACHINE_WITH_FAILURE, (void*)ATTACK_CONTINUED_TARGET),
  244. StateConditionInfo(NULL, NULL, NULL) // keep last
  245. };
  246. // we want to use the CONTINUE mode (not NEW) since we already have acquired the target.
  247. static const StateConditionInfo objectConditionsForced[] =
  248. {
  249. StateConditionInfo(outOfWeaponRangeObject, AttackStateMachine::CHASE_TARGET, NULL),
  250. StateConditionInfo(cannotPossiblyAttackObject, EXIT_MACHINE_WITH_FAILURE, (void*)ATTACK_CONTINUED_TARGET_FORCED),
  251. StateConditionInfo(wantToSquishTarget, AttackStateMachine::CHASE_TARGET, NULL),
  252. StateConditionInfo(NULL, NULL, NULL) // keep last
  253. };
  254. const StateConditionInfo* objectConditions = forceAttacking ? objectConditionsForced : objectConditionsNormal;
  255. static const StateConditionInfo positionConditions[] =
  256. {
  257. StateConditionInfo(outOfWeaponRangePosition, AttackStateMachine::CHASE_TARGET, NULL),
  258. StateConditionInfo(NULL, NULL, NULL) // keep last
  259. };
  260. #ifdef STATE_MACHINE_DEBUG
  261. AsciiString fullName = name;
  262. if (follow) fullName.concat(" follow");
  263. if (attackingObject) fullName.concat(" object");
  264. setName(fullName);
  265. //setDebugOutput(true);
  266. #endif
  267. // order matters: first state is the default state.
  268. // The default is Aim rather than Approach so things that cannot move will be able to shoot
  269. // things that are in range. Things that cannot move will automatically FAILURE on approach state.
  270. /*
  271. This state will succeed when we are aiming a useful weapon at the victim, and fail
  272. if the victim is dead. (Exception: if the weapon is on a turret, we don't leave this
  273. state unless we get out of range.)
  274. */
  275. defineState( AttackStateMachine::AIM_AT_TARGET,
  276. newInstance(AIAttackAimAtTargetState)( this, attackingObject, forceAttacking ),
  277. AttackStateMachine::FIRE_WEAPON,
  278. EXIT_MACHINE_WITH_FAILURE,
  279. attackingObject ? objectConditions : positionConditions );
  280. /*
  281. Note that the fire state succeeds iff it is able to fire... it will "fail"
  282. if unable to fire. However, it may be unable to fire because the target object
  283. is already dead.
  284. */
  285. defineState( AttackStateMachine::FIRE_WEAPON,
  286. newInstance(AIAttackFireWeaponState)( this, att ),
  287. AttackStateMachine::AIM_AT_TARGET,
  288. AttackStateMachine::AIM_AT_TARGET,
  289. attackingObject ? objectConditions : positionConditions );
  290. if (obj->isKindOf(KINDOF_IMMOBILE) == FALSE)
  291. {
  292. if (obj->isKindOf(KINDOF_PORTABLE_STRUCTURE) && obj->isKindOf(KINDOF_CAN_ATTACK))
  293. {
  294. static const StateConditionInfo portableStructureChaseConditions[] =
  295. {
  296. StateConditionInfo(inWeaponRangeObject, AttackStateMachine::AIM_AT_TARGET, NULL),
  297. StateConditionInfo(NULL, NULL, NULL) // keep last
  298. };
  299. /* we're a rider on a mobile object, so we can't control our motion.
  300. just make bogus states that always fall back into "aim".
  301. */
  302. defineState( AttackStateMachine::CHASE_TARGET,
  303. newInstance(ContinueState)(this),
  304. EXIT_MACHINE_WITH_FAILURE,
  305. EXIT_MACHINE_WITH_FAILURE,
  306. portableStructureChaseConditions );
  307. }
  308. else if (attackingObject)
  309. {
  310. /*
  311. This state will pursue a target that is moving away from it. If it is not moving away,
  312. it will drop into the AIAttackApproachTarget state.
  313. */
  314. defineState( AttackStateMachine::CHASE_TARGET,
  315. newInstance(AIAttackPursueTargetState)( this, follow, attackingObject, forceAttacking ),
  316. AttackStateMachine::APPROACH_TARGET,
  317. AttackStateMachine::APPROACH_TARGET );
  318. /*
  319. This state will succeed when we have a useful weapon within range of victim, and fail
  320. if the victim is dead
  321. */
  322. defineState( AttackStateMachine::APPROACH_TARGET,
  323. newInstance(AIAttackApproachTargetState)( this, follow, attackingObject, forceAttacking ),
  324. AttackStateMachine::AIM_AT_TARGET,
  325. EXIT_MACHINE_WITH_FAILURE );
  326. }
  327. else
  328. {
  329. /*
  330. This state will succeed when we have a useful weapon within range of victim, and fail
  331. if the victim is dead
  332. */
  333. defineState( AttackStateMachine::CHASE_TARGET,
  334. newInstance(AIAttackApproachTargetState)( this, follow, attackingObject, forceAttacking ),
  335. AttackStateMachine::AIM_AT_TARGET,
  336. EXIT_MACHINE_WITH_FAILURE );
  337. /*
  338. This state will succeed when we have a useful weapon within range of victim, and fail
  339. if the victim is dead
  340. */
  341. defineState( AttackStateMachine::APPROACH_TARGET,
  342. newInstance(AIAttackApproachTargetState)( this, follow, attackingObject, forceAttacking ),
  343. AttackStateMachine::AIM_AT_TARGET,
  344. EXIT_MACHINE_WITH_FAILURE );
  345. }
  346. }
  347. else
  348. {
  349. /*
  350. This state always instantly fails, so when immobile things transition here, we bail.
  351. */
  352. defineState( AttackStateMachine::CHASE_TARGET,
  353. newInstance(FailureState)(this),
  354. EXIT_MACHINE_WITH_FAILURE,
  355. EXIT_MACHINE_WITH_FAILURE );
  356. }
  357. };
  358. //----------------------------------------------------------------------------------------------------------
  359. AttackStateMachine::~AttackStateMachine()
  360. {
  361. }
  362. //-----------------------------------------------------------------------------------------------------------
  363. //-----------------------------------------------------------------------------------------------------------
  364. //-----------------------------------------------------------------------------------------------------------
  365. static Object* findEnemyInContainer(Object* killer, Object* bldg)
  366. {
  367. const ContainedItemsList* items = bldg->getContain() ? bldg->getContain()->getContainedItemsList() : NULL;
  368. if (items)
  369. {
  370. for (ContainedItemsList::const_iterator it = items->begin(); it != items->end(); ++it )
  371. {
  372. if ((*it)->isEffectivelyDead())
  373. {
  374. DEBUG_CRASH(("why is there a dead thing in this container?"));
  375. continue;
  376. }
  377. // order matters: we want to know if I consider it to be an enemy, not vice versa
  378. if (killer->getRelationship(*it) == ENEMIES)
  379. {
  380. return *it;
  381. }
  382. }
  383. }
  384. return NULL;
  385. }
  386. //-----------------------------------------------------------------------------------------------------------
  387. static Int killEnemiesInContainer(Object* killer, Object* bldg, Int maxToKill)
  388. {
  389. Int numKilled = 0;
  390. while (numKilled < maxToKill)
  391. {
  392. Object* enemy = findEnemyInContainer(killer, bldg);
  393. if (enemy)
  394. {
  395. Object *containedByObject = enemy->getContainedBy();
  396. if( containedByObject )
  397. {
  398. ContainModuleInterface *contain = containedByObject->getContain();
  399. if( contain )
  400. {
  401. contain->removeFromContain(enemy);
  402. }
  403. }
  404. if (killer)
  405. killer->scoreTheKill( enemy );
  406. enemy->kill();
  407. ++numKilled;
  408. }
  409. else
  410. {
  411. break;
  412. }
  413. }
  414. return numKilled;
  415. }
  416. //-----------------------------------------------------------------------------------------------------------
  417. //-----------------------------------------------------------------------------------------------------------
  418. AIRappelState::AIRappelState( StateMachine *machine ) : State( machine, "AIRappelState" )
  419. {
  420. }
  421. //-----------------------------------------------------------------------------------------------------------
  422. // ------------------------------------------------------------------------------------------------
  423. /** CRC */
  424. // ------------------------------------------------------------------------------------------------
  425. void AIRappelState::crc( Xfer *xfer )
  426. {
  427. } // end crc
  428. // ------------------------------------------------------------------------------------------------
  429. /** Xfer Method */
  430. // ------------------------------------------------------------------------------------------------
  431. void AIRappelState::xfer( Xfer *xfer )
  432. {
  433. // version
  434. XferVersion currentVersion = 1;
  435. XferVersion version = currentVersion;
  436. xfer->xferVersion( &version, currentVersion );
  437. xfer->xferReal(&m_rappelRate);
  438. xfer->xferReal(&m_destZ);
  439. xfer->xferBool(&m_targetIsBldg);
  440. } // end xfer
  441. // ------------------------------------------------------------------------------------------------
  442. /** Load post process */
  443. // ------------------------------------------------------------------------------------------------
  444. void AIRappelState::loadPostProcess( void )
  445. {
  446. } // end loadPostProcess
  447. //-----------------------------------------------------------------------------------------------------------
  448. StateReturnType AIRappelState::onEnter()
  449. {
  450. Object* obj = getMachineOwner();
  451. if (!obj->isKindOf(KINDOF_CAN_RAPPEL))
  452. return STATE_FAILURE;
  453. //AIUpdateInterface* ai = obj->getAI();
  454. obj->setModelConditionState(MODELCONDITION_RAPPELLING);
  455. // don't do this, or we'll be unable to be forced out of this state.
  456. // instead, just manipulate physics directly.
  457. //obj->setHeld();
  458. obj->getPhysics()->resetDynamicPhysics();
  459. m_targetIsBldg = true;
  460. Object* bldg = getMachineGoalObject();
  461. if (bldg == NULL || bldg->isEffectivelyDead() || !bldg->isKindOf(KINDOF_STRUCTURE))
  462. m_targetIsBldg = false;
  463. const Coord3D* pos = obj->getPosition();
  464. const Bool onlyHealthyBridges = true; // ignore dead bridges.
  465. PathfindLayerEnum layerAtDest = TheTerrainLogic->getHighestLayerForDestination(pos, onlyHealthyBridges);
  466. m_destZ = TheTerrainLogic->getLayerHeight(pos->x, pos->y, layerAtDest);
  467. if (m_targetIsBldg)
  468. m_destZ += bldg->getGeometryInfo().getMaxHeightAbovePosition();
  469. else
  470. obj->setLayer(layerAtDest);
  471. AIUpdateInterface *ai = obj->getAI();
  472. Real MAX_RAPPEL_RATE = fabs(TheGlobalData->m_gravity) * LOGICFRAMES_PER_SECOND * 2.5f;
  473. m_rappelRate = -min(ai->getDesiredSpeed(), MAX_RAPPEL_RATE);
  474. return STATE_CONTINUE;
  475. }
  476. //-----------------------------------------------------------------------------------------------------------
  477. StateReturnType AIRappelState::update()
  478. {
  479. StateReturnType result = STATE_CONTINUE;
  480. Object* obj = getMachineOwner();
  481. const Coord3D* pos = obj->getPosition();
  482. Object* bldg = getMachineGoalObject();
  483. if (m_targetIsBldg && (bldg == NULL || bldg->isEffectivelyDead()))
  484. {
  485. // if bldg is destroyed, just head for the ground
  486. // BGC - bldg could be destroyed as they are heading down the rope.
  487. m_targetIsBldg = false;
  488. m_destZ = TheTerrainLogic->getGroundHeight(pos->x, pos->y);
  489. }
  490. // nuke 2d speed...
  491. obj->getPhysics()->scrubVelocity2D(0);
  492. // and clamp z speed to rappel rate (gravity will have accelerated us)
  493. obj->getPhysics()->scrubVelocityZ(m_rappelRate);
  494. if (!m_targetIsBldg)
  495. {
  496. // if heading for ground, do this every frame... since jitter at the very start
  497. // can move us slightly, and on uneven ground it might matter.
  498. m_destZ = TheTerrainLogic->getLayerHeight(pos->x, pos->y, obj->getLayer());
  499. }
  500. if (pos->z <= m_destZ)
  501. {
  502. Coord3D tmp = *pos;
  503. tmp.z = m_destZ;
  504. obj->setPosition(&tmp);
  505. if (m_targetIsBldg)
  506. {
  507. DEBUG_ASSERTCRASH(TheActionManager->canEnterObject(obj, bldg, obj->getAI()->getLastCommandSource(), COMBATDROP_INTO), ("Hmm, this seems unlikely"));
  508. // if there are enemies... kill up to two. if we kill two, then we die ourselves,
  509. // otherwise we enter the bldg.
  510. const Int MAX_TO_KILL = 2;
  511. Int numKilled = killEnemiesInContainer(obj, bldg, MAX_TO_KILL);
  512. if (numKilled > 0)
  513. {
  514. const FXList* fx = obj->getTemplate()->getPerUnitFX("CombatDropKillFX");
  515. FXList::doFXObj(fx, bldg, NULL);
  516. DEBUG_LOG(("Killing %d enemies in combat drop!\n",numKilled));
  517. }
  518. if (numKilled == MAX_TO_KILL)
  519. {
  520. obj->kill();
  521. DEBUG_LOG(("Killing SELF in combat drop!\n"));
  522. }
  523. else
  524. {
  525. if (bldg->getContain() && bldg->getContain()->isValidContainerFor(obj, TRUE ))
  526. {
  527. bldg->getContain()->addToContain(obj);
  528. }
  529. else
  530. {
  531. // this can legitimately happen if you drop into a full (or nearly full) building.
  532. // let's just place the guy on the ground nearby, since it sucks to fall from the top of a building.
  533. Real exitAngle = bldg->getOrientation();
  534. // Garrison doesn't have reserveDoor or exitDelay, so if we do nothing, everyone will appear on top
  535. // of each other and get stuck inside each others' extent (except for the first guy). So we'll
  536. // scatter the start point around a little to make it better.
  537. Real offset = min(obj->getGeometryInfo().getBoundingCircleRadius(),
  538. bldg->getGeometryInfo().getBoundingCircleRadius());
  539. Real angle = GameLogicRandomValueReal( PI, 2*PI );//Downish.
  540. Coord3D startPosition = *bldg->getPosition();
  541. startPosition.x += offset * Cos( angle );
  542. startPosition.y += offset * Sin( angle );
  543. startPosition.z = TheTerrainLogic->getGroundHeight( startPosition.x, startPosition.y );
  544. obj->setPosition( &startPosition );
  545. obj->setOrientation( exitAngle );
  546. FindPositionOptions options;
  547. options.startAngle = (Real)(1.5 * PI);//Down.
  548. options.maxRadius = 200;
  549. Coord3D endPosition;
  550. Bool foundPosition = ThePartitionManager->findPositionAround( &startPosition, &options, &endPosition );
  551. if( foundPosition )
  552. {
  553. std::vector<Coord3D> exitPath;
  554. exitPath.push_back(endPosition);
  555. AIUpdateInterface* ai = obj->getAI();
  556. if( ai )
  557. {
  558. ai->aiFollowPath( &exitPath, bldg, CMD_FROM_AI );
  559. }
  560. }
  561. }
  562. }
  563. }
  564. result = STATE_SUCCESS;
  565. }
  566. return result;
  567. }
  568. //-----------------------------------------------------------------------------------------------------------
  569. void AIRappelState::onExit( StateExitType status )
  570. {
  571. Object* obj = getMachineOwner();
  572. AIUpdateInterface *ai = obj->getAI();
  573. obj->clearModelConditionState(MODELCONDITION_RAPPELLING);
  574. // don't do this, or we'll be unable to be forced out of this state.
  575. // instead, just manipulate physics directly.
  576. //obj->clearHeld();
  577. ai->setDesiredSpeed( FAST_AS_POSSIBLE );
  578. }
  579. //----------------------------------------------------------------------------------------------------------
  580. //----------------------------------------------------------------------------------------------------------
  581. //----------------------------------------------------------------------------------------------------------
  582. //----------------------------------------------------------------------------------------------------------
  583. /*
  584. NOTE NOTE NOTE NOTE NOTE
  585. Do NOT subclass this unless you want ALL of the states this machine possesses.
  586. If you only want SOME of the states, please make a new StateMachine, descended
  587. from StateMachine, NOT AIStateMachine. Thank you. (srj)
  588. NOTE NOTE NOTE NOTE NOTE
  589. */
  590. AIStateMachine::AIStateMachine( Object *obj, AsciiString name ) : StateMachine( obj, name )
  591. {
  592. DEBUG_ASSERTCRASH(getOwner(), ("An AI State Machine '%s' was constructed without an owner, please tell JKMCD", name));
  593. DEBUG_ASSERTCRASH(getOwner()->getAI(), ("An AI State Machine '%s' was constructed without an AIUpdateInterface, please tell JKMCD", name));
  594. m_goalPath.clear();
  595. m_goalWaypoint = NULL;
  596. m_goalSquad = NULL;
  597. m_temporaryState = NULL;
  598. m_temporaryStateFramEnd = 0;
  599. // order matters: first state is the default state.
  600. defineState( AI_IDLE, newInstance(AIIdleState)( this, AIIdleState::LOOK_FOR_TARGETS), AI_IDLE, AI_IDLE );
  601. defineState( AI_MOVE_TO, newInstance(AIMoveToState)( this ), AI_IDLE, AI_IDLE );
  602. defineState( AI_MOVE_OUT_OF_THE_WAY, newInstance(AIMoveOutOfTheWayState)( this ), AI_IDLE, AI_IDLE );
  603. defineState( AI_MOVE_AND_TIGHTEN, newInstance(AIMoveAndTightenState)( this ), AI_IDLE, AI_IDLE );
  604. defineState( AI_MOVE_AWAY_FROM_REPULSORS, newInstance(AIMoveAwayFromRepulsorsState)( this ), AI_WANDER_IN_PLACE, AI_WANDER_IN_PLACE );
  605. defineState( AI_WANDER_IN_PLACE, newInstance(AIWanderInPlaceState)( this ), AI_MOVE_AWAY_FROM_REPULSORS, AI_MOVE_AWAY_FROM_REPULSORS );
  606. defineState( AI_ATTACK_MOVE_TO, newInstance(AIAttackMoveToState)( this ), AI_IDLE, AI_IDLE );
  607. defineState( AI_ATTACKFOLLOW_WAYPOINT_PATH_AS_TEAM, newInstance(AIAttackFollowWaypointPathState)( this, true ), AI_IDLE, AI_IDLE );
  608. defineState( AI_ATTACKFOLLOW_WAYPOINT_PATH_AS_INDIVIDUALS, newInstance(AIAttackFollowWaypointPathState)( this, false ), AI_IDLE, AI_IDLE );
  609. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_TEAM, newInstance(AIFollowWaypointPathState)( this, true ), AI_IDLE, AI_IDLE );
  610. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_INDIVIDUALS, newInstance(AIFollowWaypointPathState)( this, false ), AI_IDLE, AI_IDLE );
  611. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_TEAM_EXACT, newInstance(AIFollowWaypointPathExactState)( this, true ), AI_IDLE, AI_IDLE );
  612. defineState( AI_FOLLOW_WAYPOINT_PATH_AS_INDIVIDUALS_EXACT,newInstance(AIFollowWaypointPathExactState)( this, false ), AI_IDLE, AI_IDLE );
  613. defineState( AI_FOLLOW_PATH, newInstance(AIFollowPathState)( this ), AI_IDLE, AI_IDLE );
  614. defineState( AI_FOLLOW_EXITPRODUCTION_PATH, newInstance(AIFollowPathState)( this ), AI_IDLE, AI_IDLE );
  615. defineState( AI_MOVE_AND_EVACUATE, newInstance(AIMoveAndEvacuateState)( this ), AI_IDLE, AI_IDLE );
  616. defineState( AI_MOVE_AND_EVACUATE_AND_EXIT, newInstance(AIMoveAndEvacuateState)( this ), AI_MOVE_AND_DELETE, AI_MOVE_AND_DELETE );
  617. defineState( AI_MOVE_AND_DELETE, newInstance(AIMoveAndDeleteState)( this ), AI_IDLE, AI_IDLE );
  618. defineState( AI_WAIT, newInstance(AIWaitState)( this ), AI_IDLE, AI_IDLE );
  619. defineState( AI_ATTACK_POSITION, newInstance(AIAttackState)( this, false, false, false, NULL ), AI_IDLE, AI_IDLE );
  620. defineState( AI_ATTACK_OBJECT, newInstance(AIAttackState)( this, false, true, false, NULL ), AI_IDLE, AI_IDLE );
  621. defineState( AI_FORCE_ATTACK_OBJECT, newInstance(AIAttackState)( this, false, true, true, NULL ), AI_IDLE, AI_IDLE );
  622. defineState( AI_ATTACK_AND_FOLLOW_OBJECT, newInstance(AIAttackState)( this, true, true, false, NULL ), AI_IDLE, AI_IDLE );
  623. defineState( AI_ATTACK_SQUAD, newInstance(AIAttackSquadState)( this, NULL ), AI_IDLE, AI_IDLE );
  624. defineState( AI_WANDER, newInstance(AIWanderState)( this ), AI_IDLE, AI_MOVE_AWAY_FROM_REPULSORS );
  625. defineState( AI_PANIC, newInstance(AIPanicState)( this ), AI_IDLE, AI_MOVE_AWAY_FROM_REPULSORS );
  626. defineState( AI_DEAD, newInstance(AIDeadState)( this ), AI_IDLE, AI_IDLE );
  627. defineState( AI_DOCK, newInstance(AIDockState)( this ), AI_IDLE, AI_IDLE );
  628. defineState( AI_ENTER, newInstance(AIEnterState)( this ), AI_IDLE, AI_IDLE );
  629. defineState( AI_EXIT, newInstance(AIExitState)( this ), AI_IDLE, AI_IDLE );
  630. defineState( AI_GUARD, newInstance(AIGuardState)( this ), AI_IDLE, AI_IDLE );
  631. defineState( AI_GUARD_TUNNEL_NETWORK, newInstance(AITunnelNetworkGuardState)( this ), AI_IDLE, AI_IDLE );
  632. defineState( AI_HUNT, newInstance(AIHuntState)( this ), AI_IDLE, AI_IDLE );
  633. defineState( AI_ATTACK_AREA, newInstance(AIAttackAreaState)( this ), AI_IDLE, AI_IDLE );
  634. defineState( AI_FACE_OBJECT, newInstance(AIFaceState)( this, true ), AI_IDLE, AI_IDLE );
  635. defineState( AI_FACE_POSITION, newInstance(AIFaceState)( this, false ), AI_IDLE, AI_IDLE );
  636. defineState( AI_PICK_UP_CRATE, newInstance(AIPickUpCrateState)( this ), AI_IDLE, AI_IDLE );
  637. defineState( AI_RAPPEL_INTO, newInstance(AIRappelState)( this ), AI_IDLE, AI_IDLE );
  638. defineState( AI_BUSY, newInstance(AIBusyState)( this ), AI_IDLE, AI_IDLE );
  639. }
  640. //----------------------------------------------------------------------------------------------------------
  641. AIStateMachine::~AIStateMachine()
  642. {
  643. if (m_goalSquad)
  644. {
  645. m_goalSquad->deleteInstance();
  646. }
  647. }
  648. // ------------------------------------------------------------------------------------------------
  649. /** CRC */
  650. // ------------------------------------------------------------------------------------------------
  651. void AIStateMachine::crc( Xfer *xfer )
  652. {
  653. StateMachine::crc(xfer);
  654. } // end crc
  655. // ------------------------------------------------------------------------------------------------
  656. /** Xfer Method */
  657. // ------------------------------------------------------------------------------------------------
  658. void AIStateMachine::xfer( Xfer *xfer )
  659. {
  660. // version
  661. XferVersion currentVersion = 1;
  662. XferVersion version = currentVersion;
  663. xfer->xferVersion( &version, currentVersion );
  664. // extend base class
  665. StateMachine::xfer(xfer);
  666. Int i;
  667. Int count = m_goalPath.size();
  668. xfer->xferInt(&count);
  669. for (i=0; i<count; i++) {
  670. Coord3D pos;
  671. if (xfer->getXferMode() != XFER_LOAD)
  672. {
  673. pos = m_goalPath[i];
  674. }
  675. xfer->xferCoord3D(&pos);
  676. if (xfer->getXferMode() == XFER_LOAD)
  677. {
  678. m_goalPath.push_back(pos);
  679. }
  680. }
  681. AsciiString waypointName;
  682. if (m_goalWaypoint) waypointName = m_goalWaypoint->getName();
  683. xfer->xferAsciiString(&waypointName);
  684. if (xfer->getXferMode() == XFER_LOAD)
  685. {
  686. if (waypointName.isNotEmpty()) {
  687. m_goalWaypoint = TheTerrainLogic->getWaypointByName(waypointName);
  688. }
  689. }
  690. Bool hasSquad = (m_goalSquad!=NULL);
  691. xfer->xferBool(&hasSquad);
  692. if (xfer->getXferMode() == XFER_LOAD)
  693. {
  694. if (hasSquad && m_goalSquad==NULL) {
  695. m_goalSquad = newInstance( Squad );
  696. }
  697. }
  698. if (hasSquad) {
  699. xfer->xferSnapshot(m_goalSquad);
  700. }
  701. StateID id = INVALID_STATE_ID;
  702. if (m_temporaryState) {
  703. id = m_temporaryState->getID();
  704. DEBUG_ASSERTCRASH(id!=INVALID_STATE_ID, ("State has invalid state id, no really. jba."));
  705. }
  706. xfer->xferUnsignedInt(&id);
  707. if (xfer->getXferMode() == XFER_LOAD && id != INVALID_STATE_ID) {
  708. m_temporaryState = internalGetState( id );
  709. }
  710. if (m_temporaryState!=NULL) {
  711. xfer->xferSnapshot(m_temporaryState);
  712. }
  713. xfer->xferUnsignedInt(&m_temporaryStateFramEnd);
  714. } // end xfer
  715. // ------------------------------------------------------------------------------------------------
  716. /** Load post process */
  717. // ------------------------------------------------------------------------------------------------
  718. void AIStateMachine::loadPostProcess( void )
  719. {
  720. StateMachine::loadPostProcess();
  721. } // end loadPostProcess
  722. //----------------------------------------------------------------------------------------------------------
  723. /**
  724. * Define a simple path
  725. */
  726. void AIStateMachine::setGoalPath( const std::vector<Coord3D>* path )
  727. {
  728. m_goalPath = *path;
  729. }
  730. #ifdef STATE_MACHINE_DEBUG
  731. //----------------------------------------------------------------------------------------------------------
  732. /**
  733. * Get the current state name.
  734. */
  735. AsciiString AIStateMachine::getCurrentStateName(void) const
  736. {
  737. AsciiString name = StateMachine::getCurrentStateName();
  738. if (m_temporaryState) {
  739. name.concat(" /T/");
  740. name.concat(m_temporaryState->getName());
  741. }
  742. return name;
  743. }
  744. #endif
  745. //-----------------------------------------------------------------------------
  746. /**
  747. * Run one step of the machine
  748. */
  749. StateReturnType AIStateMachine::updateStateMachine()
  750. {
  751. if (m_temporaryState)
  752. {
  753. // execute this state
  754. StateReturnType status = m_temporaryState->update();
  755. if (m_temporaryStateFramEnd < TheGameLogic->getFrame()) {
  756. // ran out of time.
  757. if (status == STATE_CONTINUE) {
  758. status = STATE_SUCCESS;
  759. }
  760. }
  761. if (status==STATE_CONTINUE) {
  762. return status;
  763. }
  764. m_temporaryState->onExit(EXIT_NORMAL);
  765. m_temporaryState = NULL;
  766. }
  767. return StateMachine::updateStateMachine();
  768. }
  769. //----------------------------------------------------------------------------------------------------------
  770. /**
  771. * Change the temporary state of the machine, and number of frames limit.th
  772. */
  773. StateReturnType AIStateMachine::setTemporaryState( StateID newStateID, Int frameLimitCoount )
  774. {
  775. // extract the state associated with the given ID
  776. State *newState = internalGetState( newStateID );
  777. #ifdef STATE_MACHINE_DEBUG
  778. if (getWantsDebugOutput())
  779. {
  780. StateID curState = INVALID_STATE_ID;
  781. if (m_temporaryState) {
  782. curState = m_temporaryState->getID();
  783. }
  784. DEBUG_LOG(("%d '%s' -(TEMP)- '%s' %x exit ", TheGameLogic->getFrame(), getOwner()->getTemplate()->getName().str(), getName().str(), this));
  785. if (m_temporaryState) {
  786. DEBUG_LOG((" '%s' ", m_temporaryState->getName().str()));
  787. } else {
  788. DEBUG_LOG((" INVALID_STATE_ID "));
  789. }
  790. if (newState) {
  791. DEBUG_LOG(("enter '%s' \n", newState->getName().str()));
  792. } else {
  793. DEBUG_LOG(("to INVALID_STATE\n"));
  794. }
  795. }
  796. #endif
  797. if (m_temporaryState) {
  798. m_temporaryState->onExit(EXIT_RESET);
  799. m_temporaryState = NULL;
  800. }
  801. if (newState) {
  802. m_temporaryState = newState;
  803. StateReturnType ret = m_temporaryState->onEnter();
  804. if (ret != STATE_CONTINUE) {
  805. m_temporaryState->onExit(EXIT_NORMAL);
  806. m_temporaryState = NULL;
  807. return ret;
  808. }
  809. enum {FRAME_COUNT_MAX = 60*LOGICFRAMES_PER_SECOND};
  810. // If you need to up this check, ok, but 1 minute seems overly long for a temporary state override. jba.
  811. DEBUG_ASSERTCRASH(frameLimitCoount<=FRAME_COUNT_MAX, ("Unusually long time to set temporary state."));
  812. if (frameLimitCoount>FRAME_COUNT_MAX) {
  813. frameLimitCoount = FRAME_COUNT_MAX;
  814. }
  815. m_temporaryStateFramEnd = TheGameLogic->getFrame()+frameLimitCoount;
  816. return ret;
  817. }
  818. return STATE_FAILURE;
  819. }
  820. //----------------------------------------------------------------------------------------------------------
  821. /**
  822. * Add a point to a simple path
  823. */
  824. void AIStateMachine::addToGoalPath( const Coord3D *pathPoint)
  825. {
  826. if (m_goalPath.size()==0) {
  827. m_goalPath.push_back(*pathPoint);
  828. } else {
  829. Coord3D *finalPoint = &m_goalPath[ m_goalPath.size() - 1 ];
  830. if( !finalPoint->equals( *pathPoint ) )
  831. {
  832. m_goalPath.push_back(*pathPoint);
  833. }
  834. }
  835. }
  836. //----------------------------------------------------------------------------------------------------------
  837. /**
  838. * Return path position at index "i"
  839. */
  840. const Coord3D *AIStateMachine::getGoalPathPosition( Int i ) const
  841. {
  842. if (i < 0 || i >= m_goalPath.size())
  843. return NULL;
  844. return &m_goalPath[i];
  845. }
  846. //----------------------------------------------------------------------------------------------------------
  847. /**
  848. * Set the current goal waypoint. If we reach this waypoint and there
  849. * are connections to further points, continue on.
  850. */
  851. void AIStateMachine::setGoalWaypoint( const Waypoint *way )
  852. {
  853. m_goalWaypoint = way;
  854. }
  855. //----------------------------------------------------------------------------------------------------------
  856. /**
  857. * Return the current goal waypoint
  858. */
  859. const Waypoint *AIStateMachine::getGoalWaypoint()
  860. {
  861. return m_goalWaypoint;
  862. }
  863. //----------------------------------------------------------------------------------------------------------
  864. void AIStateMachine::clear()
  865. {
  866. StateMachine::clear();
  867. m_goalPath.clear();
  868. m_goalWaypoint = NULL;
  869. m_goalSquad = NULL;
  870. AIUpdateInterface* ai = getOwner()->getAI();
  871. if (ai)
  872. ai->friend_notifyStateMachineChanged();
  873. }
  874. //----------------------------------------------------------------------------------------------------------
  875. StateReturnType AIStateMachine::resetToDefaultState()
  876. {
  877. StateReturnType tmp = StateMachine::resetToDefaultState();
  878. AIUpdateInterface* ai = getOwner()->getAI();
  879. if (ai)
  880. ai->friend_notifyStateMachineChanged();
  881. return tmp;
  882. }
  883. //----------------------------------------------------------------------------------------------------------
  884. StateReturnType AIStateMachine::setState(StateID newStateID)
  885. {
  886. StateID oldID = getCurrentStateID();
  887. StateReturnType tmp = StateMachine::setState(newStateID);
  888. AIUpdateInterface* ai = getOwner()->getAI();
  889. if (ai && oldID != newStateID)
  890. ai->friend_notifyStateMachineChanged();
  891. return tmp;
  892. }
  893. //----------------------------------------------------------------------------------------------------------
  894. void AIStateMachine::setGoalTeam( const Team *team )
  895. {
  896. if (m_goalSquad == NULL) {
  897. m_goalSquad = newInstance( Squad );
  898. }
  899. m_goalSquad->squadFromTeam(team, true);
  900. }
  901. //----------------------------------------------------------------------------------------------------------
  902. void AIStateMachine::setGoalSquad( const Squad *squad )
  903. {
  904. if (m_goalSquad == NULL) {
  905. m_goalSquad = newInstance( Squad );
  906. }
  907. (*m_goalSquad) = (*squad);
  908. }
  909. //----------------------------------------------------------------------------------------------------------
  910. void AIStateMachine::setGoalAIGroup( const AIGroup *group )
  911. {
  912. if (m_goalSquad == NULL) {
  913. m_goalSquad = newInstance( Squad );
  914. }
  915. m_goalSquad->squadFromAIGroup(group, true);
  916. }
  917. //----------------------------------------------------------------------------------------------------------
  918. Squad *AIStateMachine::getGoalSquad( void )
  919. {
  920. return m_goalSquad;
  921. }
  922. // State transition conditions ----------------------------------------------------------------------------
  923. /**
  924. * Return true if the machine's owner's current weapon's range
  925. * cannot reach the goalObject.
  926. */
  927. Bool outOfWeaponRangeObject( State *thisState, void* userData )
  928. {
  929. Object *obj = thisState->getMachineOwner();
  930. Object *victim = thisState->getMachineGoalObject();
  931. Weapon *weapon = obj->getCurrentWeapon();
  932. CRCDEBUG_LOG(("outOfWeaponRangeObject()\n"));
  933. if (victim && weapon)
  934. {
  935. Bool viewBlocked = false;
  936. AIUpdateInterface *ai = obj->getAI();
  937. Bool onGround = true;
  938. if (ai) {
  939. onGround = ai->isDoingGroundMovement();
  940. }
  941. if( obj->isKindOf(KINDOF_IMMOBILE) ) {
  942. onGround = true;
  943. }
  944. // brutal special case for stinger soldiers, who
  945. // generally don't have locomotors, but are still on the ground.
  946. if (obj->isKindOf(KINDOF_SPAWNS_ARE_THE_WEAPONS))
  947. {
  948. onGround = true;
  949. }
  950. Object *containedBy = obj->getContainedBy();
  951. if( containedBy && (containedBy->isKindOf( KINDOF_STRUCTURE ) || !containedBy->isAirborneTarget()) )
  952. {
  953. //Contained objects on the ground -- garrisoned buildings for example!
  954. onGround = true;
  955. }
  956. // srj sez: at tiny ranges, isAttackViewBlockedByObstacle() can return false positives,
  957. // so just skip it for contact weapons
  958. if (victim && !weapon->isContactWeapon() && onGround && !victim->isSignificantlyAboveTerrain())
  959. {
  960. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(obj, *obj->getPosition(), victim, *victim->getPosition());
  961. }
  962. // A weapon with leech range temporarily has unlimited range and is locked onto its target.
  963. if (!weapon->hasLeechRange() && viewBlocked)
  964. {
  965. //CRCDEBUG_LOG(("outOfWeaponRangeObject() - object %d (%s) view is blocked for attacking %d (%s)\n",
  966. // obj->getID(), obj->getTemplate()->getName().str(),
  967. // victim->getID(), victim->getTemplate()->getName().str()));
  968. return true;
  969. }
  970. if (!weapon->hasLeechRange() && !weapon->isWithinAttackRange(obj, victim))
  971. {
  972. //CRCDEBUG_LOG(("outOfWeaponRangeObject() - object %d (%s) is out of range for attacking %d (%s)\n",
  973. // obj->getID(), obj->getTemplate()->getName().str(),
  974. // victim->getID(), victim->getTemplate()->getName().str()));
  975. return true;
  976. }
  977. }
  978. return false;
  979. }
  980. static Bool inWeaponRangeObject(State *thisState, void* userData)
  981. {
  982. return !outOfWeaponRangeObject(thisState, userData);
  983. }
  984. Bool wantToSquishTarget( State *thisState, void* userData )
  985. {
  986. Object *obj = thisState->getMachineOwner();
  987. Object *victim = thisState->getMachineGoalObject();
  988. if (obj && victim)
  989. {
  990. if (victim->getContainedBy()) {
  991. return false; // can't crush guys in buildings or vehicles.
  992. }
  993. if( obj->getAI() && (obj->getAI()->getWhichTurretForCurWeapon() != TURRET_INVALID) )
  994. {
  995. // I can only decide to crush-attack if I am attacking with a turreted weapon.
  996. if (TheAI->getAiData()->m_aiCrushesInfantry) {
  997. if (obj && obj->getControllingPlayer() &&
  998. obj->getControllingPlayer()->getPlayerType()==PLAYER_COMPUTER) {
  999. if (obj->canCrushOrSquish(victim)) {
  1000. if (!obj->isKindOf(KINDOF_DONT_AUTO_CRUSH_INFANTRY)) {
  1001. return true;
  1002. }
  1003. }
  1004. }
  1005. }
  1006. }
  1007. }
  1008. return false;
  1009. }
  1010. Bool outOfWeaponRangePosition( State *thisState, void* userData )
  1011. {
  1012. Object *obj = thisState->getMachineOwner();
  1013. const Coord3D *pos = thisState->getMachineGoalPosition();
  1014. Weapon *weapon = obj->getCurrentWeapon();
  1015. if (weapon && pos)
  1016. {
  1017. AIUpdateInterface *ai = obj->getAI();
  1018. Bool onGround = true;
  1019. if (ai) {
  1020. onGround = ai->isDoingGroundMovement();
  1021. }
  1022. if( obj->isKindOf(KINDOF_IMMOBILE) ) {
  1023. onGround = true;
  1024. }
  1025. // brutal special case for stinger soldiers, who
  1026. // generally don't have locomotors, but are still on the ground.
  1027. if (obj->isKindOf(KINDOF_SPAWNS_ARE_THE_WEAPONS))
  1028. {
  1029. onGround = true;
  1030. }
  1031. Object *containedBy = obj->getContainedBy();
  1032. if( containedBy && (containedBy->isKindOf( KINDOF_STRUCTURE ) || !containedBy->isAirborneTarget()) )
  1033. {
  1034. //Contained objects on the ground -- garrisoned buildings for example!
  1035. onGround = true;
  1036. }
  1037. Bool viewBlocked = false;
  1038. if (onGround)
  1039. {
  1040. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(obj, *obj->getPosition(), NULL, *pos);
  1041. }
  1042. if (viewBlocked)
  1043. {
  1044. return true;
  1045. }
  1046. if (!weapon->isWithinAttackRange(obj, pos))
  1047. {
  1048. return true;
  1049. }
  1050. }
  1051. return false;
  1052. }
  1053. /**
  1054. * Return true if the machine's owner's cannot attack in any way
  1055. */
  1056. static Bool cannotPossiblyAttackObject( State *thisState, void* userData )
  1057. {
  1058. AbleToAttackType attackType = (AbleToAttackType)(UnsignedInt)userData;
  1059. Object *obj = thisState->getMachineOwner();
  1060. Object *victim = thisState->getMachineGoalObject();
  1061. if (obj && victim)
  1062. {
  1063. if( !obj->isAbleToAttack() )
  1064. {
  1065. return TRUE;
  1066. }
  1067. CanAttackResult result = obj->getAbleToAttackSpecificObject( attackType, victim, obj->getAI()->getLastCommandSource() );
  1068. if( result != ATTACKRESULT_POSSIBLE && result != ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  1069. {
  1070. return TRUE;
  1071. }
  1072. }
  1073. return FALSE;
  1074. }
  1075. //----------------------------------------------------------------------------------------------
  1076. //----------------------------------------------------------------------------------------------
  1077. //----------------------------------------------------------------------------------------------
  1078. const UnsignedInt IDLE_COUNTDOWN_DELAY = (LOGICFRAMES_PER_SECOND * 2);
  1079. //----------------------------------------------------------------------------------------------
  1080. AIIdleState::AIIdleState( StateMachine *machine, AIIdleState::AIIdleTargetingType shouldLookForTargets ) :
  1081. State( machine,"AIIdleState"),
  1082. m_shouldLookForTargets(shouldLookForTargets == AIIdleState::LOOK_FOR_TARGETS)
  1083. {
  1084. m_inited = FALSE;
  1085. m_initialSleepOffset = -1;
  1086. }
  1087. // ------------------------------------------------------------------------------------------------
  1088. /** CRC */
  1089. // ------------------------------------------------------------------------------------------------
  1090. void AIIdleState::crc( Xfer *xfer )
  1091. {
  1092. } // end crc
  1093. // ------------------------------------------------------------------------------------------------
  1094. /** Xfer Method */
  1095. // ------------------------------------------------------------------------------------------------
  1096. void AIIdleState::xfer( Xfer *xfer )
  1097. {
  1098. // version
  1099. XferVersion currentVersion = 1;
  1100. XferVersion version = currentVersion;
  1101. xfer->xferVersion( &version, currentVersion );
  1102. xfer->xferUnsignedShort(&m_initialSleepOffset);
  1103. xfer->xferBool(&m_shouldLookForTargets);
  1104. xfer->xferBool(&m_inited);
  1105. } // end xfer
  1106. // ------------------------------------------------------------------------------------------------
  1107. /** Load post process */
  1108. // ------------------------------------------------------------------------------------------------
  1109. void AIIdleState::loadPostProcess( void )
  1110. {
  1111. } // end loadPostProcess
  1112. //----------------------------------------------------------------------------------------------
  1113. /**
  1114. * Stake out our space.
  1115. */
  1116. DECLARE_PERF_TIMER(AIIdleState)
  1117. StateReturnType AIIdleState::onEnter()
  1118. {
  1119. USE_PERF_TIMER(AIIdleState)
  1120. Object *obj = getMachineOwner();
  1121. AIUpdateInterface *ai = obj->getAI();
  1122. // We could possibly not have ai here if we were constructed this frame. Strange but true. :-<
  1123. if (ai)
  1124. ai->resetNextMoodCheckTime();
  1125. m_inited = true;
  1126. // reset the idle countdown so that we don't do expensive checks too often,
  1127. // randomized so we avoid spikes
  1128. m_initialSleepOffset = (UnsignedShort)GameLogicRandomValue(0, IDLE_COUNTDOWN_DELAY);
  1129. // never sleep at the start, since we have to do checkGoalPos first time thru
  1130. return STATE_CONTINUE;
  1131. }
  1132. //----------------------------------------------------------------------------------------------
  1133. void AIIdleState::doInitIdleState()
  1134. {
  1135. // Only do it once, but do it in the update cause onEnter for idle is called during object creation. jba.
  1136. if (!m_inited)
  1137. return;
  1138. m_inited = false;
  1139. Object *obj = getMachineOwner();
  1140. AIUpdateInterface *ai = obj->getAI();
  1141. const Locomotor* loco = ai->getCurLocomotor();
  1142. Bool ultraAccurate = (loco != NULL && loco->isUltraAccurate());
  1143. #define NO_STOP_AND_SLIDE
  1144. if (ai->isIdle() && ai->isDoingGroundMovement())
  1145. {
  1146. /*
  1147. You may be asking yourself, "If I'm in an idle state, how can I be doing ground movement?"
  1148. answer from jba:
  1149. If a unit is moving, and you hit stop, it forces it into the idle state.
  1150. Depending where it is, it may be between pathfind grids.
  1151. This is a bad thing.
  1152. So it "cheat moves", to the nearest grid.
  1153. Also, for locos the "close enough" distance is 1 or so.
  1154. So it moves the rest of the way to it's goal location by cheating.
  1155. */
  1156. // Update the goal.
  1157. Coord3D goalPos = *obj->getPosition();
  1158. // but only if we have a valid position.
  1159. if (goalPos.x || goalPos.y || goalPos.z)
  1160. {
  1161. TheAI->pathfinder()->updateGoal(obj, &goalPos, obj->getLayer());
  1162. if (!ultraAccurate && TheAI->pathfinder()->goalPosition(obj, &goalPos))
  1163. {
  1164. if (TheGameLogic->getFrame()<=1) {
  1165. obj->setPosition(&goalPos);
  1166. } else {
  1167. #ifdef STOP_AND_SLIDE
  1168. ai->setFinalPosition(&goalPos);
  1169. #endif
  1170. }
  1171. TheAI->pathfinder()->updateGoal(obj, &goalPos, obj->getLayer());
  1172. }
  1173. }
  1174. }
  1175. ai->setLocomotorGoalNone();
  1176. ai->setCurrentVictim(NULL);
  1177. }
  1178. //----------------------------------------------------------------------------------------------
  1179. /**
  1180. * Just sit there.
  1181. */
  1182. StateReturnType AIIdleState::update()
  1183. {
  1184. USE_PERF_TIMER(AIIdleState)
  1185. doInitIdleState();
  1186. UnsignedInt timeToSleep = IDLE_COUNTDOWN_DELAY + m_initialSleepOffset;
  1187. UnsignedInt oldSleepOffset = m_initialSleepOffset;
  1188. m_initialSleepOffset = 0;
  1189. // This state is used internally some places, so we don't necessarily want to be looking for targets
  1190. // Places that use AI_IDLE internally should set this to false in the constructor. jkmcd
  1191. if ( m_shouldLookForTargets && !getMachine()->isLocked() )
  1192. {
  1193. // if we are here, it's time to check again
  1194. Object *obj = getMachineOwner();
  1195. AIUpdateInterface *ai = obj->getAI();
  1196. // do repulsor logic
  1197. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED) && ai->isIdle())
  1198. {
  1199. Object* enemy = TheAI->findClosestRepulsor(obj, obj->getVisionRange());
  1200. if (enemy)
  1201. {
  1202. getMachine()->setState(AI_MOVE_AWAY_FROM_REPULSORS);
  1203. // since we just changed the state, it doesn't really matter what we return here.
  1204. return STATE_CONTINUE;
  1205. }
  1206. }
  1207. // Check to see if we have created a crate we need to pick up.
  1208. Object* crate = ai->checkForCrateToPickup();
  1209. if (crate)
  1210. {
  1211. ai->aiMoveToObject(crate, CMD_FROM_AI);
  1212. // since we just changed the state, it doesn't really matter what we return here.
  1213. return STATE_CONTINUE;
  1214. }
  1215. if (! obj->isDisabledByType( DISABLED_PARALYZED ) &&
  1216. ! obj->isDisabledByType( DISABLED_UNMANNED ) &&
  1217. ! obj->isDisabledByType( DISABLED_EMP ) &&
  1218. ! obj->isDisabledByType( DISABLED_HACKED ) )
  1219. {
  1220. // mood targeting
  1221. UnsignedInt moodAdjust = ai->getMoodMatrixActionAdjustment(MM_Action_Idle);
  1222. if ((moodAdjust & MAA_Affect_Range_IgnoreAll) == 0)
  1223. {
  1224. // If we're supposed to attack based on mood, etc, then we will do so.
  1225. Object* enemy = ai->getNextMoodTarget( true, true );
  1226. if (enemy)
  1227. {
  1228. ai->aiAttackObject(enemy, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  1229. // weird but true. return state_continue, because if we're here, we're actually an attack state
  1230. // since we just changed the state, it doesn't really matter what we return here.
  1231. return STATE_CONTINUE;
  1232. }
  1233. }
  1234. }
  1235. UnsignedInt now = TheGameLogic->getFrame();
  1236. UnsignedInt nextMoodCheckTime = ai->getNextMoodCheckTime();
  1237. if (nextMoodCheckTime > now)
  1238. {
  1239. // if we need to look for targets, might need to sleep less.
  1240. UnsignedInt moodSleep = nextMoodCheckTime - now;
  1241. if (moodSleep < timeToSleep)
  1242. {
  1243. timeToSleep = moodSleep;
  1244. // if we do this, save the random sleep offset for next time.
  1245. m_initialSleepOffset = oldSleepOffset;
  1246. }
  1247. }
  1248. } // end if, should look for targets
  1249. return STATE_SLEEP(timeToSleep);
  1250. }
  1251. //----------------------------------------------------------------------------------------------
  1252. /**
  1253. * Just sit there, but dead-like.
  1254. */
  1255. StateReturnType AIDeadState::onEnter()
  1256. {
  1257. Object *obj = getMachineOwner();
  1258. // How can an object be NULL here? I don't think it actually can, but this check must be
  1259. // here for a reason. - jkmcd
  1260. if (obj)
  1261. {
  1262. ModelConditionFlags nonDyingStuff;
  1263. nonDyingStuff.set(MODELCONDITION_USING_WEAPON_A);
  1264. nonDyingStuff.set(MODELCONDITION_USING_WEAPON_B);
  1265. nonDyingStuff.set(MODELCONDITION_USING_WEAPON_C);
  1266. nonDyingStuff.set(MODELCONDITION_FIRING_A);
  1267. nonDyingStuff.set(MODELCONDITION_FIRING_B);
  1268. nonDyingStuff.set(MODELCONDITION_FIRING_C);
  1269. nonDyingStuff.set(MODELCONDITION_BETWEEN_FIRING_SHOTS_A);
  1270. nonDyingStuff.set(MODELCONDITION_BETWEEN_FIRING_SHOTS_B);
  1271. nonDyingStuff.set(MODELCONDITION_BETWEEN_FIRING_SHOTS_C);
  1272. nonDyingStuff.set(MODELCONDITION_RELOADING_A);
  1273. nonDyingStuff.set(MODELCONDITION_RELOADING_B);
  1274. nonDyingStuff.set(MODELCONDITION_RELOADING_C);
  1275. nonDyingStuff.set(MODELCONDITION_PREATTACK_A);
  1276. nonDyingStuff.set(MODELCONDITION_PREATTACK_B);
  1277. nonDyingStuff.set(MODELCONDITION_PREATTACK_C);
  1278. #ifdef ALLOW_SURRENDER
  1279. nonDyingStuff.set(MODELCONDITION_SURRENDER);
  1280. #endif
  1281. nonDyingStuff.set(MODELCONDITION_MOVING);
  1282. // dying objects are NEVER firing, surrendered, etc, so clear 'em all here.
  1283. obj->clearAndSetModelConditionFlags(nonDyingStuff, MAKE_MODELCONDITION_MASK(MODELCONDITION_DYING));
  1284. TheScriptEngine->notifyOfObjectCreationOrDestruction();
  1285. }
  1286. return STATE_CONTINUE;
  1287. }
  1288. StateReturnType AIDeadState::update()
  1289. {
  1290. Object *obj = getMachineOwner();
  1291. AIUpdateInterface *ai = obj->getAI();
  1292. ai->setLocomotorGoalNone();
  1293. // re-mark this every time, just in case our health miraculously heals from 0 to nonzero...
  1294. obj->setEffectivelyDead(true);
  1295. if (obj->isKindOf(KINDOF_INFANTRY))
  1296. {
  1297. PhysicsBehavior* phys = obj->getPhysics();
  1298. if (phys)
  1299. {
  1300. // we want 'em to stop, but looks wonky if they stop dead in their tracks in onEnter.
  1301. // this slows 'em down quickly
  1302. const Real FACTOR = 0.8f; // 0.8 ^ 30 == 0.012, so they slow to 4% of speed over 1 sec
  1303. Real vel = phys->getVelocityMagnitude();
  1304. phys->scrubVelocity2D(vel * FACTOR);
  1305. }
  1306. }
  1307. return STATE_CONTINUE;
  1308. }
  1309. void AIDeadState::onExit( StateExitType status )
  1310. {
  1311. Object *obj = getMachineOwner();
  1312. obj->clearModelConditionState(MODELCONDITION_DYING);
  1313. }
  1314. //----------------------------------------------------------------------------------------------
  1315. // ------------------------------------------------------------------------------------------------
  1316. /** CRC */
  1317. // ------------------------------------------------------------------------------------------------
  1318. void AIInternalMoveToState::crc( Xfer *xfer )
  1319. {
  1320. } // end crc
  1321. // ------------------------------------------------------------------------------------------------
  1322. /** Xfer Method */
  1323. // ------------------------------------------------------------------------------------------------
  1324. void AIInternalMoveToState::xfer( Xfer *xfer )
  1325. {
  1326. // version
  1327. XferVersion currentVersion = 1;
  1328. XferVersion version = currentVersion;
  1329. xfer->xferVersion( &version, currentVersion );
  1330. // extend base class
  1331. xfer->xferCoord3D(&m_goalPosition);
  1332. xfer->xferUser(&m_goalLayer, sizeof(m_goalLayer));
  1333. xfer->xferBool(&m_waitingForPath);
  1334. xfer->xferCoord3D(&m_pathGoalPosition);
  1335. xfer->xferUnsignedInt(&m_pathTimestamp);
  1336. xfer->xferUnsignedInt(&m_blockedRepathTimestamp);
  1337. xfer->xferBool(&m_adjustDestinations);
  1338. } // end xfer
  1339. // ------------------------------------------------------------------------------------------------
  1340. /** Load post process */
  1341. // ------------------------------------------------------------------------------------------------
  1342. void AIInternalMoveToState::loadPostProcess( void )
  1343. {
  1344. startMoveSound();
  1345. } // end loadPostProcess
  1346. Bool AIInternalMoveToState::getAdjustsDestination() const
  1347. {
  1348. const Object *obj = getMachineOwner();
  1349. if (obj->testStatus(OBJECT_STATUS_PARACHUTING))
  1350. return false;
  1351. const AIUpdateInterface* ai = obj->getAI();
  1352. if (ai && !ai->isAllowedToAdjustDestination())
  1353. return false;
  1354. return m_adjustDestinations;
  1355. }
  1356. /**
  1357. * (Re)compute a path to the goal position, if we are on our own,
  1358. * or we are the leader of a group.
  1359. */
  1360. Bool AIInternalMoveToState::computePath()
  1361. {
  1362. Object *obj = getMachineOwner();
  1363. AIUpdateInterface *ai = obj->getAI();
  1364. m_waitingForPath = true;
  1365. ai->requestPath(&m_goalPosition, getAdjustsDestination());
  1366. ai->friend_startingMove();
  1367. return true;
  1368. }
  1369. /**
  1370. * We are initiating a moveTo action.
  1371. * Pathfind from m_goalPosition to goal.
  1372. */
  1373. StateReturnType AIInternalMoveToState::onEnter()
  1374. {
  1375. m_ambientPlayingHandle = AHSV_Error;
  1376. Object *obj = getMachineOwner();
  1377. AIUpdateInterface *ai = obj->getAI();
  1378. m_waitingForPath = ai->isWaitingForPath();
  1379. if (ai->getCurLocomotor()) {
  1380. ai->getCurLocomotor()->startMove();
  1381. if (ai->getCurLocomotor()->isUltraAccurate())
  1382. {
  1383. setAdjustsDestination(false); // if we're being ultra accurate, we can't adjust the destination. jba.
  1384. }
  1385. }
  1386. m_tryOneMoreRepath = true; // We may try one more repath after the first one is finished.
  1387. ai->friend_startingMove();
  1388. // get object physics state
  1389. PhysicsBehavior *physics = obj->getPhysics();
  1390. if (physics && physics->isMotive()) {
  1391. // If we were already moving, go immediately to the animation.
  1392. // This is so if you redirect a moving infantry or other animated model, he doesn't
  1393. // pop into idle for 1 frame. jba.
  1394. //Determine if we are on a cliff cell... if so, use the climbing model condition
  1395. //instead of moving.
  1396. Int cellX = REAL_TO_INT( obj->getPosition()->x / PATHFIND_CELL_SIZE );
  1397. Int cellY = REAL_TO_INT( obj->getPosition()->y / PATHFIND_CELL_SIZE );
  1398. PathfindCell* cell = TheAI->pathfinder()->getCell( obj->getLayer(), cellX, cellY );
  1399. ModelConditionFlagType modelConditionFlag = (cell && cell->getType() != PathfindCell::CELL_CLIFF) ? MODELCONDITION_MOVING : MODELCONDITION_CLIMBING;
  1400. obj->setModelConditionState( modelConditionFlag );
  1401. }
  1402. // This is a classic January 2 type of hack
  1403. // Since the worker can go into its attack modelcondition in AIAttack::OnEnter(),
  1404. // it needs to get its moving modelcondition set timely enough to trigger a transition
  1405. // from conditionX into ATTACKING|MOVING... Thanks for reading, MLorenzen, Jan 2, 2003
  1406. else if ( obj->isKindOf( KINDOF_DOZER ) && obj->isKindOf( KINDOF_HARVESTER ) )
  1407. obj->setModelConditionState( MODELCONDITION_MOVING );
  1408. if (getAdjustsDestination())
  1409. {
  1410. if (!TheAI->pathfinder()->adjustDestination(obj, ai->getLocomotorSet(), &m_goalPosition))
  1411. {
  1412. TheAI->pathfinder()->snapClosestGoalPosition(obj, &m_goalPosition);
  1413. }
  1414. TheAI->pathfinder()->updateGoal(obj, &m_goalPosition, TheTerrainLogic->getLayerForDestination(&m_goalPosition));
  1415. }
  1416. // request a path to the destination
  1417. if (!computePath())
  1418. {
  1419. ai->friend_endingMove();
  1420. return STATE_FAILURE;
  1421. }
  1422. // Target to stop at the end of this path.
  1423. // This value will be overriden by the FollowWaypoint ai state.
  1424. ai->setPathExtraDistance(0);
  1425. ai->setDesiredSpeed( FAST_AS_POSSIBLE );
  1426. startMoveSound();
  1427. return STATE_CONTINUE;
  1428. }
  1429. /**
  1430. * Start playing the object's move sound.
  1431. */
  1432. void AIInternalMoveToState::startMoveSound(void)
  1433. {
  1434. Object *obj = getMachineOwner();
  1435. const BodyModuleInterface *objBody = obj->getBodyModule();
  1436. if (objBody && IS_CONDITION_WORSE(objBody->getDamageState(), BODY_DAMAGED))
  1437. {
  1438. AudioEventRTS soundEventMoveDamaged = *obj->getTemplate()->getSoundMoveStartDamaged();
  1439. if (!soundEventMoveDamaged.getEventName().isEmpty())
  1440. {
  1441. soundEventMoveDamaged.setObjectID(obj->getID());
  1442. TheAudio->addAudioEvent( &soundEventMoveDamaged );
  1443. }
  1444. else
  1445. {
  1446. soundEventMoveDamaged = *obj->getTemplate()->getSoundMoveLoopDamaged();
  1447. if (!soundEventMoveDamaged.getEventName().isEmpty())
  1448. {
  1449. soundEventMoveDamaged.setObjectID(obj->getID());
  1450. m_ambientPlayingHandle = TheAudio->addAudioEvent( &soundEventMoveDamaged );
  1451. }
  1452. }
  1453. }
  1454. else
  1455. {
  1456. AudioEventRTS soundEventMove = *obj->getTemplate()->getSoundMoveStart();
  1457. soundEventMove.setObjectID(obj->getID());
  1458. if (!soundEventMove.getEventName().isEmpty())
  1459. {
  1460. TheAudio->addAudioEvent( &soundEventMove );
  1461. }
  1462. else
  1463. {
  1464. soundEventMove = *obj->getTemplate()->getSoundMoveLoop();
  1465. soundEventMove.setObjectID(obj->getID());
  1466. if (!soundEventMove.getEventName().isEmpty())
  1467. {
  1468. m_ambientPlayingHandle = TheAudio->addAudioEvent( &soundEventMove );
  1469. }
  1470. }
  1471. }
  1472. }
  1473. /**
  1474. * We are leaving the moveTo state.
  1475. */
  1476. void AIInternalMoveToState::onExit( StateExitType status )
  1477. {
  1478. Object *obj = getMachineOwner();
  1479. AIUpdateInterface *ai = obj->getAI();
  1480. // stop ambient sound associated with movement
  1481. TheAudio->removeAudioEvent( m_ambientPlayingHandle );
  1482. // If this onExit is the result of the state machine being deleted, then there is no AI.
  1483. // (This is why destructors should not do game logic)
  1484. if (ai) {
  1485. ai->friend_endingMove();
  1486. DEBUG_ASSERTLOG(obj->getTeam(), ("AIInternalMoveToState::onExit obj has NULL team.\n"));
  1487. if (obj->getTeam() && ai->isDoingGroundMovement() && ai->getCurLocomotor() &&
  1488. ai->getCurLocomotor()->isUltraAccurate()) {
  1489. Real dx = m_goalPosition.x-obj->getPosition()->x;
  1490. Real dy = m_goalPosition.y-obj->getPosition()->y;
  1491. if (dx*dx+dy*dy<PATHFIND_CELL_SIZE_F*PATHFIND_CELL_SIZE_F)
  1492. {
  1493. // We are doing accurate ground movement, so make sure we end exactly at the goal.
  1494. ai->setFinalPosition(&m_goalPosition);
  1495. }
  1496. }
  1497. }
  1498. }
  1499. /**
  1500. * Execute the moveTo behavior towards GoalPosition.
  1501. */
  1502. StateReturnType AIInternalMoveToState::update()
  1503. {
  1504. Object *obj = getMachineOwner();
  1505. AIUpdateInterface *ai = obj->getAI();
  1506. Path *thePath = ai->getPath();
  1507. if (m_waitingForPath)
  1508. {
  1509. // bump the timer.
  1510. m_pathTimestamp = TheGameLogic->getFrame();
  1511. if (ai->isWaitingForPath()) {
  1512. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  1513. return STATE_CONTINUE;
  1514. }
  1515. if (thePath==NULL) {
  1516. return STATE_FAILURE;
  1517. }
  1518. m_waitingForPath = false;
  1519. m_pathGoalPosition = m_goalPosition;
  1520. if (this->getAdjustsDestination()) {
  1521. TheAI->pathfinder()->updateGoal(obj, thePath->getLastNode()->getPosition(), thePath->getLastNode()->getLayer());
  1522. } else {
  1523. TheAI->pathfinder()->removeGoal(obj);
  1524. }
  1525. if (!ai->getRetryPath()) {
  1526. m_tryOneMoreRepath = false;
  1527. }
  1528. }
  1529. Bool forceRecompute = false;
  1530. if (thePath==NULL) {
  1531. forceRecompute = true;
  1532. }
  1533. Bool blocked=false;
  1534. if (ai->isBlockedAndStuck() || ai->getNumFramesBlocked()>2*LOGICFRAMES_PER_SECOND) {
  1535. forceRecompute = true;
  1536. blocked = true;
  1537. m_blockedRepathTimestamp = TheGameLogic->getFrame();
  1538. // Intense debug logging jba.
  1539. //DEBUG_LOG(("Info - Blocked - recomputing.\n"));
  1540. }
  1541. //Determine if we are on a cliff cell... if so, use the climbing model condition
  1542. //instead of moving.
  1543. Int cellX = REAL_TO_INT( obj->getPosition()->x / PATHFIND_CELL_SIZE );
  1544. Int cellY = REAL_TO_INT( obj->getPosition()->y / PATHFIND_CELL_SIZE );
  1545. PathfindCell* cell = TheAI->pathfinder()->getCell( obj->getLayer(), cellX, cellY );
  1546. ModelConditionFlagType setConditionFlag = MODELCONDITION_MOVING;
  1547. // Totally hacky set of conditions to make col. burton's monkey ass not slide down
  1548. // the cliffs backwards. This could use some improvement at some point. jba. 31DEC2002
  1549. if (cell && cell->getType() == PathfindCell::CELL_CLIFF && !cell->getPinched()) {
  1550. if (ai->getCurLocomotor() && ai->getCurLocomotor()->isMovingBackwards()) {
  1551. setConditionFlag = MODELCONDITION_RAPPELLING;
  1552. obj->clearModelConditionState( MODELCONDITION_CLIMBING );
  1553. } else {
  1554. setConditionFlag = MODELCONDITION_CLIMBING;
  1555. obj->clearModelConditionState( MODELCONDITION_RAPPELLING );
  1556. }
  1557. }
  1558. if (ai->getNumFramesBlocked()>LOGICFRAMES_PER_SECOND/4)
  1559. {
  1560. obj->clearModelConditionState( MODELCONDITION_MOVING );
  1561. }
  1562. else
  1563. {
  1564. //Clear climbing if modelConditionFlag is not climbing
  1565. if( setConditionFlag == MODELCONDITION_MOVING )
  1566. {
  1567. obj->clearModelConditionState( MODELCONDITION_CLIMBING );
  1568. obj->clearModelConditionState( MODELCONDITION_RAPPELLING );
  1569. }
  1570. obj->setModelConditionState(MODELCONDITION_MOVING);
  1571. if (setConditionFlag!=MODELCONDITION_MOVING) {
  1572. obj->setModelConditionState( setConditionFlag );
  1573. }
  1574. }
  1575. if (ai->canComputeQuickPath()) {
  1576. if (obj->isKindOf(KINDOF_PROJECTILE)) {
  1577. m_pathTimestamp = 0; // We can compute paths cheap, so don't delay to recompute. jba.
  1578. forceRecompute = true;
  1579. }
  1580. }
  1581. if (thePath != NULL)
  1582. ai->setLocomotorGoalPositionOnPath();
  1583. // if our goal has moved, recompute our path
  1584. if (forceRecompute || TheGameLogic->getFrame() - m_pathTimestamp > MIN_REPATH_TIME)
  1585. {
  1586. if (forceRecompute || !isSamePosition(obj->getPosition(), &m_pathGoalPosition, &m_goalPosition ))
  1587. {
  1588. // goal moved - repath
  1589. if (!computePath())
  1590. return STATE_FAILURE;
  1591. // srj sez: must re-set setLocoGoal after computePath, since computePath
  1592. // can set the loco goal to NONE...
  1593. if (ai->getPath() != NULL)
  1594. ai->setLocomotorGoalPositionOnPath();
  1595. else
  1596. return STATE_CONTINUE;
  1597. }
  1598. }
  1599. //
  1600. // Check if we have reached our destination
  1601. //
  1602. Real onPathDistToGoal = ai->getLocomotorDistanceToGoal();
  1603. //DEBUG_LOG(("onPathDistToGoal = %f %s\n",onPathDistToGoal, obj->getTemplate()->getName().str()));
  1604. if (ai->getCurLocomotor() && (onPathDistToGoal < ai->getCurLocomotor()->getCloseEnoughDist()))
  1605. {
  1606. if (ai->isDoingGroundMovement()) {
  1607. // sanity check
  1608. Coord3D delta;
  1609. Coord3D goalPos = m_goalPosition;
  1610. if (ai->getPath()->getLastNode()) {
  1611. goalPos = *ai->getPath()->getLastNode()->getPosition();
  1612. }
  1613. delta.x = obj->getPosition()->x - goalPos.x;
  1614. delta.y = obj->getPosition()->y - goalPos.y;
  1615. delta.z = 0;
  1616. if (delta.length() > 4*PATHFIND_CELL_SIZE_F) {
  1617. //DEBUG_LOG(("AIInternalMoveToState Trying to finish early. Continuing...\n"));
  1618. onPathDistToGoal = ai->getLocomotorDistanceToGoal();
  1619. return STATE_CONTINUE;
  1620. }
  1621. }
  1622. // we have reached the end of the path
  1623. if (getAdjustsDestination())
  1624. {
  1625. ai->setLocomotorGoalNone();
  1626. }
  1627. DEBUG_ASSERTLOG(!getMachine()->getWantsDebugOutput(), ("AIInternalMoveToState::update: reached end of path, exiting state with success\n"));
  1628. return STATE_SUCCESS;
  1629. }
  1630. return STATE_CONTINUE;
  1631. }
  1632. //-------------------------------------------------------------------------------------------------
  1633. //-------------------------------------------------------------------------------------------------
  1634. //-------------------------------------------------------------------------------------------------
  1635. //-----------------------------------------------------------------------------------------------------------
  1636. class AIAttackMoveStateMachine : public StateMachine
  1637. {
  1638. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( AIAttackMoveStateMachine, "AIAttackMoveStateMachine" );
  1639. public:
  1640. AIAttackMoveStateMachine( Object *owner, AsciiString name );
  1641. protected:
  1642. // snapshot interface
  1643. virtual void crc( Xfer *xfer );
  1644. virtual void xfer( Xfer *xfer );
  1645. virtual void loadPostProcess();
  1646. };
  1647. // ------------------------------------------------------------------------------------------------
  1648. /** CRC */
  1649. // ------------------------------------------------------------------------------------------------
  1650. void AIAttackMoveStateMachine::crc( Xfer *xfer )
  1651. {
  1652. StateMachine::crc(xfer);
  1653. } // end crc
  1654. // ------------------------------------------------------------------------------------------------
  1655. /** Xfer Method */
  1656. // ------------------------------------------------------------------------------------------------
  1657. void AIAttackMoveStateMachine::xfer( Xfer *xfer )
  1658. {
  1659. XferVersion cv = 1;
  1660. XferVersion v = cv;
  1661. xfer->xferVersion( &v, cv );
  1662. StateMachine::xfer(xfer);
  1663. } // end xfer
  1664. // ------------------------------------------------------------------------------------------------
  1665. /** Load post process */
  1666. // ------------------------------------------------------------------------------------------------
  1667. void AIAttackMoveStateMachine::loadPostProcess( void )
  1668. {
  1669. StateMachine::loadPostProcess();
  1670. } // end loadPostProcess
  1671. //-----------------------------------------------------------------------------------------------------------
  1672. AIAttackMoveStateMachine::AIAttackMoveStateMachine(Object *owner, AsciiString name) : StateMachine(owner, name)
  1673. {
  1674. // order matters: first state is the default state.
  1675. defineState( AI_IDLE, newInstance(AIIdleState)( this, AIIdleState::DO_NOT_LOOK_FOR_TARGETS ), AI_IDLE, AI_IDLE );
  1676. defineState( AI_PICK_UP_CRATE, newInstance(AIPickUpCrateState)( this ), AI_IDLE, AI_IDLE );
  1677. defineState( AI_ATTACK_OBJECT, newInstance(AIAttackState)(this, false, true, false, NULL ), AI_IDLE, AI_IDLE);
  1678. }
  1679. //----------------------------------------------------------------------------------------------------------
  1680. AIAttackMoveStateMachine::~AIAttackMoveStateMachine()
  1681. {
  1682. }
  1683. //-------------------------------------------------------------------------------------------------
  1684. //-------------------------------------------------------------------------------------------------
  1685. //-------------------------------------------------------------------------------------------------
  1686. //
  1687. // note - has no crc/xfer as has no member vars. jba.
  1688. //-------------------------------------------------------------------------------------------------
  1689. AIMoveToState::AIMoveToState(StateMachine *machine) : m_isMoveTo(true), AIInternalMoveToState( machine, "AIMoveToState" )
  1690. {
  1691. // m_isMoveTo is a boolean that specifies that this thing is ACTUALLY A MOVE TO.
  1692. // child classes should set it false. (We don't have or want RTTI, so...)
  1693. }
  1694. //----------------------------------------------------------------------------------------------------------
  1695. StateReturnType AIMoveToState::onEnter()
  1696. {
  1697. setAdjustsDestination(true);
  1698. //If we have a goal object and are trying to ignore it as an obstacle...
  1699. //This is used in the case of units trying to get really close.
  1700. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1701. if( getMachineGoalObject() )
  1702. {
  1703. if( ai && getMachineGoalObject()->getID() == ai->getIgnoredObstacleID() )
  1704. {
  1705. setAdjustsDestination( false );
  1706. }
  1707. }
  1708. // if we have a goal object, move to it, otherwise move to goal position
  1709. if (getMachineGoalObject()) {
  1710. m_goalPosition = *getMachineGoalObject()->getPosition();
  1711. if (getMachineOwner()->isKindOf(KINDOF_PROJECTILE)) {
  1712. Real halfHeight = getMachineGoalObject()->getGeometryInfo().getMaxHeightAbovePosition()/2.0f;
  1713. m_goalPosition.z += halfHeight;
  1714. if (getMachineGoalObject()->getPosition()->z < m_goalPosition.z) {
  1715. m_goalPosition.z += halfHeight;
  1716. }
  1717. }
  1718. } else
  1719. m_goalPosition = *getMachineGoalPosition();
  1720. StateReturnType ret = AIInternalMoveToState::onEnter();
  1721. if (getMachineOwner()->getFormationID() != NO_FORMATION_ID) {
  1722. AIGroup *group = ai->getGroup();
  1723. if (group) {
  1724. Real speed = group->getSpeed();
  1725. ai->setDesiredSpeed(speed);
  1726. }
  1727. }
  1728. return ret;
  1729. }
  1730. //----------------------------------------------------------------------------------------------------------
  1731. void AIMoveToState::onExit( StateExitType status )
  1732. {
  1733. AIInternalMoveToState::onExit( status );
  1734. }
  1735. //----------------------------------------------------------------------------------------------------------
  1736. StateReturnType AIMoveToState::update()
  1737. {
  1738. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1739. UnsignedInt adjustment = ai->getMoodMatrixActionAdjustment(MM_Action_Move);
  1740. if (m_isMoveTo && (adjustment & MAA_Action_To_AttackMove))
  1741. ai->aiAttackMoveToPosition(&m_goalPosition, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  1742. // if we have a goal object, move to it, as it may have moved
  1743. Object* goalObj = getMachineGoalObject();
  1744. Object *obj = getMachineOwner();
  1745. if (goalObj)
  1746. {
  1747. m_goalPosition = *goalObj->getPosition();
  1748. Bool gotPhysics = obj->getPhysics()!=NULL && goalObj->getPhysics()!=NULL;
  1749. Bool isMissile = obj->isKindOf(KINDOF_PROJECTILE);
  1750. if (isMissile) {
  1751. Real halfHeight = getMachineGoalObject()->getGeometryInfo().getMaxHeightAbovePosition()/2.0f;
  1752. m_goalPosition.z += halfHeight;
  1753. Real zDelta = m_goalPosition.z - obj->getPosition()->z;
  1754. if (zDelta>0) {
  1755. m_goalPosition.z += zDelta;
  1756. }
  1757. }
  1758. //gotPhysics = false;
  1759. if (gotPhysics && isMissile && !goalObj->isKindOf(KINDOF_IMMOBILE)) {
  1760. Coord3D ourPos = *obj->getPosition();
  1761. Coord3D delta;
  1762. delta.x = m_goalPosition.x - ourPos.x;
  1763. delta.y = m_goalPosition.y - ourPos.y;
  1764. delta.z = m_goalPosition.z - ourPos.z;
  1765. Real mySpeed = obj->getPhysics()->getVelocityMagnitude();
  1766. Real goalSpeed = goalObj->getPhysics()->getVelocityMagnitude();
  1767. if (mySpeed<5.0f) mySpeed = 5.0f; // avoid divide by 0.
  1768. Real leadDistance = (0.5*delta.length()) * goalSpeed / mySpeed;
  1769. Coord3D dir;
  1770. goalObj->getUnitDirectionVector3D(dir);
  1771. m_goalPosition.x += dir.x*leadDistance;
  1772. m_goalPosition.y += dir.y*leadDistance;
  1773. m_goalPosition.z += dir.z*leadDistance;
  1774. }
  1775. //DEBUG_LOG(("update goal pos to %f %f %f\n",m_goalPosition.x,m_goalPosition.y,m_goalPosition.z));
  1776. } else {
  1777. Bool isMissile = obj->isKindOf(KINDOF_PROJECTILE);
  1778. if (isMissile) {
  1779. // When missiles are moving uphill, they need to start up quickly to clear hills. jba.
  1780. m_goalPosition = *getMachineGoalPosition();
  1781. Real zDelta = m_goalPosition.z - obj->getPosition()->z;
  1782. if (zDelta>0) {
  1783. m_goalPosition.z += zDelta;
  1784. }
  1785. }
  1786. }
  1787. return AIInternalMoveToState::update();
  1788. }
  1789. //----------------------------------------------------------------------------------------------------------
  1790. //----------------------------------------------------------------------------------------------------------
  1791. //----------------------------------------------------------------------------------------------------------
  1792. //
  1793. // note - has no crc/xfer as has no member vars. jba.
  1794. //----------------------------------------------------------------------------------------------------------
  1795. StateReturnType AIMoveOutOfTheWayState::onEnter()
  1796. {
  1797. setAdjustsDestination(true);
  1798. Object *obj = getMachineOwner();
  1799. AIUpdateInterface *ai = obj->getAI();
  1800. if (ai->getPath()==NULL) {
  1801. // Must have existing path.
  1802. return STATE_FAILURE;
  1803. }
  1804. m_goalPosition = *ai->getPath()->getLastNode()->getPosition();
  1805. return AIInternalMoveToState::onEnter();
  1806. }
  1807. //----------------------------------------------------------------------------------------------------------
  1808. Bool AIMoveOutOfTheWayState::computePath()
  1809. {
  1810. Object *obj = getMachineOwner();
  1811. AIUpdateInterface *ai = obj->getAI();
  1812. m_waitingForPath = true;
  1813. if (ai->isBlockedAndStuck()) {
  1814. ai->setCanPathThroughUnits(true);
  1815. return true; // don't repath, just stop.
  1816. }
  1817. return true; // just use the existing path. See above.
  1818. }
  1819. //----------------------------------------------------------------------------------------------------------
  1820. StateReturnType AIMoveOutOfTheWayState::update()
  1821. {
  1822. return AIInternalMoveToState::update();
  1823. }
  1824. //----------------------------------------------------------------------------------------------------------
  1825. void AIMoveOutOfTheWayState::onExit( StateExitType status )
  1826. {
  1827. AIInternalMoveToState::onExit(status);
  1828. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1829. if (ai) {
  1830. ai->destroyPath();
  1831. ai->setCanPathThroughUnits(false);
  1832. ai->clearMoveOutOfWay();
  1833. }
  1834. }
  1835. //----------------------------------------------------------------------------------------------------------
  1836. //----------------------------------------------------------------------------------------------------------
  1837. //----------------------------------------------------------------------------------------------------------
  1838. // ------------------------------------------------------------------------------------------------
  1839. /** CRC */
  1840. // ------------------------------------------------------------------------------------------------
  1841. void AIMoveAndTightenState::crc( Xfer *xfer )
  1842. {
  1843. AIInternalMoveToState::crc(xfer);
  1844. } // end crc
  1845. // ------------------------------------------------------------------------------------------------
  1846. /** Xfer Method */
  1847. // ------------------------------------------------------------------------------------------------
  1848. void AIMoveAndTightenState::xfer( Xfer *xfer )
  1849. {
  1850. // version
  1851. XferVersion currentVersion = 1;
  1852. XferVersion version = currentVersion;
  1853. xfer->xferVersion( &version, currentVersion );
  1854. // extend base class
  1855. AIInternalMoveToState::xfer(xfer);
  1856. xfer->xferInt(&m_okToRepathTimes);
  1857. xfer->xferBool(&m_checkForPath);
  1858. } // end xfer
  1859. // ------------------------------------------------------------------------------------------------
  1860. /** Load post process */
  1861. // ------------------------------------------------------------------------------------------------
  1862. void AIMoveAndTightenState::loadPostProcess( void )
  1863. {
  1864. AIInternalMoveToState::loadPostProcess();
  1865. } // end loadPostProcess
  1866. //----------------------------------------------------------------------------------------------------------
  1867. StateReturnType AIMoveAndTightenState::onEnter()
  1868. {
  1869. setAdjustsDestination(false);
  1870. Object *obj = getMachineOwner();
  1871. AIUpdateInterface *ai = obj->getAI();
  1872. m_okToRepathTimes = 1;
  1873. m_checkForPath = true;
  1874. TheAI->pathfinder()->removeGoal(obj);
  1875. m_goalPosition = *getMachineGoalPosition();
  1876. ai->requestApproachPath(&m_goalPosition);
  1877. return AIInternalMoveToState::onEnter();
  1878. }
  1879. //----------------------------------------------------------------------------------------------------------
  1880. StateReturnType AIMoveAndTightenState::update()
  1881. {
  1882. if (m_checkForPath) {
  1883. Object *obj = getMachineOwner();
  1884. AIUpdateInterface *ai = obj->getAI();
  1885. Path *thePath = ai->getPath();
  1886. if (thePath && !ai->isWaitingForPath()) {
  1887. setAdjustsDestination(true);
  1888. m_checkForPath = false;
  1889. }
  1890. }
  1891. return AIInternalMoveToState::update();
  1892. }
  1893. //----------------------------------------------------------------------------------------------------------
  1894. Bool AIMoveAndTightenState::computePath()
  1895. {
  1896. Object *obj = getMachineOwner();
  1897. AIUpdateInterface *ai = obj->getAI();
  1898. if (ai->isBlockedAndStuck()) {
  1899. if (m_okToRepathTimes>0) {
  1900. m_okToRepathTimes--;
  1901. m_waitingForPath = true;
  1902. ai->requestPath(&m_goalPosition, true);
  1903. return true;
  1904. }
  1905. //DEBUG_LOG(("AIMoveAndTightenState::computePath - stuck, failing.\n"));
  1906. return false; // don't repath for now. jba.
  1907. }
  1908. return true; // just use the existing path. See above.
  1909. }
  1910. //----------------------------------------------------------------------------------------------------------
  1911. //----------------------------------------------------------------------------------------------------------
  1912. //----------------------------------------------------------------------------------------------------------
  1913. StateReturnType AIMoveAwayFromRepulsorsState::onEnter()
  1914. {
  1915. setAdjustsDestination(false);
  1916. Object *obj = getMachineOwner();
  1917. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  1918. AIUpdateInterface *ai = getMachineOwner()->getAI();
  1919. if (!enemy || !ai) {
  1920. return STATE_FAILURE;
  1921. }
  1922. ai->chooseLocomotorSet(LOCOMOTORSET_PANIC);
  1923. if (obj)
  1924. {
  1925. obj->setModelConditionState(MODELCONDITION_PANICKING);
  1926. }
  1927. m_okToRepathTimes = 1;
  1928. m_checkForPath = true;
  1929. TheAI->pathfinder()->removeGoal(obj);
  1930. ai->requestSafePath(enemy->getID());
  1931. return AIInternalMoveToState::onEnter();
  1932. }
  1933. //----------------------------------------------------------------------------------------------------------
  1934. StateReturnType AIMoveAwayFromRepulsorsState::update()
  1935. {
  1936. if (m_checkForPath) {
  1937. Object *obj = getMachineOwner();
  1938. AIUpdateInterface *ai = obj->getAI();
  1939. Path *thePath = ai->getPath();
  1940. if (thePath && !ai->isWaitingForPath()) {
  1941. m_goalPosition = *thePath->getLastNode()->getPosition();
  1942. setAdjustsDestination(false);
  1943. m_checkForPath = false;
  1944. }
  1945. }
  1946. return AIInternalMoveToState::update();
  1947. }
  1948. //----------------------------------------------------------------------------------------------------------
  1949. Bool AIMoveAwayFromRepulsorsState::computePath()
  1950. {
  1951. if (m_okToRepathTimes>0) {
  1952. m_okToRepathTimes--;
  1953. return true;
  1954. }
  1955. return false; // don't recompute path, just stop moving.
  1956. }
  1957. //----------------------------------------------------------------------------------------------------------
  1958. void AIMoveAwayFromRepulsorsState::onExit( StateExitType status )
  1959. {
  1960. AIInternalMoveToState::onExit( status );
  1961. Object *obj = getMachineOwner();
  1962. if (obj)
  1963. {
  1964. obj->clearModelConditionState(MODELCONDITION_PANICKING);
  1965. }
  1966. }
  1967. //----------------------------------------------------------------------------------------------------------
  1968. //----------------------------------------------------------------------------------------------------------
  1969. //----------------------------------------------------------------------------------------------------------
  1970. /**
  1971. * Returns true if we can pursue the unit. Requires that :
  1972. * 1. We are faster than the other unit.
  1973. * 2. The other unit is moving.
  1974. * 3. The other unit is moving away from us.
  1975. */
  1976. static Bool canPursue(Object *source, Weapon *weapon, Object *victim)
  1977. {
  1978. /* This state is only used if the target is moving away from us, and has physics. */
  1979. if (!victim->getPhysics()) {
  1980. return false;
  1981. }
  1982. AIUpdateInterface *ai = source->getAI();
  1983. if (!ai) {
  1984. return false;
  1985. }
  1986. // Have to have a turret to pursue.
  1987. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  1988. if (tur == TURRET_INVALID) {
  1989. return false;
  1990. }
  1991. if (TheAI->getAiData()->m_aiCrushesInfantry) {
  1992. if ( source->getControllingPlayer() &&
  1993. (source->getControllingPlayer()->getPlayerType() == PLAYER_COMPUTER) &&
  1994. source->canCrushOrSquish(victim) ) {
  1995. return true; // Always pursue if we can squish.
  1996. }
  1997. }
  1998. if (weapon->isTooClose(source, victim)) {
  1999. return false; // Don't chase it if we are already too close.
  2000. }
  2001. Real ourMaxSpeed = source->getAI()->getCurLocomotorSpeed();
  2002. Real victimSpeed = victim->getPhysics()->getForwardSpeed2D();
  2003. if (victimSpeed >= ourMaxSpeed) {
  2004. return false; // we can't catch them.
  2005. }
  2006. if (victimSpeed < ourMaxSpeed/10) {
  2007. return false; // They aren't moving very fast, so don't chase.
  2008. }
  2009. Real dx = victim->getPosition()->x - source->getPosition()->x;
  2010. Real dy = victim->getPosition()->y - source->getPosition()->y;
  2011. Coord3D victimVector = *victim->getUnitDirectionVector2D();
  2012. if (dx*victimVector.x + dy*victimVector.y < 0 ) {
  2013. return false; // they are moving towards us.
  2014. }
  2015. return true;
  2016. }
  2017. //----------------------------------------------------------------------------------------------------------
  2018. /**
  2019. * Compute a valid spot to fire our weapon from.
  2020. * Result in m_goalPosition.
  2021. * Return false if can't find a good spot.
  2022. */
  2023. Bool AIAttackApproachTargetState::computePath()
  2024. {
  2025. Bool forceRepath = false;
  2026. // if we're immobile we can't possibly approach the target
  2027. if( getMachineOwner()->isMobile() == false )
  2028. return false;
  2029. //CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - begin for object %d\n", getMachineOwner()->getID()));
  2030. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2031. if (ai->isBlockedAndStuck())
  2032. {
  2033. forceRepath = true;
  2034. // Intense logging. jba
  2035. //CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - stuck, recomputing for object %d\n", getMachineOwner()->getID()));
  2036. }
  2037. if (m_waitingForPath) return true;
  2038. if (!forceRepath && ai->getPath()==NULL && !ai->isWaitingForPath())
  2039. {
  2040. forceRepath = true;
  2041. }
  2042. // force minimum time between recomputation
  2043. /// @todo Unify recomputation conditions & account for obj ID so everyone doesnt compute on the same frame (MSB)
  2044. if (!forceRepath && TheGameLogic->getFrame() - m_approachTimestamp < MIN_RECOMPUTE_TIME)
  2045. {
  2046. //CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because of min time for object %d\n", getMachineOwner()->getID()));
  2047. return true;
  2048. }
  2049. m_approachTimestamp = TheGameLogic->getFrame();
  2050. // if we have a goal object, move to it, otherwise move to goal position
  2051. if (getMachineGoalObject())
  2052. {
  2053. Object* source = getMachineOwner();
  2054. // if our victim's position hasn't changed, don't re-path
  2055. if (!forceRepath && isSamePosition(source->getPosition(), &m_prevVictimPos, getMachineGoalObject()->getPosition() ))
  2056. {
  2057. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because victim in same place for object %d\n", getMachineOwner()->getID()));
  2058. return true;
  2059. }
  2060. Weapon* weapon = source->getCurrentWeapon();
  2061. if (!weapon)
  2062. {
  2063. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because of no weapon for object %d\n", getMachineOwner()->getID()));
  2064. return false;
  2065. }
  2066. // remember where we think our victim is, so if it moves, we can re-path
  2067. Object *victim = getMachineGoalObject();
  2068. m_prevVictimPos = *victim->getPosition();
  2069. if (canPursue(source, weapon, victim))
  2070. {
  2071. return false; // break out, and do the pursuit state.
  2072. }
  2073. setAdjustsDestination(true);
  2074. if (weapon->isContactWeapon())
  2075. {
  2076. // Weapon is basically a contact weapon, so let the attacker pathfind into the target.
  2077. ai->ignoreObstacle(victim);
  2078. setAdjustsDestination(false); // We want to run into the target.
  2079. ai->setPathExtraDistance(10*PATHFIND_CELL_SIZE_F); // We don't want it to slow down.
  2080. }
  2081. if (ai->isBlockedAndStuck())
  2082. {
  2083. m_waitingForPath = true;
  2084. m_goalPosition = m_prevVictimPos;
  2085. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - requestPath() for object %d\n", getMachineOwner()->getID()));
  2086. ai->requestPath(&m_goalPosition, getAdjustsDestination());
  2087. }
  2088. else
  2089. {
  2090. m_goalPosition = m_prevVictimPos;
  2091. m_waitingForPath = true;
  2092. Coord3D pos;
  2093. victim->getGeometryInfo().getCenterPosition( *victim->getPosition(), pos );
  2094. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - requestAttackPath() for object %d\n", getMachineOwner()->getID()));
  2095. ai->requestAttackPath(victim->getID(), &pos );
  2096. m_stopIfInRange = false; // we have calculated a position to shoot from, so go there.
  2097. }
  2098. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing after repathing for object %d\n", getMachineOwner()->getID()));
  2099. return true;
  2100. }
  2101. else
  2102. {
  2103. // goal position.
  2104. setAdjustsDestination(true);
  2105. m_stopIfInRange = false; // Attack position is used by missiles, and they hit the position.
  2106. m_goalPosition = *getMachineGoalPosition();
  2107. if (!forceRepath)
  2108. {
  2109. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing because we're aiming for a fixed position for object %d\n", getMachineOwner()->getID()));
  2110. return true; // fixed positions don't move.
  2111. }
  2112. // must use computeAttackPath so that min ranges are considered.
  2113. m_waitingForPath = true;
  2114. ai->requestAttackPath(INVALID_ID, &m_goalPosition);
  2115. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing after repathing at a fixed position for object %d\n", getMachineOwner()->getID()));
  2116. return true;
  2117. }
  2118. CRCDEBUG_LOG(("AIAttackApproachTargetState::computePath - bailing at end of function for object %d\n", getMachineOwner()->getID()));
  2119. return true;
  2120. }
  2121. // ------------------------------------------------------------------------------------------------
  2122. /** CRC */
  2123. // ------------------------------------------------------------------------------------------------
  2124. void AIAttackApproachTargetState::crc( Xfer *xfer )
  2125. {
  2126. AIInternalMoveToState::crc(xfer);
  2127. } // end crc
  2128. // ------------------------------------------------------------------------------------------------
  2129. /** Xfer Method */
  2130. // ------------------------------------------------------------------------------------------------
  2131. void AIAttackApproachTargetState::xfer( Xfer *xfer )
  2132. {
  2133. // version
  2134. XferVersion currentVersion = 1;
  2135. XferVersion version = currentVersion;
  2136. xfer->xferVersion( &version, currentVersion );
  2137. // extend base class
  2138. AIInternalMoveToState::xfer( xfer );
  2139. xfer->xferCoord3D(&m_prevVictimPos);
  2140. xfer->xferUnsignedInt(&m_approachTimestamp);
  2141. xfer->xferBool(&m_follow);
  2142. xfer->xferBool(&m_isAttackingObject);
  2143. xfer->xferBool(&m_stopIfInRange);
  2144. xfer->xferBool(&m_isInitialApproach);
  2145. } // end xfer
  2146. // ------------------------------------------------------------------------------------------------
  2147. /** Load post process */
  2148. // ------------------------------------------------------------------------------------------------
  2149. void AIAttackApproachTargetState::loadPostProcess( void )
  2150. {
  2151. // extend base class
  2152. AIInternalMoveToState::loadPostProcess();
  2153. } // end loadPostProcess
  2154. //----------------------------------------------------------------------------------------------------------
  2155. StateReturnType AIAttackApproachTargetState::onEnter()
  2156. {
  2157. // contained by AIAttackState, so no separate timer
  2158. // urg. hacky. if we are a projectile, turn on precise z-pos.
  2159. //CRCDEBUG_LOG(("AIAttackApproachTargetState::onEnter() - object %d\n", getMachineOwner()->getID()));
  2160. Object* source = getMachineOwner();
  2161. AIUpdateInterface* ai = source->getAI();
  2162. if (source->isKindOf(KINDOF_PROJECTILE))
  2163. {
  2164. if (ai->getCurLocomotor())
  2165. ai->getCurLocomotor()->setUsePreciseZPos(true);
  2166. }
  2167. if (getMachine()->isGoalObjectDestroyed())
  2168. {
  2169. return STATE_SUCCESS; // Already killed victim.
  2170. }
  2171. m_prevVictimPos.x = 0.0f;
  2172. m_prevVictimPos.y = 0.0f;
  2173. m_prevVictimPos.z = 0.0f;
  2174. m_approachTimestamp = -MIN_RECOMPUTE_TIME;
  2175. // See if we're close enough.
  2176. Object *victim = getMachineGoalObject();
  2177. if (victim)
  2178. {
  2179. Weapon* weapon = source->getCurrentWeapon();
  2180. if (!weapon)
  2181. {
  2182. return STATE_FAILURE;
  2183. }
  2184. if (weapon->isWithinAttackRange(source, victim))
  2185. {
  2186. Bool viewBlocked = false;
  2187. if (source && victim && ai->isDoingGroundMovement() && !victim->isSignificantlyAboveTerrain())
  2188. {
  2189. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), victim, *victim->getPosition());
  2190. }
  2191. if (!viewBlocked)
  2192. {
  2193. return STATE_SUCCESS;
  2194. }
  2195. }
  2196. // Check here: If we are a player, and we got to this state via an ai command (ie we auto-acquired),
  2197. // we don't want to chase the unit. isAllowedToChase is set when we are in a deploy and attack state (troop crawler).
  2198. if (source->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN) {
  2199. if (ai->getLastCommandSource() == CMD_FROM_AI && !ai->isAllowedToChase() ) {
  2200. if (!weapon->isContactWeapon()) {
  2201. return STATE_FAILURE;
  2202. }
  2203. }
  2204. }
  2205. if (canPursue(source, weapon, victim))
  2206. {
  2207. return STATE_SUCCESS; // break out, and do the pursuit state.
  2208. }
  2209. }
  2210. // If we have a turret, start aiming.
  2211. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2212. if (tur != TURRET_INVALID)
  2213. {
  2214. if (m_isAttackingObject)
  2215. {
  2216. ai->setTurretTargetObject(tur, victim, m_isForceAttacking);
  2217. }
  2218. else
  2219. {
  2220. ai->setTurretTargetPosition(tur, getMachineGoalPosition());
  2221. }
  2222. }
  2223. // find a good spot to shoot from
  2224. //CRCDEBUG_LOG(("AIAttackApproachTargetState::onEnter() - calling computePath() for object %d\n", getMachineOwner()->getID()));
  2225. if (computePath() == false)
  2226. return STATE_FAILURE;
  2227. return AIInternalMoveToState::onEnter();
  2228. }
  2229. //----------------------------------------------------------------------------------------------------------
  2230. StateReturnType AIAttackApproachTargetState::updateInternal()
  2231. {
  2232. AIUpdateInterface* ai = getMachineOwner()->getAI();
  2233. //CRCDEBUG_LOG(("AIAttackApproachTargetState::updateInternal() - object %d\n", getMachineOwner()->getID()));
  2234. if (getMachine()->isGoalObjectDestroyed())
  2235. {
  2236. ai->notifyVictimIsDead();
  2237. ai->setCurrentVictim(NULL);
  2238. return STATE_FAILURE;
  2239. }
  2240. m_stopIfInRange = !ai->isAttackPath();
  2241. StateReturnType code = STATE_FAILURE;
  2242. Object* source = getMachineOwner();
  2243. Weapon* weapon = source->getCurrentWeapon();
  2244. Object *victim = getMachineGoalObject();
  2245. if (victim)
  2246. {
  2247. if( victim->testStatus( OBJECT_STATUS_STEALTHED ) && !victim->testStatus( OBJECT_STATUS_DETECTED ) ) {
  2248. return STATE_FAILURE; // If obj is stealthed, can no longer approach.
  2249. }
  2250. ai->setCurrentVictim(victim);
  2251. // Attacking an object.
  2252. if (weapon && weapon->isContactWeapon() && weapon->isWithinAttackRange(source, victim))
  2253. {
  2254. return STATE_SUCCESS;
  2255. }
  2256. if (m_stopIfInRange && weapon && weapon->isWithinAttackRange(source, victim))
  2257. {
  2258. Bool viewBlocked = false;
  2259. if (victim && ai->isDoingGroundMovement() && !victim->isSignificantlyAboveTerrain())
  2260. {
  2261. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), victim, *victim->getPosition());
  2262. }
  2263. if (!viewBlocked)
  2264. {
  2265. return STATE_SUCCESS;
  2266. }
  2267. }
  2268. // find a good spot to shoot from
  2269. //CRCDEBUG_LOG(("AIAttackApproachTargetState::updateInternal() - calling computePath() to victim for object %d\n", getMachineOwner()->getID()));
  2270. if (computePath() == false)
  2271. return STATE_SUCCESS;
  2272. code = AIInternalMoveToState::update();
  2273. if (code != STATE_CONTINUE)
  2274. {
  2275. return STATE_SUCCESS; // Always return state success, as state failure exits the attack.
  2276. // we may need to aim & do another approach if the target moved. jba.
  2277. }
  2278. }
  2279. else
  2280. {
  2281. // Attacking a position.
  2282. // find a good spot to shoot from
  2283. //CRCDEBUG_LOG(("AIAttackApproachTargetState::updateInternal() - calling computePath() to position for object %d\n", getMachineOwner()->getID()));
  2284. if (m_stopIfInRange && weapon && weapon->isWithinAttackRange(source, &m_goalPosition))
  2285. {
  2286. Bool viewBlocked = false;
  2287. if ( ai->isDoingGroundMovement() )
  2288. {
  2289. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), NULL, m_goalPosition);
  2290. }
  2291. if (!viewBlocked)
  2292. {
  2293. return STATE_SUCCESS;
  2294. }
  2295. }
  2296. if (computePath() == false)
  2297. return STATE_FAILURE;
  2298. code = AIInternalMoveToState::update();
  2299. }
  2300. return code;
  2301. }
  2302. //----------------------------------------------------------------------------------------------------------
  2303. StateReturnType AIAttackApproachTargetState::update()
  2304. {
  2305. // contained by AIAttackState, so no separate timer
  2306. StateReturnType code = updateInternal();
  2307. Object* source = getMachineOwner();
  2308. AIUpdateInterface *ai = source->getAI();
  2309. if (m_follow && m_isAttackingObject)
  2310. {
  2311. // Basically, if the object is alive, we continue, in case the target moves.
  2312. Object* victim = getMachineGoalObject();
  2313. if (source && victim && source->isMobile() && !victim->getTemplate()->isKindOf(KINDOF_IMMOBILE))
  2314. {
  2315. if (code != STATE_CONTINUE)
  2316. {
  2317. m_isInitialApproach = false;
  2318. }
  2319. // Object is still alive (and so are we)
  2320. // It could move (and so can we), so just continue & keep checking.
  2321. code = STATE_CONTINUE;
  2322. }
  2323. }
  2324. if (m_isInitialApproach)
  2325. {
  2326. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2327. if (tur != TURRET_INVALID)
  2328. {
  2329. Object *temporaryTarget = ai->getNextMoodTarget( true, false );
  2330. if (temporaryTarget)
  2331. {
  2332. ai->setTurretTargetObject(tur, temporaryTarget, m_isForceAttacking);
  2333. }
  2334. }
  2335. }
  2336. return code;
  2337. }
  2338. //----------------------------------------------------------------------------------------------------------
  2339. void AIAttackApproachTargetState::onExit( StateExitType status )
  2340. {
  2341. // contained by AIAttackState, so no separate timer
  2342. AIInternalMoveToState::onExit( status );
  2343. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2344. Object *obj = getMachineOwner();
  2345. if (ai) {
  2346. ai->ignoreObstacle(NULL);
  2347. // Per JohnA, this state should not be calling ai->destroyPath, because we can have spastic users
  2348. // that click the target repeadedly. This will prevent the unit from stuttering for said spastic
  2349. // users.
  2350. // ai->destroyPath();
  2351. // urg. hacky. if we are a projectile, reset precise z-pos.
  2352. if (getMachineOwner()->isKindOf(KINDOF_PROJECTILE))
  2353. {
  2354. if (ai && ai->getCurLocomotor())
  2355. ai->getCurLocomotor()->setUsePreciseZPos(false);
  2356. }
  2357. if (ai->isDoingGroundMovement()) {
  2358. Real dx = m_goalPosition.x-obj->getPosition()->x;
  2359. Real dy = m_goalPosition.y-obj->getPosition()->y;
  2360. if (dx*dx+dy*dy<PATHFIND_CELL_SIZE_F*PATHFIND_CELL_SIZE_F*0.125)
  2361. {
  2362. // We are doing accurate ground movement, so make sure we end exactly at the goal.
  2363. obj->setPosition(&m_goalPosition);
  2364. }
  2365. }
  2366. }
  2367. m_isInitialApproach = false; // We only want to allow turreted things to fire at enemies during their
  2368. // first approach
  2369. }
  2370. //----------------------------------------------------------------------------------------------------------
  2371. //----------------------------------------------------------------------------------------------------------
  2372. //----------------------------------------------------------------------------------------------------------
  2373. //----------------------------------------------------------------------------------------------------------
  2374. /**
  2375. * Compute a valid spot to fire our weapon from.
  2376. * Result in m_goalPosition.
  2377. * Return false if can't find a good spot.
  2378. */
  2379. Bool AIAttackPursueTargetState::computePath()
  2380. {
  2381. Bool forceRepath = false;
  2382. // if we're immobile we can't possibly approach the target
  2383. if( getMachineOwner()->isMobile() == false )
  2384. return false;
  2385. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2386. if (ai->isBlockedAndStuck())
  2387. {
  2388. return false;
  2389. }
  2390. if (m_waitingForPath) return true;
  2391. if (!forceRepath && ai->getPath()==NULL && !ai->isWaitingForPath())
  2392. {
  2393. forceRepath = true;
  2394. }
  2395. // force minimum time between recomputation
  2396. /// @todo Unify recomputation conditions & account for obj ID so everyone doesnt compute on the same frame (MSB)
  2397. if (!forceRepath && TheGameLogic->getFrame() - m_approachTimestamp < MIN_RECOMPUTE_TIME)
  2398. {
  2399. return true;
  2400. }
  2401. m_approachTimestamp = TheGameLogic->getFrame();
  2402. DEBUG_ASSERTLOG(getMachineGoalObject(), ("***************************Should only be pursuing objects. jba"));
  2403. // if we have a goal object, move to it, otherwise fail & continue to AIAttackApproachTargetState
  2404. if (getMachineGoalObject())
  2405. {
  2406. Object* source = getMachineOwner();
  2407. // if our victim's position hasn't changed, don't re-path
  2408. if (!forceRepath && isSamePosition(source->getPosition(), &m_prevVictimPos, getMachineGoalObject()->getPosition() ))
  2409. return true;
  2410. Weapon* weapon = source->getCurrentWeapon();
  2411. if (!weapon)
  2412. {
  2413. return false;
  2414. }
  2415. if (!canPursue(source, weapon, getMachineGoalObject())) {
  2416. return false;
  2417. }
  2418. // remember where we think our victim is, so if it moves, we can re-path
  2419. Object *victim = getMachineGoalObject();
  2420. m_prevVictimPos = *victim->getPosition();
  2421. setAdjustsDestination(true);
  2422. m_goalPosition = m_prevVictimPos;
  2423. m_waitingForPath = true;
  2424. ai->requestPath(&m_goalPosition, false);
  2425. m_stopIfInRange = false; // we have calculated a position to shoot from, so go there.
  2426. return true;
  2427. }
  2428. return false;
  2429. }
  2430. // ------------------------------------------------------------------------------------------------
  2431. /** CRC */
  2432. // ------------------------------------------------------------------------------------------------
  2433. void AIAttackPursueTargetState::crc( Xfer *xfer )
  2434. {
  2435. AIInternalMoveToState::crc(xfer);
  2436. } // end crc
  2437. // ------------------------------------------------------------------------------------------------
  2438. /** Xfer Method */
  2439. // ------------------------------------------------------------------------------------------------
  2440. void AIAttackPursueTargetState::xfer( Xfer *xfer )
  2441. {
  2442. // version
  2443. XferVersion currentVersion = 1;
  2444. XferVersion version = currentVersion;
  2445. xfer->xferVersion( &version, currentVersion );
  2446. // extend base class
  2447. AIInternalMoveToState::xfer( xfer );
  2448. xfer->xferCoord3D(&m_prevVictimPos);
  2449. xfer->xferUnsignedInt(&m_approachTimestamp);
  2450. xfer->xferBool(&m_follow);
  2451. xfer->xferBool(&m_isAttackingObject);
  2452. xfer->xferBool(&m_stopIfInRange);
  2453. xfer->xferBool(&m_isInitialApproach);
  2454. } // end xfer
  2455. // ------------------------------------------------------------------------------------------------
  2456. /** Load post process */
  2457. // ------------------------------------------------------------------------------------------------
  2458. void AIAttackPursueTargetState::loadPostProcess( void )
  2459. {
  2460. // extend base class
  2461. AIInternalMoveToState::loadPostProcess();
  2462. } // end loadPostProcess
  2463. //----------------------------------------------------------------------------------------------------------
  2464. StateReturnType AIAttackPursueTargetState::onEnter()
  2465. {
  2466. // contained by AIAttackState, so no separate timer
  2467. // If we return STATE_SUCCESS or STATE_FAILURE, we proceed to AIAttackApproachTargetState.
  2468. Object* source = getMachineOwner();
  2469. AIUpdateInterface* ai = source->getAI();
  2470. if (source->isKindOf(KINDOF_PROJECTILE))
  2471. {
  2472. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - is a projectile for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2473. return STATE_SUCCESS; // Projectiles go directly to AIAttackApproachTargetState.
  2474. }
  2475. if (getMachine()->isGoalObjectDestroyed())
  2476. {
  2477. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - goal object is destroyed for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2478. return STATE_SUCCESS; // Already killed victim.
  2479. }
  2480. if (!m_isAttackingObject) {
  2481. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - not attacking for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2482. return STATE_SUCCESS; // only pursue objects - positions don't move.
  2483. }
  2484. setAdjustsDestination(false);
  2485. // Check here: If we are a player, and we got to this state via an ai command (ie we auto-acquired),
  2486. // we don't want to chase the unit.
  2487. if (source->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN) {
  2488. if (ai->getLastCommandSource() == CMD_FROM_AI) {
  2489. return STATE_SUCCESS;
  2490. }
  2491. }
  2492. m_prevVictimPos.x = 0.0f;
  2493. m_prevVictimPos.y = 0.0f;
  2494. m_prevVictimPos.z = 0.0f;
  2495. m_approachTimestamp = -MIN_RECOMPUTE_TIME;
  2496. // See if we're close enough.
  2497. Object *victim = getMachineGoalObject();
  2498. if (victim) {
  2499. Weapon* weapon = source->getCurrentWeapon();
  2500. if (!weapon)
  2501. {
  2502. return STATE_FAILURE;
  2503. }
  2504. if (!canPursue(source, weapon, victim) )
  2505. {
  2506. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - can't pursue for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2507. return STATE_SUCCESS;
  2508. }
  2509. } else {
  2510. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - no victim for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2511. return STATE_SUCCESS; // gotta have a victim.
  2512. }
  2513. // If we have a turret, start aiming.
  2514. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2515. if (tur != TURRET_INVALID)
  2516. {
  2517. ai->setTurretTargetObject(tur, victim, m_isForceAttacking);
  2518. } else {
  2519. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onEnter() - no turret for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2520. return STATE_SUCCESS; // we only pursue with turrets, as non-turreted weapons can't fire on the run.
  2521. }
  2522. // find a good spot to shoot from
  2523. if (computePath() == false)
  2524. return STATE_SUCCESS;
  2525. return AIInternalMoveToState::onEnter();
  2526. }
  2527. //----------------------------------------------------------------------------------------------------------
  2528. StateReturnType AIAttackPursueTargetState::updateInternal()
  2529. {
  2530. AIUpdateInterface* ai = getMachineOwner()->getAI();
  2531. if (getMachine()->isGoalObjectDestroyed())
  2532. {
  2533. ai->notifyVictimIsDead();
  2534. ai->setCurrentVictim(NULL);
  2535. return STATE_FAILURE;
  2536. }
  2537. m_stopIfInRange = false;
  2538. Object* source = getMachineOwner();
  2539. StateReturnType code = STATE_FAILURE;
  2540. Object *victim = getMachineGoalObject();
  2541. if (victim)
  2542. {
  2543. if( victim->testStatus( OBJECT_STATUS_STEALTHED ) && !victim->testStatus( OBJECT_STATUS_DETECTED ) ){
  2544. return STATE_FAILURE; // If obj is stealthed, can no longer pursue.
  2545. }
  2546. ai->setCurrentVictim(victim);
  2547. // Attacking an object.
  2548. // find a good spot to shoot from
  2549. if (computePath() == false)
  2550. return STATE_FAILURE;
  2551. code = AIInternalMoveToState::update();
  2552. if (code != STATE_CONTINUE)
  2553. {
  2554. //CRCDEBUG_LOG(("AIAttackPursueTargetState::updateInternal() - failed internal update() for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2555. return STATE_SUCCESS; // Always return state success, as state failure exits the attack.
  2556. // we may need to aim & do another approach if the target moved. jba.
  2557. }
  2558. Weapon* weapon = source->getCurrentWeapon();
  2559. if (!weapon)
  2560. return STATE_FAILURE;
  2561. // If we have a turret, start aiming.
  2562. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2563. if (tur == TURRET_INVALID)
  2564. {
  2565. //CRCDEBUG_LOG(("AIAttackPursueTargetState::updateInternal() - no turret for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2566. return STATE_SUCCESS; // We currently only pursue with a turret weapon.
  2567. }
  2568. Bool viewBlocked = false;
  2569. if (ai->isDoingGroundMovement() && !victim->isSignificantlyAboveTerrain())
  2570. {
  2571. viewBlocked = TheAI->pathfinder()->isAttackViewBlockedByObstacle(source, *source->getPosition(), victim, *victim->getPosition());
  2572. }
  2573. if (!viewBlocked && victim->getPhysics() && weapon->isWithinAttackRange(source, victim)) {
  2574. // If we have a turret, start aiming.
  2575. ai->setTurretTargetObject(tur, victim, m_isForceAttacking);
  2576. // match speeds;
  2577. m_isInitialApproach = false;
  2578. Real victimSpeed = victim->getPhysics()->getForwardSpeed2D();
  2579. if (weapon->isGoalPosWithinAttackRange(source, source->getPosition(), victim, victim->getPosition())){
  2580. victimSpeed *= 0.95f;
  2581. }
  2582. if (source->canCrushOrSquish(victim)) {
  2583. victimSpeed = FAST_AS_POSSIBLE;
  2584. }
  2585. ai->setDesiredSpeed(victimSpeed);
  2586. // Really intense debug info. jba.
  2587. // DEBUG_LOG(("VS %f, OS %f, goal %f\n", victim->getPhysics()->getForwardSpeed2D(), source->getPhysics()->getForwardSpeed2D(), victimSpeed));
  2588. } else {
  2589. ai->setDesiredSpeed(FAST_AS_POSSIBLE);
  2590. }
  2591. }
  2592. return code;
  2593. }
  2594. //----------------------------------------------------------------------------------------------------------
  2595. StateReturnType AIAttackPursueTargetState::update()
  2596. {
  2597. // contained by AIAttackState, so no separate timer
  2598. StateReturnType code = updateInternal();
  2599. Object* source = getMachineOwner();
  2600. AIUpdateInterface *ai = source->getAI();
  2601. if (m_isInitialApproach)
  2602. {
  2603. WhichTurretType tur = ai->getWhichTurretForCurWeapon();
  2604. if (tur != TURRET_INVALID)
  2605. {
  2606. Object *temporaryTarget = ai->getNextMoodTarget( true, false );
  2607. if (temporaryTarget)
  2608. {
  2609. ai->setTurretTargetObject(tur, temporaryTarget, m_isForceAttacking);
  2610. }
  2611. }
  2612. }
  2613. return code;
  2614. }
  2615. //----------------------------------------------------------------------------------------------------------
  2616. void AIAttackPursueTargetState::onExit( StateExitType status )
  2617. {
  2618. // contained by AIAttackState, so no separate timer
  2619. //CRCDEBUG_LOG(("AIAttackPursueTargetState::onExit() for object %d (%s)\n", getMachineOwner()->getID(), getMachineOwner()->getTemplate()->getName().str()));
  2620. AIInternalMoveToState::onExit( status );
  2621. m_isInitialApproach = false; // We only want to allow turreted things to fire at enemies during their
  2622. // first approach
  2623. }
  2624. //----------------------------------------------------------------------------------------------------------
  2625. //----------------------------------------------------------------------------------------------------------
  2626. //----------------------------------------------------------------------------------------------------------
  2627. //----------------------------------------------------------------------------------------------------------
  2628. Bool AIPickUpCrateState::computePath()
  2629. {
  2630. return AIInternalMoveToState::computePath();
  2631. }
  2632. // ------------------------------------------------------------------------------------------------
  2633. /** CRC */
  2634. // ------------------------------------------------------------------------------------------------
  2635. void AIPickUpCrateState::crc( Xfer *xfer )
  2636. {
  2637. AIInternalMoveToState::crc(xfer);
  2638. } // end crc
  2639. // ------------------------------------------------------------------------------------------------
  2640. /** Xfer Method */
  2641. // ------------------------------------------------------------------------------------------------
  2642. void AIPickUpCrateState::xfer( Xfer *xfer )
  2643. {
  2644. // version
  2645. XferVersion currentVersion = 1;
  2646. XferVersion version = currentVersion;
  2647. xfer->xferVersion( &version, currentVersion );
  2648. // extend base class
  2649. AIInternalMoveToState::xfer( xfer );
  2650. xfer->xferInt(&m_delayCounter);
  2651. xfer->xferCoord3D(&m_goalPosition);
  2652. } // end xfer
  2653. // ------------------------------------------------------------------------------------------------
  2654. /** Load post process */
  2655. // ------------------------------------------------------------------------------------------------
  2656. void AIPickUpCrateState::loadPostProcess( void )
  2657. {
  2658. // extend base class
  2659. AIInternalMoveToState::loadPostProcess();
  2660. } // end loadPostProcess
  2661. //----------------------------------------------------------------------------------------------------------
  2662. StateReturnType AIPickUpCrateState::onEnter()
  2663. {
  2664. Object* goalObj = getMachineGoalObject();
  2665. if (!goalObj) {
  2666. return STATE_FAILURE;
  2667. }
  2668. setAdjustsDestination(true);
  2669. m_goalPosition = *goalObj->getPosition();
  2670. m_delayCounter = 3;
  2671. return STATE_CONTINUE;
  2672. }
  2673. //----------------------------------------------------------------------------------------------------------
  2674. void AIPickUpCrateState::onExit( StateExitType status )
  2675. {
  2676. AIInternalMoveToState::onExit( status );
  2677. }
  2678. //----------------------------------------------------------------------------------------------------------
  2679. StateReturnType AIPickUpCrateState::update()
  2680. {
  2681. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  2682. if (m_delayCounter) {
  2683. m_delayCounter--;
  2684. if (m_delayCounter == 0) {
  2685. return AIInternalMoveToState::onEnter();
  2686. }
  2687. return STATE_CONTINUE;
  2688. }
  2689. // do movement
  2690. StateReturnType status = AIInternalMoveToState::update();
  2691. return status;
  2692. }
  2693. //----------------------------------------------------------------------------------------------------------
  2694. //----------------------------------------------------------------------------------------------------------
  2695. //----------------------------------------------------------------------------------------------------------
  2696. // ------------------------------------------------------------------------------------------------
  2697. /** CRC */
  2698. // ------------------------------------------------------------------------------------------------
  2699. void AIFollowPathState::crc( Xfer *xfer )
  2700. {
  2701. AIInternalMoveToState::crc(xfer);
  2702. } // end crc
  2703. // ------------------------------------------------------------------------------------------------
  2704. /** Xfer Method */
  2705. // ------------------------------------------------------------------------------------------------
  2706. void AIFollowPathState::xfer( Xfer *xfer )
  2707. {
  2708. // version
  2709. XferVersion currentVersion = 1;
  2710. XferVersion version = currentVersion;
  2711. xfer->xferVersion( &version, currentVersion );
  2712. AIInternalMoveToState::xfer(xfer);
  2713. xfer->xferInt(&m_index);
  2714. xfer->xferBool(&m_adjustFinal);
  2715. xfer->xferBool(&m_adjustFinalOverride);
  2716. } // end xfer
  2717. // ------------------------------------------------------------------------------------------------
  2718. /** Load post process */
  2719. // ------------------------------------------------------------------------------------------------
  2720. void AIFollowPathState::loadPostProcess( void )
  2721. {
  2722. AIInternalMoveToState::loadPostProcess();
  2723. } // end loadPostProcess
  2724. //----------------------------------------------------------------------------------------------------------
  2725. StateReturnType AIFollowPathState::onEnter()
  2726. {
  2727. Object *obj = getMachineOwner();
  2728. AIUpdateInterface *ai = obj->getAI();
  2729. m_index = 0;
  2730. const Coord3D *pos = ai->friend_getGoalPathPosition( m_index );
  2731. if (pos == NULL)
  2732. return STATE_FAILURE;
  2733. // set initial movement goal
  2734. m_goalPosition = *pos;
  2735. const Coord3D *nextPos = ai->friend_getGoalPathPosition( m_index+1 );
  2736. m_adjustFinal = true;
  2737. //Assign this value to the AIUpdateInterface so object's can access this value while
  2738. //determine which waypoints to plot in the waypoint renderer.
  2739. ai->friend_setCurrentGoalPathIndex( m_index );
  2740. if (getID() == AI_FOLLOW_EXITPRODUCTION_PATH) {
  2741. ai->setCanPathThroughUnits(true);
  2742. setAdjustsDestination(false);
  2743. m_adjustFinal = true;
  2744. }
  2745. StateReturnType ret = AIInternalMoveToState::onEnter();
  2746. if (obj->getFormationID() != NO_FORMATION_ID) {
  2747. AIGroup *group = ai->getGroup();
  2748. if (group) {
  2749. Real speed = group->getSpeed();
  2750. ai->setDesiredSpeed(speed);
  2751. }
  2752. }
  2753. if (nextPos)
  2754. {
  2755. Coord2D delta;
  2756. delta.x = nextPos->x - pos->x;
  2757. delta.y = nextPos->y - pos->y;
  2758. Real offset = delta.length();
  2759. const Coord3D *followingPos = ai->friend_getGoalPathPosition( m_index+2 );
  2760. if (followingPos) offset += 4*PATHFIND_CELL_SIZE_F;
  2761. ai->setPathExtraDistance(offset);
  2762. // We are in the middle of a path, so don't set the final goal location yet.
  2763. setAdjustsDestination(false);
  2764. }
  2765. else
  2766. {
  2767. setAdjustsDestination(m_adjustFinal);
  2768. ai->setPathExtraDistance(0);
  2769. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  2770. if (obj->isKindOf(KINDOF_PROJECTILE))
  2771. {
  2772. if (ai && ai->getCurLocomotor())
  2773. ai->getCurLocomotor()->setUsePreciseZPos(true);
  2774. }
  2775. }
  2776. return ret;
  2777. }
  2778. //----------------------------------------------------------------------------------------------------------
  2779. void AIFollowPathState::onExit( StateExitType status )
  2780. {
  2781. AIInternalMoveToState::onExit( status );
  2782. // turn off precision-z-pos when we exit, just in case.
  2783. AIUpdateInterface *ai = getMachineOwner()->getAI();
  2784. if (!ai) return;
  2785. ai->setCanPathThroughUnits(false);
  2786. if (ai->getCurLocomotor())
  2787. ai->getCurLocomotor()->setUsePreciseZPos(false);
  2788. //Assign this value to the AIUpdateInterface so object's can access this value while
  2789. //determine which waypoints to plot in the waypoint renderer.
  2790. ai->friend_setCurrentGoalPathIndex( -1 );
  2791. }
  2792. //----------------------------------------------------------------------------------------------------------
  2793. StateReturnType AIFollowPathState::update()
  2794. {
  2795. getMachine()->setGoalPosition(&m_goalPosition);
  2796. // do movement
  2797. StateReturnType status = AIInternalMoveToState::update();
  2798. // if move to has finished, move to next point on path
  2799. if (status == STATE_SUCCESS || status == STATE_FAILURE)
  2800. {
  2801. Object *obj = getMachineOwner();
  2802. AIUpdateInterface *ai = obj->getAI();
  2803. if (status == STATE_FAILURE && m_retryCount>0) {
  2804. // If we failed, & haven't reached retry limit, try again. jba.
  2805. m_retryCount--;
  2806. } else {
  2807. ++m_index;
  2808. }
  2809. const Coord3D *pos = ai->friend_getGoalPathPosition( m_index );
  2810. Bool tooClose=true;
  2811. while (pos && tooClose) {
  2812. Real dx = pos->x - obj->getPosition()->x;
  2813. Real dy = pos->y - obj->getPosition()->y;
  2814. tooClose = false;
  2815. if (sqr(dx) + sqr(dy) < sqr(PATHFIND_CELL_SIZE_F)) {
  2816. tooClose = true;
  2817. }
  2818. if (tooClose) {
  2819. m_index++;
  2820. pos = ai->friend_getGoalPathPosition(m_index);
  2821. }
  2822. }
  2823. //Assign this value to the AIUpdateInterface so object's can access this value while
  2824. //determine which waypoints to plot in the waypoint renderer.
  2825. ai->friend_setCurrentGoalPathIndex( m_index );
  2826. ai->ignoreObstacleID(INVALID_ID); // we have exited whatever object we are leaving, if any. jba.
  2827. if (pos == NULL)
  2828. {
  2829. // reached the end of the path
  2830. return STATE_SUCCESS;
  2831. }
  2832. ai->friend_startingMove();
  2833. // set next movement goal
  2834. m_goalPosition = *pos;
  2835. const Coord3D *nextPos = ai->friend_getGoalPathPosition( m_index+1 );
  2836. if (nextPos)
  2837. {
  2838. Coord2D delta;
  2839. delta.x = nextPos->x - pos->x;
  2840. delta.y = nextPos->y - pos->y;
  2841. Real offset = delta.length();
  2842. const Coord3D *followingPos = ai->friend_getGoalPathPosition( m_index+2 );
  2843. if (followingPos) offset += 4*PATHFIND_CELL_SIZE_F;
  2844. ai->setPathExtraDistance(offset);
  2845. // We are in the middle of a path, so don't set the final goal location yet.
  2846. setAdjustsDestination(false);
  2847. }
  2848. else
  2849. {
  2850. setAdjustsDestination(m_adjustFinal && (m_adjustFinalOverride || ai->isDoingGroundMovement()));
  2851. if (getAdjustsDestination())
  2852. {
  2853. if (!TheAI->pathfinder()->adjustDestination(getMachineOwner(), ai->getLocomotorSet(), &m_goalPosition)) {
  2854. return STATE_FAILURE;
  2855. }
  2856. TheAI->pathfinder()->updateGoal(getMachineOwner(), &m_goalPosition, TheTerrainLogic->getLayerForDestination(&m_goalPosition));
  2857. }
  2858. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  2859. if (obj->isKindOf(KINDOF_PROJECTILE))
  2860. {
  2861. if (ai && ai->getCurLocomotor())
  2862. ai->getCurLocomotor()->setUsePreciseZPos(true);
  2863. }
  2864. }
  2865. computePath();
  2866. return STATE_CONTINUE;
  2867. }
  2868. return status;
  2869. }
  2870. //----------------------------------------------------------------------------------------------------------
  2871. //----------------------------------------------------------------------------------------------------------
  2872. //----------------------------------------------------------------------------------------------------------
  2873. // ------------------------------------------------------------------------------------------------
  2874. /** CRC */
  2875. // ------------------------------------------------------------------------------------------------
  2876. void AIMoveAndEvacuateState::crc( Xfer *xfer )
  2877. {
  2878. AIInternalMoveToState::crc(xfer);
  2879. } // end crc
  2880. // ------------------------------------------------------------------------------------------------
  2881. /** Xfer Method */
  2882. // ------------------------------------------------------------------------------------------------
  2883. void AIMoveAndEvacuateState::xfer( Xfer *xfer )
  2884. {
  2885. // version
  2886. XferVersion currentVersion = 1;
  2887. XferVersion version = currentVersion;
  2888. xfer->xferVersion( &version, currentVersion );
  2889. AIInternalMoveToState::xfer(xfer);
  2890. xfer->xferCoord3D(&m_origin);
  2891. } // end xfer
  2892. // ------------------------------------------------------------------------------------------------
  2893. /** Load post process */
  2894. // ------------------------------------------------------------------------------------------------
  2895. void AIMoveAndEvacuateState::loadPostProcess( void )
  2896. {
  2897. AIInternalMoveToState::loadPostProcess();
  2898. } // end loadPostProcess
  2899. //----------------------------------------------------------------------------------------------------------
  2900. StateReturnType AIMoveAndEvacuateState::onEnter()
  2901. {
  2902. Object *obj = getMachineOwner();
  2903. getMachine()->lock("AIMoveAndEvacuateState::onEnter"); // This state is not user interruptable.
  2904. m_origin = *obj->getPosition();
  2905. setAdjustsDestination(true);
  2906. // if we have a goal object, move to it, otherwise move to goal position
  2907. if (getMachine()->getGoalObject())
  2908. m_goalPosition = *getMachine()->getGoalObject()->getPosition();
  2909. else
  2910. m_goalPosition = *getMachine()->getGoalPosition();
  2911. return AIInternalMoveToState::onEnter();
  2912. }
  2913. //----------------------------------------------------------------------------------------------------------
  2914. StateReturnType AIMoveAndEvacuateState::update()
  2915. {
  2916. Object *obj = getMachine()->getOwner();
  2917. if (obj->isEffectivelyDead())
  2918. {
  2919. return STATE_FAILURE;
  2920. }
  2921. // do movement
  2922. StateReturnType status = AIInternalMoveToState::update();
  2923. if (status != STATE_CONTINUE)
  2924. {
  2925. Object *obj = getMachineOwner();
  2926. if (obj->isEffectivelyDead())
  2927. {
  2928. return STATE_FAILURE;
  2929. }
  2930. AIUpdateInterface *ai = obj->getAI();
  2931. ai->aiEvacuate(FALSE, CMD_FROM_AI);
  2932. obj->getTeam()->setActive();
  2933. }
  2934. return status;
  2935. }
  2936. //----------------------------------------------------------------------------------------------------------
  2937. void AIMoveAndEvacuateState::onExit( StateExitType status )
  2938. {
  2939. getMachine()->unlock();
  2940. getMachine()->setGoalPosition(&m_origin); // In case we follow with a AIMoveAndDeleteState.
  2941. AIInternalMoveToState::onExit( status );
  2942. }
  2943. //----------------------------------------------------------------------------------------------------------
  2944. //----------------------------------------------------------------------------------------------------------
  2945. //----------------------------------------------------------------------------------------------------------
  2946. //-------------------------------------------------------------------------------------------------
  2947. AIAttackMoveToState::AIAttackMoveToState( StateMachine *machine ) : AIMoveToState(machine)
  2948. {
  2949. #ifdef STATE_MACHINE_DEBUG
  2950. setName("AIAttackMoveToState");
  2951. #endif // set up the state
  2952. m_isMoveTo = false;
  2953. m_frameToSleepUntil = 0;
  2954. m_retryCount = ATTACK_RETRY_COUNT;
  2955. m_attackMoveMachine = newInstance(AIAttackMoveStateMachine)(getMachineOwner(), "AIAttackMoveMachine");
  2956. m_attackMoveMachine->initDefaultState();
  2957. }
  2958. //----------------------------------------------------------------------------------------------------------
  2959. AIAttackMoveToState::~AIAttackMoveToState()
  2960. {
  2961. m_attackMoveMachine->deleteInstance();
  2962. }
  2963. // ------------------------------------------------------------------------------------------------
  2964. /** CRC */
  2965. // ------------------------------------------------------------------------------------------------
  2966. void AIAttackMoveToState::crc( Xfer *xfer )
  2967. {
  2968. } // end crc
  2969. // ------------------------------------------------------------------------------------------------
  2970. /** Xfer Method */
  2971. // ------------------------------------------------------------------------------------------------
  2972. void AIAttackMoveToState::xfer( Xfer *xfer )
  2973. {
  2974. // version
  2975. XferVersion currentVersion = 2;
  2976. XferVersion version = currentVersion;
  2977. xfer->xferVersion( &version, currentVersion );
  2978. // extend base class
  2979. AIMoveToState::xfer( xfer );
  2980. if (version>=2) {
  2981. xfer->xferUnsignedInt(&m_frameToSleepUntil);
  2982. xfer->xferInt(&m_retryCount);
  2983. }
  2984. xfer->xferSnapshot(m_attackMoveMachine);
  2985. } // end xfer
  2986. // ------------------------------------------------------------------------------------------------
  2987. /** Load post process */
  2988. // ------------------------------------------------------------------------------------------------
  2989. void AIAttackMoveToState::loadPostProcess( void )
  2990. {
  2991. } // end loadPostProcess
  2992. #ifdef STATE_MACHINE_DEBUG
  2993. //----------------------------------------------------------------------------------------------------------
  2994. AsciiString AIAttackMoveToState::getName( ) const
  2995. {
  2996. AsciiString name = m_name;
  2997. name.concat("/");
  2998. if (m_attackMoveMachine) name.concat(m_attackMoveMachine->getCurrentStateName());
  2999. else name.concat("*NULL m_deployMachine");
  3000. return name;
  3001. }
  3002. #endif
  3003. //----------------------------------------------------------------------------------------------------------
  3004. StateReturnType AIAttackMoveToState::onEnter()
  3005. {
  3006. Object *owner = getMachineOwner();
  3007. AIUpdateInterface *ai = owner->getAI();
  3008. m_attackMoveMachine->clear();
  3009. m_attackMoveMachine->setState( AI_IDLE );
  3010. m_commandSrc = ai->getLastCommandSource();
  3011. m_retryCount = ATTACK_RETRY_COUNT;
  3012. m_frameToSleepUntil = 0;
  3013. return AIMoveToState::onEnter();
  3014. }
  3015. //----------------------------------------------------------------------------------------------------------
  3016. void AIAttackMoveToState::onExit( StateExitType status )
  3017. {
  3018. m_attackMoveMachine->setState(AI_IDLE);
  3019. AIMoveToState::onExit(status);
  3020. }
  3021. //----------------------------------------------------------------------------------------------------------
  3022. StateReturnType AIAttackMoveToState::update()
  3023. {
  3024. Object *owner = getMachineOwner();
  3025. AIUpdateInterface *ai = owner->getAI();
  3026. Bool forceRetargetThisFrame = false;
  3027. Bool shouldRepathThisFrame = false;
  3028. if (!m_attackMoveMachine->isInIdleState())
  3029. {
  3030. ai->setLocomotorGoalNone();
  3031. owner->clearModelConditionState(MODELCONDITION_MOVING);
  3032. m_attackMoveMachine->updateStateMachine();
  3033. // if the machine is now idling, then we need to attempt to get a new target
  3034. if (m_attackMoveMachine->isInIdleState()) {
  3035. forceRetargetThisFrame = true;
  3036. shouldRepathThisFrame = true;
  3037. ai->friend_setLastCommandSource(m_commandSrc);
  3038. } else {
  3039. return STATE_CONTINUE;
  3040. }
  3041. }
  3042. if (m_attackMoveMachine->isInIdleState())
  3043. {
  3044. // Check to see if we have created a crate we need to pick up.
  3045. Object* crate = ai->checkForCrateToPickup();
  3046. if (crate)
  3047. {
  3048. m_attackMoveMachine->setGoalObject(crate);
  3049. m_attackMoveMachine->setState( AI_PICK_UP_CRATE );
  3050. return STATE_CONTINUE;
  3051. }
  3052. Object* nextObjectToAttack;
  3053. nextObjectToAttack = ai->getNextMoodTarget( !forceRetargetThisFrame, false );
  3054. if (nextObjectToAttack != NULL)
  3055. {
  3056. ai->friend_endingMove();
  3057. m_attackMoveMachine->setGoalObject(nextObjectToAttack);
  3058. m_attackMoveMachine->setState( AI_ATTACK_OBJECT );
  3059. shouldRepathThisFrame = false; // we're about to drop out of this function, but this is semantic emphasis.
  3060. // Note that we picked up this command from the ai.
  3061. ai->friend_setLastCommandSource(CMD_FROM_AI);
  3062. // we don't want an update to take place 'till next frame.
  3063. return STATE_CONTINUE;
  3064. }
  3065. }
  3066. if (m_frameToSleepUntil>TheGameLogic->getFrame()) {
  3067. return STATE_CONTINUE;
  3068. } else if (m_frameToSleepUntil == TheGameLogic->getFrame()) {
  3069. shouldRepathThisFrame = true;
  3070. }
  3071. if (shouldRepathThisFrame)
  3072. {
  3073. AIMoveToState::onEnter();
  3074. forceRepath();
  3075. }
  3076. StateReturnType ret = AIMoveToState::update();
  3077. if (ret != STATE_CONTINUE) {
  3078. if (m_retryCount<1) return ret;
  3079. /* check for close enough. */
  3080. Real distSqr = sqr(owner->getPosition()->x - m_pathGoalPosition.x) + sqr(owner->getPosition()->y-m_pathGoalPosition.y);
  3081. if (distSqr < sqr(ATTACK_CLOSE_ENOUGH_CELLS*PATHFIND_CELL_SIZE_F)) {
  3082. return ret;
  3083. }
  3084. DEBUG_LOG(("AIAttackMoveToState::update Distance from goal %f, retrying.\n", sqrt(distSqr)));
  3085. ret = STATE_CONTINUE;
  3086. m_retryCount--;
  3087. // Sleep 3 seconds. We can attack during these frames, just not move.
  3088. m_frameToSleepUntil = TheGameLogic->getFrame() + 3*LOGICFRAMES_PER_SECOND;
  3089. }
  3090. return ret;
  3091. }
  3092. //----------------------------------------------------------------------------------------------------------
  3093. //----------------------------------------------------------------------------------------------------------
  3094. //----------------------------------------------------------------------------------------------------------
  3095. // ------------------------------------------------------------------------------------------------
  3096. /** CRC */
  3097. // ------------------------------------------------------------------------------------------------
  3098. void AIMoveAndDeleteState::crc( Xfer *xfer )
  3099. {
  3100. AIInternalMoveToState::crc(xfer);
  3101. } // end crc
  3102. // ------------------------------------------------------------------------------------------------
  3103. /** Xfer Method */
  3104. // ------------------------------------------------------------------------------------------------
  3105. void AIMoveAndDeleteState::xfer( Xfer *xfer )
  3106. {
  3107. // version
  3108. XferVersion currentVersion = 1;
  3109. XferVersion version = currentVersion;
  3110. xfer->xferVersion( &version, currentVersion );
  3111. AIInternalMoveToState::xfer(xfer);
  3112. xfer->xferBool(&m_appendGoalPosition);
  3113. } // end xfer
  3114. // ------------------------------------------------------------------------------------------------
  3115. /** Load post process */
  3116. // ------------------------------------------------------------------------------------------------
  3117. void AIMoveAndDeleteState::loadPostProcess( void )
  3118. {
  3119. AIInternalMoveToState::loadPostProcess();
  3120. } // end loadPostProcess
  3121. //----------------------------------------------------------------------------------------------------------
  3122. StateReturnType AIMoveAndDeleteState::onEnter()
  3123. {
  3124. setAdjustsDestination(false);
  3125. getMachine()->lock("AIMoveAndDeleteState::onEnter");
  3126. // if we have a goal object, move to it, otherwise move to goal position
  3127. if (getMachine()->getGoalObject())
  3128. m_goalPosition = *getMachine()->getGoalObject()->getPosition();
  3129. else
  3130. m_goalPosition = *getMachine()->getGoalPosition();
  3131. m_appendGoalPosition = true; // We may be moving off the map.
  3132. return AIInternalMoveToState::onEnter();
  3133. }
  3134. //----------------------------------------------------------------------------------------------------------
  3135. StateReturnType AIMoveAndDeleteState::update()
  3136. {
  3137. Object *obj = getMachine()->getOwner();
  3138. if (obj->isEffectivelyDead())
  3139. {
  3140. return STATE_FAILURE;
  3141. }
  3142. // do movement
  3143. AIUpdateInterface *ai = obj->getAI();
  3144. if (ai->getCurLocomotor())
  3145. {
  3146. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  3147. }
  3148. if (m_appendGoalPosition)
  3149. {
  3150. Path *thePath = ai->getPath();
  3151. if (!ai->isWaitingForPath() && ai->getPath())
  3152. {
  3153. m_goalPosition.z = TheTerrainLogic->getGroundHeight(m_goalPosition.x, m_goalPosition.y);
  3154. thePath->appendNode( &m_goalPosition, LAYER_GROUND);
  3155. m_appendGoalPosition = false; // just did it.
  3156. }
  3157. }
  3158. StateReturnType status = AIInternalMoveToState::update();
  3159. if (status != STATE_CONTINUE)
  3160. {
  3161. Object *obj = getMachineOwner();
  3162. TheGameLogic->destroyObject(obj);
  3163. }
  3164. return status;
  3165. }
  3166. //----------------------------------------------------------------------------------------------------------
  3167. void AIMoveAndDeleteState::onExit( StateExitType status )
  3168. {
  3169. getMachine()->unlock();
  3170. AIInternalMoveToState::onExit( status );
  3171. }
  3172. //----------------------------------------------------------------------------------------------------------
  3173. //----------------------------------------------------------------------------------------------------------
  3174. //----------------------------------------------------------------------------------------------------------
  3175. //----------------------------------------------------------------------------------------------------------
  3176. #define ALLOW_BACKTRACK
  3177. //----------------------------------------------------------------------------------------------------------
  3178. const Waypoint * AIFollowWaypointPathState::getNextWaypoint(void)
  3179. {
  3180. #ifdef ALLOW_BACKTRACK
  3181. Int linkCount = m_currentWaypoint->getNumLinks();
  3182. Int which = GameLogicRandomValue( 0, linkCount-1 );
  3183. const Waypoint *nextWay = m_currentWaypoint->getLink( which );
  3184. m_priorWaypoint = m_currentWaypoint;
  3185. getMachine()->setGoalPosition(m_currentWaypoint->getLocation());// THANKS, JOHN
  3186. return nextWay;
  3187. #else
  3188. if (!hasNextWaypoint()) {
  3189. m_priorWaypoint = m_currentWaypoint;
  3190. return NULL;
  3191. }
  3192. Int skip = -1;
  3193. Int i;
  3194. Int linkCount = m_currentWaypoint->getNumLinks();
  3195. for (i=0; i<linkCount; i++) {
  3196. if (m_priorWaypoint == m_currentWaypoint->getLink(i)) {
  3197. skip = i;
  3198. break;
  3199. }
  3200. }
  3201. Int which = 0;
  3202. if (skip >= 0) {
  3203. which = GameLogicRandomValue( 0, linkCount-2 );
  3204. if (which == skip) which = linkCount-1;
  3205. } else {
  3206. // pick a random link
  3207. which = GameLogicRandomValue( 0, linkCount-1 );
  3208. }
  3209. const Waypoint *nextWay = m_currentWaypoint->getLink( which );
  3210. m_priorWaypoint = m_currentWaypoint;
  3211. return nextWay;
  3212. #endif
  3213. }
  3214. //----------------------------------------------------------------------------------------------------------
  3215. Bool AIFollowWaypointPathState::hasNextWaypoint(void)
  3216. {
  3217. #ifdef ALLOW_BACKTRACK
  3218. return m_currentWaypoint->getNumLinks()>0;
  3219. #else
  3220. if (m_currentWaypoint->getNumLinks()==0) {
  3221. return false; // no links, no next.
  3222. }
  3223. if (m_priorWaypoint==NULL) {
  3224. return m_currentWaypoint->getNumLinks()>0;
  3225. }
  3226. if (m_currentWaypoint->getNumLinks()>1) {
  3227. // Two links, always works.
  3228. return true;
  3229. }
  3230. // We have a prior waypoint, and 1 link.
  3231. if (m_priorWaypoint == m_currentWaypoint->getLink(0)) {
  3232. return false; // don't go back to same waypoint.
  3233. }
  3234. return true;
  3235. #endif
  3236. }
  3237. //----------------------------------------------------------------------------------------------------------
  3238. Real AIFollowWaypointPathState::calcExtraPathDistance(void)
  3239. {
  3240. Real extra = PATHFIND_CELL_SIZE_F/10.0f;
  3241. const Waypoint *curWay = m_currentWaypoint;
  3242. Int limit = 5; // just look ahead 5, in case of circular paths. jba
  3243. while (curWay && limit>0) {
  3244. limit--;
  3245. Int linkCount = curWay->getNumLinks();
  3246. if (linkCount == 0) return extra;
  3247. Int which = 0;
  3248. const Waypoint *nextWay = curWay->getLink( which );
  3249. Coord2D delta;
  3250. delta.x = nextWay->getLocation()->x - curWay->getLocation()->x;
  3251. delta.y = nextWay->getLocation()->y - curWay->getLocation()->y;
  3252. extra += delta.length();
  3253. curWay = nextWay;
  3254. }
  3255. return extra;
  3256. }
  3257. //----------------------------------------------------------------------------------------------------------
  3258. void AIFollowWaypointPathState::computeGoal(Bool useGroupOffsets)
  3259. {
  3260. if (m_currentWaypoint == NULL)
  3261. return;
  3262. Object *obj = getMachineOwner();
  3263. AIUpdateInterface *ai = obj->getAI();
  3264. Coord3D dest = *m_currentWaypoint->getLocation();
  3265. m_goalLayer = LAYER_GROUND; // waypoints are always on the ground.
  3266. if (TheAI->pathfinder()->isPointOnWall(&dest)) {
  3267. // except when they're on the wall. jba.
  3268. dest.z = TheAI->pathfinder()->getWallHeight();
  3269. m_goalLayer = LAYER_WALL;
  3270. }
  3271. ai->setPathExtraDistance(calcExtraPathDistance());
  3272. if (hasNextWaypoint()) {
  3273. // We are in the middle of a path, so don't set the final goal location yet.
  3274. setAdjustsDestination(false);
  3275. } else {
  3276. setAdjustsDestination(true);
  3277. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  3278. if (obj->isKindOf(KINDOF_PROJECTILE))
  3279. {
  3280. if (ai && ai->getCurLocomotor())
  3281. ai->getCurLocomotor()->setUsePreciseZPos(true);
  3282. }
  3283. }
  3284. #define NO_ROTATE_OFFSETS
  3285. #ifdef ROTATE_OFFSETS
  3286. Real dx = (dest.x) - (obj->getPosition()->x - m_groupOffset.x);
  3287. Real dy = (dest.y) - (obj->getPosition()->y - m_groupOffset.y);
  3288. Real angle;
  3289. if (m_priorWaypoint) {
  3290. dx = dest.x - m_priorWaypoint->getLocation()->x;
  3291. dy = dest.y - m_priorWaypoint->getLocation()->y;
  3292. angle = atan2(dy, dx);
  3293. Real deltaAngle = angle - m_angle;
  3294. Real s = sin(deltaAngle);
  3295. Real c = cos(deltaAngle);
  3296. Real x = m_groupOffset.x * c - m_groupOffset.y * s;
  3297. Real y = m_groupOffset.y * c + m_groupOffset.x * s;
  3298. m_groupOffset.x = x;
  3299. m_groupOffset.y = y;
  3300. } else {
  3301. angle = atan2(dy, dx);
  3302. }
  3303. m_angle = angle;
  3304. #endif
  3305. m_goalPosition = dest;
  3306. m_goalPosition.x += m_groupOffset.x;
  3307. m_goalPosition.y += m_groupOffset.y;
  3308. if (m_goalLayer == LAYER_WALL) {
  3309. if (!TheAI->pathfinder()->isPointOnWall(&m_goalPosition)) {
  3310. m_goalPosition = dest;
  3311. }
  3312. } else {
  3313. m_goalPosition.z = TheTerrainLogic->getGroundHeight(m_goalPosition.x, m_goalPosition.y);
  3314. }
  3315. Region3D extent;
  3316. TheTerrainLogic->getMaximumPathfindExtent(&extent);
  3317. if (!extent.isInRegionNoZ(&m_goalPosition)) {
  3318. setAdjustsDestination(false); // moving off the map.
  3319. ai->getCurLocomotor()->setAllowInvalidPosition(true); // allow it to move off the map.
  3320. m_appendGoalPosition = true; // Moving off the map.
  3321. }
  3322. }
  3323. // ------------------------------------------------------------------------------------------------
  3324. /** CRC */
  3325. // ------------------------------------------------------------------------------------------------
  3326. void AIFollowWaypointPathState::crc( Xfer *xfer )
  3327. {
  3328. AIInternalMoveToState::crc(xfer);
  3329. } // end crc
  3330. // ------------------------------------------------------------------------------------------------
  3331. /** Xfer Method */
  3332. // ------------------------------------------------------------------------------------------------
  3333. void AIFollowWaypointPathState::xfer( Xfer *xfer )
  3334. {
  3335. // version
  3336. XferVersion currentVersion = 1;
  3337. XferVersion version = currentVersion;
  3338. xfer->xferVersion( &version, currentVersion );
  3339. AIInternalMoveToState::xfer(xfer);
  3340. xfer->xferCoord2D(&m_groupOffset);
  3341. xfer->xferReal(&m_angle);
  3342. xfer->xferInt(&m_framesSleeping);
  3343. UnsignedInt id = INVALID_WAYPOINT_ID;
  3344. if (m_currentWaypoint) {
  3345. id = m_currentWaypoint->getID();
  3346. }
  3347. xfer->xferUnsignedInt(&id);
  3348. if (xfer->getXferMode() == XFER_LOAD)
  3349. {
  3350. m_currentWaypoint = TheTerrainLogic->getWaypointByID(id);
  3351. }
  3352. id = INVALID_WAYPOINT_ID;
  3353. if (m_priorWaypoint) {
  3354. id = m_priorWaypoint->getID();
  3355. }
  3356. xfer->xferUnsignedInt(&id);
  3357. if (xfer->getXferMode() == XFER_LOAD)
  3358. {
  3359. m_priorWaypoint = TheTerrainLogic->getWaypointByID(id);
  3360. }
  3361. xfer->xferBool(&m_appendGoalPosition);
  3362. } // end xfer
  3363. // ------------------------------------------------------------------------------------------------
  3364. /** Load post process */
  3365. // ------------------------------------------------------------------------------------------------
  3366. void AIFollowWaypointPathState::loadPostProcess( void )
  3367. {
  3368. AIInternalMoveToState::loadPostProcess();
  3369. } // end loadPostProcess
  3370. //----------------------------------------------------------------------------------------------------------
  3371. StateReturnType AIFollowWaypointPathState::onEnter()
  3372. {
  3373. m_appendGoalPosition = false; // not moving off the map at this point.
  3374. m_priorWaypoint = NULL;
  3375. m_currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  3376. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3377. if (m_currentWaypoint == NULL && !m_moveAsGroup) return STATE_FAILURE;
  3378. getMachine()->setGoalPosition(m_currentWaypoint->getLocation());
  3379. m_framesSleeping = 0;
  3380. m_groupOffset.x = m_groupOffset.y = 0;
  3381. Object *obj = getMachineOwner();
  3382. /* Interesting thought experiment. Didn't work well. jba
  3383. Real distSqrLimit = 9*obj->getGeometryInfo().getMajorRadius()*obj->getGeometryInfo().getMajorRadius();
  3384. const Waypoint *way = m_currentWaypoint;
  3385. Bool doPrecise = false;
  3386. while (way) {
  3387. if (way->getNext()) {
  3388. Real dx = way->getLocation()->x - way->getNext()->getLocation()->x;
  3389. Real dy = way->getLocation()->y - way->getNext()->getLocation()->y;
  3390. Real distSqr = dx*dx + dy*dy;
  3391. if (distSqr < distSqrLimit) {
  3392. doPrecise = true;
  3393. }
  3394. }
  3395. way = way->getNext();
  3396. }
  3397. if (doPrecise && ai->getCurLocomotor()) {
  3398. //ai->getCurLocomotor()->setUltraAccurate(true);
  3399. }
  3400. */
  3401. Real speed = FAST_AS_POSSIBLE;
  3402. if (m_moveAsGroup && m_currentWaypoint) {
  3403. obj->getTeam()->setCurrentWaypoint(m_currentWaypoint);
  3404. AIGroup *group = ai->getGroup();
  3405. if (group) {
  3406. speed = group->getSpeed();
  3407. Coord3D center;
  3408. group->getCenter( &center );
  3409. m_groupOffset.x = obj->getPosition()->x - center.x;
  3410. m_groupOffset.y = obj->getPosition()->y - center.y;
  3411. }
  3412. }
  3413. if (m_currentWaypoint==NULL && m_moveAsGroup) {
  3414. m_currentWaypoint = obj->getTeam()->getCurrentWaypoint();
  3415. }
  3416. // set initial movement goal
  3417. computeGoal(m_moveAsGroup);
  3418. StateReturnType ret = AIInternalMoveToState::onEnter();
  3419. ai->setDesiredSpeed(speed);
  3420. // Update the extra path distance. AIInternalMoveToState::onEnter resets it.
  3421. ai->setPathExtraDistance(calcExtraPathDistance());
  3422. if (hasNextWaypoint()) {
  3423. // We are in the middle of a path, so don't set the final goal location yet.
  3424. setAdjustsDestination(false);
  3425. } else {
  3426. setAdjustsDestination(ai->isDoingGroundMovement());
  3427. if (getAdjustsDestination()) {
  3428. if (!TheAI->pathfinder()->adjustDestination(getMachineOwner(), ai->getLocomotorSet(), &m_goalPosition)) {
  3429. DEBUG_LOG(("Breaking out of follow waypoint path\n"));
  3430. return STATE_FAILURE;
  3431. }
  3432. TheAI->pathfinder()->updateGoal(getMachineOwner(), &m_goalPosition, m_goalLayer);
  3433. }
  3434. // urg. hacky. if we are a projectile on the last segment, turn on precise z-pos.
  3435. if (obj->isKindOf(KINDOF_PROJECTILE))
  3436. {
  3437. if (ai && ai->getCurLocomotor())
  3438. ai->getCurLocomotor()->setUsePreciseZPos(true);
  3439. }
  3440. }
  3441. if (ret != STATE_CONTINUE) {
  3442. DEBUG_LOG(("Breaking out of follow waypoint path\n"));
  3443. }
  3444. return ret;
  3445. }
  3446. //----------------------------------------------------------------------------------------------------------
  3447. void AIFollowWaypointPathState::onExit( StateExitType status )
  3448. {
  3449. AIInternalMoveToState::onExit( status );
  3450. // turn off precision-z-pos when we exit, just in case.
  3451. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3452. if (ai && ai->getCurLocomotor()) {
  3453. ai->getCurLocomotor()->setUsePreciseZPos(false);
  3454. ai->getCurLocomotor()->setUltraAccurate(false);
  3455. }
  3456. }
  3457. //----------------------------------------------------------------------------------------------------------
  3458. StateReturnType AIFollowWaypointPathState::update()
  3459. {
  3460. if (m_framesSleeping>0) {
  3461. m_framesSleeping--;
  3462. return STATE_CONTINUE;
  3463. }
  3464. Object *obj = getMachineOwner();
  3465. AIUpdateInterface *ai = obj->getAI();
  3466. getMachine()->setGoalPosition(m_currentWaypoint->getLocation());
  3467. UnsignedInt adjustment = ai->getMoodMatrixActionAdjustment(MM_Action_Move);
  3468. if (m_isFollowWaypointPathState && (adjustment & MAA_Action_To_AttackMove)) {
  3469. if (m_moveAsGroup) {
  3470. ai->aiAttackFollowWaypointPathAsTeam(m_currentWaypoint, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  3471. } else {
  3472. ai->aiAttackFollowWaypointPath(m_currentWaypoint, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI);
  3473. }
  3474. }
  3475. if (m_appendGoalPosition) {
  3476. Path *thePath = ai->getPath();
  3477. if (!ai->isWaitingForPath() && ai->getPath()) {
  3478. //Coord3D pathEnd = *thePath->getLastNode()->getPosition();
  3479. thePath->appendNode(&m_goalPosition, LAYER_GROUND); // waypoints are always on the ground.
  3480. m_appendGoalPosition = false; // just did it.
  3481. }
  3482. }
  3483. if (m_moveAsGroup && m_currentWaypoint != obj->getTeam()->getCurrentWaypoint()) {
  3484. m_priorWaypoint = m_currentWaypoint;
  3485. m_currentWaypoint = obj->getTeam()->getCurrentWaypoint();
  3486. if (m_currentWaypoint == NULL) {
  3487. return STATE_SUCCESS;
  3488. }
  3489. computeGoal(false);
  3490. if (getAdjustsDestination() && ai->isDoingGroundMovement()) {
  3491. if (!TheAI->pathfinder()->adjustDestination(obj, ai->getLocomotorSet(), &m_goalPosition)) {
  3492. if (m_currentWaypoint) {
  3493. DEBUG_LOG(("Breaking out of follow waypoint path %s of %s\n",
  3494. m_currentWaypoint->getName().str(), m_currentWaypoint->getPathLabel1().str()));
  3495. }
  3496. return STATE_FAILURE;
  3497. }
  3498. }
  3499. ai->friend_startingMove();
  3500. computePath();
  3501. if (getAdjustsDestination()) {
  3502. TheAI->pathfinder()->updateGoal(obj, &m_goalPosition, m_goalLayer);
  3503. }
  3504. }
  3505. // do movement
  3506. StateReturnType status = AIInternalMoveToState::update();
  3507. // We may want to allow ourselves to bail out of this one early. In order to do this, we check and
  3508. // see if we're moving as a group, and then if our team is owned by an AI Skirmish player.
  3509. // If it is, then we compute the group centroid, and see if it is within some distance of the
  3510. if (m_moveAsGroup) {
  3511. if (obj->getControllingPlayer()->isSkirmishAIPlayer()) {
  3512. Team *team = obj->getTeam();
  3513. AIGroup *group = TheAI->createGroup();
  3514. team->getTeamAsAIGroup(group);
  3515. Coord3D pos;
  3516. group->getCenter(&pos);
  3517. pos.x -= m_goalPosition.x;
  3518. pos.y -= m_goalPosition.y;
  3519. pos.z = 0;
  3520. Int numInGroup = group->getCount();
  3521. if (pos.length() <= (numInGroup * TheAI->getAiData()->m_skirmishGroupFudgeValue)) {
  3522. // Consider ourselves close enough.
  3523. status = STATE_SUCCESS;
  3524. }
  3525. }
  3526. }
  3527. // if move to has finished, move to next point on waypoint path
  3528. if (status != STATE_CONTINUE)
  3529. {
  3530. m_currentWaypoint = getNextWaypoint();
  3531. //LORENZEN ADDED LORENZEN ADDED LORENZEN ADDED
  3532. Object *obj = getMachineOwner();
  3533. AIUpdateInterface *ai = obj->getAI();
  3534. if ( m_priorWaypoint )
  3535. ai->setPriorWaypointID( m_priorWaypoint->getID() );
  3536. if ( m_currentWaypoint )
  3537. ai->setCurrentWaypointID( m_currentWaypoint->getID() );
  3538. //LORENZEN ADDED LORENZEN ADDED LORENZEN ADDED
  3539. // if there are no links from this waypoint, we're done
  3540. if (m_currentWaypoint==NULL) {
  3541. /// Trigger "end of waypoint path" scripts (jba)
  3542. ai->setCompletedWaypoint(m_priorWaypoint);
  3543. return STATE_SUCCESS;
  3544. }
  3545. if (m_moveAsGroup) {
  3546. obj->getTeam()->setCurrentWaypoint(m_currentWaypoint);
  3547. }
  3548. computeGoal(false);
  3549. if (getAdjustsDestination() && ai->isDoingGroundMovement()) {
  3550. if (!TheAI->pathfinder()->adjustDestination(obj, ai->getLocomotorSet(), &m_goalPosition)) {
  3551. if (m_currentWaypoint) {
  3552. DEBUG_LOG(("Breaking out of follow waypoint path %s of %s\n",
  3553. m_currentWaypoint->getName().str(), m_currentWaypoint->getPathLabel1().str()));
  3554. }
  3555. return STATE_FAILURE;
  3556. }
  3557. }
  3558. ai->friend_startingMove();
  3559. computePath();
  3560. if (getAdjustsDestination()) {
  3561. TheAI->pathfinder()->updateGoal(obj, &m_goalPosition, m_goalLayer);
  3562. }
  3563. return STATE_CONTINUE;
  3564. }
  3565. if (status != STATE_CONTINUE) {
  3566. DEBUG_LOG(("Breaking out of follow waypoint path\n"));
  3567. }
  3568. return status;
  3569. }
  3570. //----------------------------------------------------------------------------------------------------------
  3571. //----------------------------------------------------------------------------------------------------------
  3572. //----------------------------------------------------------------------------------------------------------
  3573. //----------------------------------------------------------------------------------------------------------
  3574. // ------------------------------------------------------------------------------------------------
  3575. /** CRC */
  3576. // ------------------------------------------------------------------------------------------------
  3577. void AIFollowWaypointPathExactState::crc( Xfer *xfer )
  3578. {
  3579. AIInternalMoveToState::crc(xfer);
  3580. } // end crc
  3581. // ------------------------------------------------------------------------------------------------
  3582. /** Xfer Method */
  3583. // ------------------------------------------------------------------------------------------------
  3584. void AIFollowWaypointPathExactState::xfer( Xfer *xfer )
  3585. {
  3586. // version
  3587. XferVersion currentVersion = 1;
  3588. XferVersion version = currentVersion;
  3589. xfer->xferVersion( &version, currentVersion );
  3590. AIInternalMoveToState::xfer(xfer);
  3591. UnsignedInt id = INVALID_WAYPOINT_ID;
  3592. if (m_lastWaypoint) {
  3593. id = m_lastWaypoint->getID();
  3594. }
  3595. xfer->xferUnsignedInt(&id);
  3596. if (xfer->getXferMode() == XFER_LOAD)
  3597. {
  3598. m_lastWaypoint = TheTerrainLogic->getWaypointByID(id);
  3599. }
  3600. } // end xfer
  3601. // ------------------------------------------------------------------------------------------------
  3602. /** Load post process */
  3603. // ------------------------------------------------------------------------------------------------
  3604. void AIFollowWaypointPathExactState::loadPostProcess( void )
  3605. {
  3606. AIInternalMoveToState::loadPostProcess();
  3607. } // end loadPostProcess
  3608. //----------------------------------------------------------------------------------------------------------
  3609. StateReturnType AIFollowWaypointPathExactState::onEnter()
  3610. {
  3611. const Waypoint *currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  3612. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3613. if (currentWaypoint == NULL) return STATE_FAILURE;
  3614. getMachine()->setGoalPosition(currentWaypoint->getLocation());
  3615. Coord2D groupOffset;
  3616. groupOffset.x = groupOffset.y = 0;
  3617. Object *obj = getMachineOwner();
  3618. Real speed = FAST_AS_POSSIBLE;
  3619. if (m_moveAsGroup) {
  3620. AIGroup *group = ai->getGroup();
  3621. if (group) {
  3622. speed = group->getSpeed();
  3623. Coord3D center;
  3624. group->getCenter( &center );
  3625. groupOffset.x = obj->getPosition()->x - center.x;
  3626. groupOffset.y = obj->getPosition()->y - center.y;
  3627. }
  3628. }
  3629. ai->setCanPathThroughUnits(true);
  3630. setAdjustsDestination(false);
  3631. // set initial movement goal
  3632. StateReturnType ret = AIInternalMoveToState::onEnter();
  3633. ai->setPathFromWaypoint(currentWaypoint, &groupOffset);
  3634. m_lastWaypoint = currentWaypoint;
  3635. ai->getCurLocomotor()->setAllowInvalidPosition(true); // allow it to move off the map.
  3636. //Kris: October 4, 2002 -- Commented out by guidance of John A.
  3637. // Artist couldn't load his map, and turned out that it was because
  3638. // there was a waypoint path that pointed to itself (2 point path).
  3639. // John said that this code only needs "a" point, not the "last" point.
  3640. //while (m_lastWaypoint && m_lastWaypoint->getLink(0)) {
  3641. // m_lastWaypoint = m_lastWaypoint->getLink(0);
  3642. //}
  3643. ai->setDesiredSpeed(speed);
  3644. return ret;
  3645. }
  3646. //----------------------------------------------------------------------------------------------------------
  3647. void AIFollowWaypointPathExactState::onExit( StateExitType status )
  3648. {
  3649. AIInternalMoveToState::onExit( status );
  3650. // turn off precision-z-pos when we exit, just in case.
  3651. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3652. if (ai) {
  3653. ai->setCompletedWaypoint(m_lastWaypoint);
  3654. ai->setCanPathThroughUnits(false);
  3655. ai->getCurLocomotor()->setAllowInvalidPosition(false); // turn off allow it to move off the map.
  3656. }
  3657. }
  3658. //----------------------------------------------------------------------------------------------------------
  3659. StateReturnType AIFollowWaypointPathExactState::update()
  3660. {
  3661. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3662. if (ai) ai->setCanPathThroughUnits(true);
  3663. // do movement
  3664. StateReturnType status = AIInternalMoveToState::update();
  3665. return status;
  3666. }
  3667. //-------------------------------------------------------------------------------------------------
  3668. //-------------------------------------------------------------------------------------------------
  3669. //-------------------------------------------------------------------------------------------------
  3670. //-------------------------------------------------------------------------------------------------
  3671. //-------------------------------------------------------------------------------------------------
  3672. //-------------------------------------------------------------------------------------------------
  3673. AIAttackFollowWaypointPathState::AIAttackFollowWaypointPathState ( StateMachine *machine, Bool asGroup ) :
  3674. AIFollowWaypointPathState ( machine, asGroup, false )
  3675. {
  3676. #ifdef STATE_MACHINE_DEBUG
  3677. setName("AIAttackFollowWaypointPathState");
  3678. #endif
  3679. m_attackFollowMachine = newInstance(AIAttackMoveStateMachine)(getMachineOwner(), "AIAttackFollowMachine");
  3680. m_attackFollowMachine->initDefaultState();
  3681. }
  3682. //-------------------------------------------------------------------------------------------------
  3683. AIAttackFollowWaypointPathState::~AIAttackFollowWaypointPathState()
  3684. {
  3685. m_attackFollowMachine->deleteInstance();
  3686. }
  3687. // ------------------------------------------------------------------------------------------------
  3688. /** CRC */
  3689. // ------------------------------------------------------------------------------------------------
  3690. void AIAttackFollowWaypointPathState::crc( Xfer *xfer )
  3691. {
  3692. } // end crc
  3693. // ------------------------------------------------------------------------------------------------
  3694. /** Xfer Method */
  3695. // ------------------------------------------------------------------------------------------------
  3696. void AIAttackFollowWaypointPathState::xfer( Xfer *xfer )
  3697. {
  3698. // version
  3699. XferVersion currentVersion = 1;
  3700. XferVersion version = currentVersion;
  3701. xfer->xferVersion( &version, currentVersion );
  3702. // extend base class
  3703. AIFollowWaypointPathState::xfer( xfer );
  3704. xfer->xferSnapshot(m_attackFollowMachine);
  3705. } // end xfer
  3706. // ------------------------------------------------------------------------------------------------
  3707. /** Load post process */
  3708. // ------------------------------------------------------------------------------------------------
  3709. void AIAttackFollowWaypointPathState::loadPostProcess( void )
  3710. {
  3711. } // end loadPostProcess
  3712. #ifdef STATE_MACHINE_DEBUG
  3713. //----------------------------------------------------------------------------------------------------------
  3714. AsciiString AIAttackFollowWaypointPathState::getName( ) const
  3715. {
  3716. AsciiString name = m_name;
  3717. name.concat("/");
  3718. if (m_attackFollowMachine) name.concat(m_attackFollowMachine->getCurrentStateName());
  3719. else name.concat("*NULL m_attackFollowMachine");
  3720. return name;
  3721. }
  3722. #endif
  3723. //-------------------------------------------------------------------------------------------------
  3724. StateReturnType AIAttackFollowWaypointPathState ::onEnter()
  3725. {
  3726. m_attackFollowMachine->clear();
  3727. m_attackFollowMachine->setState( AI_IDLE );
  3728. return AIFollowWaypointPathState::onEnter();
  3729. }
  3730. //-------------------------------------------------------------------------------------------------
  3731. StateReturnType AIAttackFollowWaypointPathState::update()
  3732. {
  3733. Object *owner = getMachineOwner();
  3734. AIUpdateInterface *ai = owner->getAI();
  3735. Bool forceRetargetThisFrame = false;
  3736. Bool shouldRepathThisFrame = false;
  3737. if (!m_attackFollowMachine->isInIdleState())
  3738. {
  3739. ai->setLocomotorGoalNone();
  3740. owner->clearModelConditionState(MODELCONDITION_MOVING);
  3741. m_attackFollowMachine->updateStateMachine();
  3742. // if the machine is now idling, then we need to attempt to get a new target
  3743. if (m_attackFollowMachine->isInIdleState())
  3744. {
  3745. forceRetargetThisFrame = true;
  3746. shouldRepathThisFrame = true;
  3747. }
  3748. else
  3749. {
  3750. return STATE_CONTINUE;
  3751. }
  3752. }
  3753. if (m_attackFollowMachine->isInIdleState())
  3754. {
  3755. // Check to see if we have created a crate we need to pick up.
  3756. Object* crate = ai->checkForCrateToPickup();
  3757. if (crate)
  3758. {
  3759. m_attackFollowMachine->setGoalObject(crate);
  3760. m_attackFollowMachine->setState( AI_PICK_UP_CRATE );
  3761. return STATE_CONTINUE;
  3762. }
  3763. Object* nextObjectToAttack;
  3764. {
  3765. nextObjectToAttack = ai->getNextMoodTarget( !forceRetargetThisFrame, false );
  3766. }
  3767. if (nextObjectToAttack != NULL)
  3768. {
  3769. m_attackFollowMachine->setGoalObject(nextObjectToAttack);
  3770. m_attackFollowMachine->setState( AI_ATTACK_OBJECT );
  3771. shouldRepathThisFrame = false; // we're about to drop out of this function, but this is semantic emphasis.
  3772. // we don't want an update to take place 'till next frame.
  3773. return STATE_CONTINUE;
  3774. }
  3775. }
  3776. if (shouldRepathThisFrame)
  3777. {
  3778. // Update the goal waypoint if we've moved along the path.
  3779. computeGoal(m_moveAsGroup);
  3780. computePath();
  3781. }
  3782. return AIFollowWaypointPathState::update();
  3783. }
  3784. //-------------------------------------------------------------------------------------------------
  3785. void AIAttackFollowWaypointPathState ::onExit( StateExitType status )
  3786. {
  3787. m_attackFollowMachine->setState(AI_IDLE);
  3788. AIFollowWaypointPathState::onExit(status);
  3789. }
  3790. //----------------------------------------------------------------------------------------------------------
  3791. //----------------------------------------------------------------------------------------------------------
  3792. //----------------------------------------------------------------------------------------------------------
  3793. //----------------------------------------------------------------------------------------------------------
  3794. //----------------------------------------------------------------------------------------------------------
  3795. /**
  3796. * Wander along a waypoint path.
  3797. */
  3798. // ------------------------------------------------------------------------------------------------
  3799. /** CRC */
  3800. // ------------------------------------------------------------------------------------------------
  3801. void AIWanderState::crc( Xfer *xfer )
  3802. {
  3803. AIFollowWaypointPathState::crc(xfer);
  3804. } // end crc
  3805. // ------------------------------------------------------------------------------------------------
  3806. /** Xfer Method */
  3807. // ------------------------------------------------------------------------------------------------
  3808. void AIWanderState::xfer( Xfer *xfer )
  3809. {
  3810. // version
  3811. XferVersion currentVersion = 1;
  3812. XferVersion version = currentVersion;
  3813. xfer->xferVersion( &version, currentVersion );
  3814. AIFollowWaypointPathState::xfer(xfer);
  3815. xfer->xferInt(&m_waitFrames);
  3816. xfer->xferInt(&m_timer);
  3817. } // end xfer
  3818. // ------------------------------------------------------------------------------------------------
  3819. /** Load post process */
  3820. // ------------------------------------------------------------------------------------------------
  3821. void AIWanderState::loadPostProcess( void )
  3822. {
  3823. AIFollowWaypointPathState::loadPostProcess();
  3824. } // end loadPostProcess
  3825. // ------------------------------------------------------------------------------------------------
  3826. // ------------------------------------------------------------------------------------------------
  3827. StateReturnType AIWanderState::onEnter()
  3828. {
  3829. m_currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  3830. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3831. m_priorWaypoint = NULL;
  3832. if (m_currentWaypoint == NULL || ai==NULL)
  3833. return STATE_FAILURE;
  3834. m_groupOffset.x = m_groupOffset.y = 0;
  3835. Locomotor* curLoco = ai->getCurLocomotor();
  3836. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  3837. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  3838. if (delta<1) delta = 1;
  3839. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3840. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3841. }
  3842. m_timer = 0;
  3843. m_waitFrames = 10 + (getMachineOwner()->getID() & 0x7);
  3844. // set initial movement goal
  3845. computeGoal(false);
  3846. StateReturnType ret = AIInternalMoveToState::onEnter();
  3847. ai->setPathExtraDistance(calcExtraPathDistance());
  3848. return ret;
  3849. }
  3850. //----------------------------------------------------------------------------------------------------------
  3851. StateReturnType AIWanderState::update()
  3852. {
  3853. // do movement
  3854. Object *obj = getMachineOwner();
  3855. StateReturnType status = AIInternalMoveToState::update();
  3856. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED)) {
  3857. m_timer--;
  3858. if (m_timer<0) {
  3859. m_timer = m_waitFrames;
  3860. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  3861. if (enemy) {
  3862. return STATE_FAILURE;
  3863. }
  3864. }
  3865. }
  3866. // if move to has finished, move to next point on waypoint path
  3867. if (status != STATE_CONTINUE)
  3868. {
  3869. AIUpdateInterface *ai = obj->getAI();
  3870. m_currentWaypoint = getNextWaypoint();
  3871. // if there are no links from this waypoint, we're done
  3872. if (m_currentWaypoint == NULL) {
  3873. /// Trigger "end of waypoint path" scripts (jba)
  3874. ai->setCompletedWaypoint(m_priorWaypoint);
  3875. return STATE_SUCCESS;
  3876. }
  3877. Locomotor* curLoco = ai->getCurLocomotor();
  3878. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  3879. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  3880. if (delta<1) delta = 1;
  3881. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3882. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3883. }
  3884. computeGoal(false);
  3885. computePath();
  3886. return STATE_CONTINUE;
  3887. }
  3888. // Never leave this state until told to.
  3889. return STATE_CONTINUE;
  3890. }
  3891. //----------------------------------------------------------------------------------------------------------
  3892. void AIWanderState::onExit( StateExitType status )
  3893. {
  3894. AIFollowWaypointPathState::onExit( status );
  3895. }
  3896. //----------------------------------------------------------------------------------------------------------
  3897. //----------------------------------------------------------------------------------------------------------
  3898. //----------------------------------------------------------------------------------------------------------
  3899. //----------------------------------------------------------------------------------------------------------
  3900. //----------------------------------------------------------------------------------------------------------
  3901. /**
  3902. * Wander around a point.
  3903. */
  3904. // ------------------------------------------------------------------------------------------------
  3905. /** CRC */
  3906. // ------------------------------------------------------------------------------------------------
  3907. void AIWanderInPlaceState::crc( Xfer *xfer )
  3908. {
  3909. AIInternalMoveToState::crc(xfer);
  3910. } // end crc
  3911. // ------------------------------------------------------------------------------------------------
  3912. /** Xfer Method */
  3913. // ------------------------------------------------------------------------------------------------
  3914. void AIWanderInPlaceState::xfer( Xfer *xfer )
  3915. {
  3916. // version
  3917. XferVersion currentVersion = 1;
  3918. XferVersion version = currentVersion;
  3919. xfer->xferVersion( &version, currentVersion );
  3920. AIInternalMoveToState::xfer(xfer);
  3921. xfer->xferCoord3D(&m_origin);
  3922. xfer->xferInt(&m_waitFrames);
  3923. xfer->xferInt(&m_timer);
  3924. } // end xfer
  3925. // ------------------------------------------------------------------------------------------------
  3926. /** LoadPostProcess */
  3927. // ------------------------------------------------------------------------------------------------
  3928. void AIWanderInPlaceState::loadPostProcess( void )
  3929. {
  3930. AIInternalMoveToState::loadPostProcess();
  3931. } // end loadPostProcess
  3932. // ------------------------------------------------------------------------------------------------
  3933. StateReturnType AIWanderInPlaceState::onEnter()
  3934. {
  3935. m_origin = *getMachineOwner()->getPosition();
  3936. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3937. if (ai) {
  3938. ai->chooseLocomotorSet(LOCOMOTORSET_WANDER);
  3939. }
  3940. Int delta = 3;
  3941. if (ai->getCurLocomotor()) {
  3942. delta = REAL_TO_INT_FLOOR( (ai->getCurLocomotor()->getWanderAboutPointRadius()/PATHFIND_CELL_SIZE_F) + 0.5f);
  3943. }
  3944. Coord3D offset;
  3945. offset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3946. offset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3947. m_goalPosition = m_origin;
  3948. m_goalPosition.x += offset.x;
  3949. m_goalPosition.y += offset.y;
  3950. m_timer = 0;
  3951. m_waitFrames = 10 + (getMachineOwner()->getID() & 0x7);
  3952. StateReturnType ret = AIInternalMoveToState::onEnter();
  3953. return ret;
  3954. }
  3955. //----------------------------------------------------------------------------------------------------------
  3956. StateReturnType AIWanderInPlaceState::update()
  3957. {
  3958. // do movement
  3959. StateReturnType status = AIInternalMoveToState::update();
  3960. Object *obj = getMachineOwner();
  3961. AIUpdateInterface *ai = getMachineOwner()->getAI();
  3962. if (!ai) return STATE_FAILURE;
  3963. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED)) {
  3964. m_timer--;
  3965. if (m_timer<0) {
  3966. m_timer = m_waitFrames;
  3967. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  3968. if (enemy) {
  3969. return STATE_FAILURE;
  3970. }
  3971. }
  3972. }
  3973. // if move to has finished, move to next point on waypoint path
  3974. if (status != STATE_CONTINUE)
  3975. {
  3976. Int delta = 3;
  3977. if (ai->getCurLocomotor()) {
  3978. delta = REAL_TO_INT_FLOOR( (ai->getCurLocomotor()->getWanderAboutPointRadius()/PATHFIND_CELL_SIZE_F) + 0.5f);
  3979. }
  3980. Coord3D offset;
  3981. offset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3982. offset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  3983. m_goalPosition = m_origin;
  3984. m_goalPosition.x += offset.x;
  3985. m_goalPosition.y += offset.y;
  3986. AIInternalMoveToState::onEnter();
  3987. return STATE_CONTINUE;
  3988. }
  3989. // Never leave this state until told to.
  3990. return STATE_CONTINUE;
  3991. }
  3992. //----------------------------------------------------------------------------------------------------------
  3993. void AIWanderInPlaceState::onExit( StateExitType status )
  3994. {
  3995. AIInternalMoveToState::onExit( status );
  3996. }
  3997. //----------------------------------------------------------------------------------------------------------
  3998. //----------------------------------------------------------------------------------------------------------
  3999. //----------------------------------------------------------------------------------------------------------
  4000. //----------------------------------------------------------------------------------------------------------
  4001. // ------------------------------------------------------------------------------------------------
  4002. /** CRC */
  4003. // ------------------------------------------------------------------------------------------------
  4004. void AIPanicState::crc( Xfer *xfer )
  4005. {
  4006. AIFollowWaypointPathState::crc(xfer);
  4007. } // end crc
  4008. // ------------------------------------------------------------------------------------------------
  4009. /** Xfer Method */
  4010. // ------------------------------------------------------------------------------------------------
  4011. void AIPanicState::xfer( Xfer *xfer )
  4012. {
  4013. // version
  4014. XferVersion currentVersion = 1;
  4015. XferVersion version = currentVersion;
  4016. xfer->xferVersion( &version, currentVersion );
  4017. AIFollowWaypointPathState::xfer(xfer);
  4018. xfer->xferInt(&m_waitFrames);
  4019. xfer->xferInt(&m_timer);
  4020. } // end xfer
  4021. // ------------------------------------------------------------------------------------------------
  4022. /** Load post process */
  4023. // ------------------------------------------------------------------------------------------------
  4024. void AIPanicState::loadPostProcess( void )
  4025. {
  4026. AIFollowWaypointPathState::loadPostProcess();
  4027. } // end loadPostProcess
  4028. /**
  4029. * Panic and run screaming along a waypoint path.
  4030. */
  4031. StateReturnType AIPanicState::onEnter()
  4032. {
  4033. m_currentWaypoint = ((AIStateMachine *)getMachine())->getGoalWaypoint();
  4034. Object *obj = getMachineOwner();
  4035. AIUpdateInterface *ai = obj->getAI();
  4036. if (m_currentWaypoint == NULL)
  4037. return STATE_FAILURE;
  4038. // set initial movement goal
  4039. Locomotor* curLoco = ai->getCurLocomotor();
  4040. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  4041. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  4042. if (delta<1) delta = 1;
  4043. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4044. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4045. }
  4046. computeGoal(false);
  4047. StateReturnType ret = AIInternalMoveToState::onEnter();
  4048. m_timer = 0;
  4049. m_waitFrames = 10 + (getMachineOwner()->getID() & 0x7);
  4050. // Update the extra path distance. AIInternalMoveToState::onEnter resets it.
  4051. ai->setPathExtraDistance(calcExtraPathDistance());
  4052. if (obj)
  4053. {
  4054. obj->setModelConditionState(MODELCONDITION_PANICKING);
  4055. }
  4056. return ret;
  4057. }
  4058. //----------------------------------------------------------------------------------------------------------
  4059. StateReturnType AIPanicState::update()
  4060. {
  4061. // do movement
  4062. StateReturnType status = AIInternalMoveToState::update();
  4063. Object *obj = getMachineOwner();
  4064. if (obj->isKindOf(KINDOF_CAN_BE_REPULSED)) {
  4065. m_timer--;
  4066. if (m_timer<0) {
  4067. m_timer = m_waitFrames;
  4068. Object* enemy = TheAI->findClosestRepulsor(getMachineOwner(), obj->getVisionRange());
  4069. if (enemy) {
  4070. return STATE_FAILURE;
  4071. }
  4072. }
  4073. }
  4074. // if move to has finished, move to next point on waypoint path
  4075. if (status == STATE_SUCCESS)
  4076. {
  4077. Object *obj = getMachineOwner();
  4078. AIUpdateInterface *ai = obj->getAI();
  4079. m_currentWaypoint = getNextWaypoint();
  4080. // if there are no links from this waypoint, we're done
  4081. if (m_currentWaypoint == NULL) {
  4082. /// Trigger "end of waypoint path" scripts (jba)
  4083. ai->setCompletedWaypoint(m_priorWaypoint);
  4084. return STATE_SUCCESS;
  4085. }
  4086. Locomotor* curLoco = ai->getCurLocomotor();
  4087. if (curLoco && curLoco->getWanderWidthFactor() > 0.0f) {
  4088. Int delta = REAL_TO_INT_FLOOR(curLoco->getWanderWidthFactor()+0.5f);
  4089. if (delta<1) delta = 1;
  4090. m_groupOffset.x = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4091. m_groupOffset.y = GameLogicRandomValue(-delta, delta)*PATHFIND_CELL_SIZE_F;
  4092. }
  4093. computeGoal(false);
  4094. computePath();
  4095. return STATE_CONTINUE;
  4096. }
  4097. // Never leave this state until told to.
  4098. return STATE_CONTINUE;
  4099. }
  4100. //----------------------------------------------------------------------------------------------------------
  4101. void AIPanicState::onExit( StateExitType status )
  4102. {
  4103. Object *obj = getMachineOwner();
  4104. obj->clearModelConditionState(MODELCONDITION_PANICKING);
  4105. AIInternalMoveToState::onExit( status );
  4106. }
  4107. //----------------------------------------------------------------------------------------------------------
  4108. //----------------------------------------------------------------------------------------------------------
  4109. //----------------------------------------------------------------------------------------------------------
  4110. // ------------------------------------------------------------------------------------------------
  4111. /** CRC */
  4112. // ------------------------------------------------------------------------------------------------
  4113. void AIAttackAimAtTargetState::crc( Xfer *xfer )
  4114. {
  4115. } // end crc
  4116. // ------------------------------------------------------------------------------------------------
  4117. /** Xfer Method */
  4118. // ------------------------------------------------------------------------------------------------
  4119. void AIAttackAimAtTargetState::xfer( Xfer *xfer )
  4120. {
  4121. // version
  4122. XferVersion currentVersion = 1;
  4123. XferVersion version = currentVersion;
  4124. xfer->xferVersion( &version, currentVersion );
  4125. xfer->xferBool(&m_canTurnInPlace);
  4126. xfer->xferBool(&m_setLocomotor);
  4127. } // end xfer
  4128. // ------------------------------------------------------------------------------------------------
  4129. /** Load post process */
  4130. // ------------------------------------------------------------------------------------------------
  4131. void AIAttackAimAtTargetState::loadPostProcess( void )
  4132. {
  4133. } // end loadPostProcess
  4134. //----------------------------------------------------------------------------------------------------------
  4135. StateReturnType AIAttackAimAtTargetState::onEnter()
  4136. {
  4137. // contained by AIAttackState, so no separate timer
  4138. Object* source = getMachineOwner();
  4139. Weapon* weapon = source->getCurrentWeapon();
  4140. Object* victim = getMachineGoalObject();
  4141. const Coord3D* targetPos = getMachineGoalPosition();
  4142. AIUpdateInterface* sourceAI = source->getAI();
  4143. AIUpdateInterface* victimAI = victim ? victim->getAI() : NULL;
  4144. Locomotor* curLoco = sourceAI->getCurLocomotor();
  4145. m_canTurnInPlace = curLoco ? curLoco->getMinSpeed() == 0.0f : false;
  4146. // if (!victim)
  4147. // return STATE_CONTINUE; // Just continue till we get a victim.
  4148. // Ick. This was originally a safety to a single line that required victim, and was never meant
  4149. // as an early return to all cases. We now want to use preattack frames on ground position targets
  4150. Bool inFiringRange = FALSE;
  4151. //If the object is garrisoning a building, then we want to force the object
  4152. //to move to the best fire point, check if it's in firing range, and if not
  4153. //move it back so another unit with longer range can!
  4154. Object *containedBy = source->getContainedBy();
  4155. if( containedBy && weapon )
  4156. {
  4157. ContainModuleInterface *contain = containedBy->getContain();
  4158. if (victim)
  4159. {
  4160. inFiringRange = contain->attemptBestFirePointPosition( source, weapon, victim );
  4161. }
  4162. else
  4163. {
  4164. inFiringRange = contain->attemptBestFirePointPosition( source, weapon, targetPos );
  4165. }
  4166. }
  4167. else if( victim && weapon )
  4168. inFiringRange = weapon->isWithinAttackRange( source, victim );
  4169. else if( weapon )
  4170. inFiringRange = weapon->isWithinAttackRange( source, targetPos );//See, I can be attacking the ground. Perfectly valid.
  4171. else
  4172. return STATE_FAILURE; // can't happen.
  4173. // add ourself as a targeter BEFORE calling isTemporarilyPreventingAimSuccess().
  4174. if (victimAI)
  4175. victimAI->addTargeter(source->getID(), true);
  4176. WhichTurretType tur = sourceAI->getWhichTurretForCurWeapon();
  4177. if (tur != TURRET_INVALID)
  4178. {
  4179. if (m_isAttackingObject)
  4180. {
  4181. sourceAI->setTurretTargetObject(tur, victim, m_isForceAttacking);
  4182. }
  4183. else
  4184. {
  4185. sourceAI->setTurretTargetPosition(tur, getMachineGoalPosition());
  4186. }
  4187. }
  4188. else
  4189. {
  4190. // GS moved contact weapon check in here, because Success can never be given to a unit in this state
  4191. // using a turret to attack. Check out ::update and you will see.
  4192. Bool preventing = victimAI && victimAI->isTemporarilyPreventingAimSuccess();
  4193. // Contact weapons don't aim. They just go boom. jba.
  4194. if( weapon && weapon->isContactWeapon() && inFiringRange && !preventing )
  4195. return STATE_SUCCESS;
  4196. }
  4197. m_setLocomotor = false;
  4198. source->setStatus( OBJECT_STATUS_IS_AIMING_WEAPON, true );
  4199. return STATE_CONTINUE;
  4200. }
  4201. //----------------------------------------------------------------------------------------------------------
  4202. /**
  4203. * Orient the machine's owner to face towards the given target
  4204. */
  4205. StateReturnType AIAttackAimAtTargetState::update()
  4206. {
  4207. // contained by AIAttackState, so no separate timer
  4208. Object* source = getMachineOwner();
  4209. AIUpdateInterface* sourceAI = source->getAI();
  4210. if (!source->hasAnyWeapon())
  4211. return STATE_FAILURE;
  4212. Object* victim = getMachineGoalObject();
  4213. if (m_isAttackingObject)
  4214. {
  4215. if (!victim || victim->isEffectivelyDead())
  4216. return STATE_FAILURE; // can't aim at dead things
  4217. }
  4218. WhichTurretType tur = sourceAI->getWhichTurretForCurWeapon();
  4219. if (tur != TURRET_INVALID)
  4220. {
  4221. if (m_isAttackingObject)
  4222. {
  4223. sourceAI->setTurretTargetObject(tur, victim, m_isForceAttacking);
  4224. }
  4225. else
  4226. {
  4227. sourceAI->setTurretTargetPosition(tur, getMachineGoalPosition());
  4228. }
  4229. // if we have a turret, but it is incapable of turning, turn ourself.
  4230. // (gotta do this for units like the Comanche, which have fake "turrets"
  4231. // solely to allow for attacking-on-the-move...)
  4232. if (sourceAI->getTurretTurnRate(tur) != 0.0f)
  4233. {
  4234. // The Body can never return Success if the weapon is on the turret, or else we end
  4235. // up shooting the current weapon (which is on the turret) in the wrong direction.
  4236. // We always say Continue, so the Turret can do its own Aiming state.
  4237. // if (m_isAttackingObject && source->canCrushOrSquish(victim)) {
  4238. // return STATE_SUCCESS;
  4239. // }
  4240. return STATE_CONTINUE;
  4241. }
  4242. // else fall thru!
  4243. }
  4244. // no else here!
  4245. {
  4246. Real relAngle = m_isAttackingObject ?
  4247. ThePartitionManager->getRelativeAngle2D( source, victim ) :
  4248. ThePartitionManager->getRelativeAngle2D( source, getMachineGoalPosition() );
  4249. const Real REL_THRESH = 0.035f; // about 2 degrees. (getRelativeAngle2D is current only accurate to about 1.25 degrees)
  4250. Weapon* weapon = source->getCurrentWeapon();
  4251. Real aimDelta = weapon ? weapon->getAimDelta() : 0.0f;
  4252. if (aimDelta < REL_THRESH) aimDelta = REL_THRESH;
  4253. //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));
  4254. if (m_canTurnInPlace)
  4255. {
  4256. if (fabs(relAngle) > aimDelta)
  4257. {
  4258. Real desiredAngle = source->getOrientation() + relAngle;
  4259. sourceAI->setLocomotorGoalOrientation(desiredAngle);
  4260. m_setLocomotor = true;
  4261. }
  4262. }
  4263. else
  4264. {
  4265. sourceAI->setLocomotorGoalPositionExplicit(m_isAttackingObject ? *victim->getPosition() : *getMachineGoalPosition());
  4266. }
  4267. if (fabs(relAngle) < aimDelta /*&& !m_preAttackFrames*/ )
  4268. {
  4269. AIUpdateInterface* victimAI = victim ? victim->getAI() : NULL;
  4270. // add ourself as a targeter BEFORE calling isTemporarilyPreventingAimSuccess().
  4271. // we do this every time thru, just in case we get into a squabble with our turret-ai
  4272. // over whether or not we are a targeter... (srj)
  4273. if (victimAI)
  4274. victimAI->addTargeter(source->getID(), true);
  4275. Bool preventing = victimAI && victimAI->isTemporarilyPreventingAimSuccess();
  4276. if (preventing)
  4277. {
  4278. return STATE_CONTINUE;
  4279. }
  4280. else
  4281. {
  4282. return STATE_SUCCESS;
  4283. }
  4284. }
  4285. }
  4286. if (source->isDisabledByType(DISABLED_HELD))
  4287. {
  4288. // We are contained by something (transport, building). This means we can't
  4289. // actually move to the location and if we are firing on a specific target
  4290. // and that target is no longer in range, then we need to abort the state
  4291. // so it can fire on other targets.
  4292. // Are we still in range?
  4293. Weapon *weapon = source->getCurrentWeapon();
  4294. const Coord3D *pos = m_isAttackingObject ? victim->getPosition() : getMachineGoalPosition();
  4295. if( !weapon || !weapon->isWithinAttackRange( source, pos ) )
  4296. {
  4297. // We're no longer in range, so exit with failure so we can automatically
  4298. // reacquire a closer target if possible.
  4299. return STATE_FAILURE;
  4300. }
  4301. }
  4302. return STATE_CONTINUE;
  4303. }
  4304. //----------------------------------------------------------------------------------------------------------
  4305. void AIAttackAimAtTargetState::onExit( StateExitType status )
  4306. {
  4307. // contained by AIAttackState, so no separate timer
  4308. if (m_canTurnInPlace)
  4309. {
  4310. AIUpdateInterface* sourceAI = getMachineOwner()->getAI();
  4311. // Tell the ai we are done moving, if we set the locomotor goal.
  4312. if (sourceAI && m_setLocomotor)
  4313. sourceAI->setLocomotorGoalNone();
  4314. }
  4315. else
  4316. {
  4317. // don't do the loco call, or else we will "wiggle"... we already have an appropriate goal
  4318. }
  4319. getMachineOwner()->setStatus( OBJECT_STATUS_IS_AIMING_WEAPON, false );
  4320. //getMachineOwner()->clearModelConditionState( MODELCONDITION_PREATTACK );
  4321. }
  4322. //----------------------------------------------------------------------------------------------------------
  4323. //----------------------------------------------------------------------------------------------------------
  4324. //----------------------------------------------------------------------------------------------------------
  4325. //----------------------------------------------------------------------------------------------------------
  4326. /**
  4327. * Start firing.
  4328. */
  4329. StateReturnType AIAttackFireWeaponState::onEnter()
  4330. {
  4331. // contained by AIAttackState, so no separate timer
  4332. DEBUG_ASSERTCRASH(m_att != NULL, ("m_att may not be null"));
  4333. Object *obj = getMachineOwner();
  4334. AIUpdateInterface *ai = obj->getAI();
  4335. // Passive stuff will approach but not attack, so we check here (after approach is complete)
  4336. UnsignedInt adjust = ai->getMoodMatrixActionAdjustment(MM_Action_Attack);
  4337. if ((adjust & MAA_Action_Ok) == 0)
  4338. {
  4339. return STATE_FAILURE;
  4340. }
  4341. Object *victim = getMachineGoalObject();
  4342. if (victim && obj->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget) {
  4343. if (obj->getTeam()->getTeamTargetObject()==NULL) {
  4344. obj->getTeam()->setTeamTargetObject(victim);
  4345. }
  4346. }
  4347. obj->setStatus( OBJECT_STATUS_IS_FIRING_WEAPON, true );
  4348. obj->preFireCurrentWeapon( getMachineGoalObject() );
  4349. return STATE_CONTINUE;
  4350. }
  4351. //----------------------------------------------------------------------------------------------------------
  4352. /**
  4353. * Fire the owner's weapon once and exit.
  4354. */
  4355. StateReturnType AIAttackFireWeaponState::update()
  4356. {
  4357. // contained by AIAttackState, so no separate timer
  4358. Object *obj = getMachineOwner();
  4359. Object* victim = getMachineGoalObject();
  4360. if (m_att->isAttackingObject())
  4361. {
  4362. // if our target is dead, go ahead and stop.
  4363. if (!victim || victim->isEffectivelyDead())
  4364. return STATE_FAILURE;
  4365. }
  4366. WeaponSlotType wslot;
  4367. Weapon* weapon = obj->getCurrentWeapon(&wslot);
  4368. if (!weapon)
  4369. {
  4370. return STATE_FAILURE;
  4371. }
  4372. WeaponStatus status = weapon->getStatus();
  4373. if (status == PRE_ATTACK)
  4374. {
  4375. return STATE_CONTINUE;
  4376. }
  4377. else if (status != READY_TO_FIRE)
  4378. {
  4379. return STATE_FAILURE;
  4380. }
  4381. /**
  4382. this is the weird case where we have multi turrets, and turret 'a' wants
  4383. to fire, but someone has changed the current weapon to be one not on him.
  4384. rather than addressing the situation, we just punt and wait for it to clear
  4385. up on its own.
  4386. */
  4387. if (m_att && !m_att->isWeaponSlotOkToFire(wslot))
  4388. {
  4389. return STATE_FAILURE;
  4390. }
  4391. // must adjust the state BEFORE calling fireWeapon, for FX to work correctly...
  4392. obj->setFiringConditionForCurrentWeapon();
  4393. if (m_att->isAttackingObject())
  4394. {
  4395. obj->fireCurrentWeapon(victim);
  4396. // clear this, just in case.
  4397. obj->setStatus( OBJECT_STATUS_IGNORING_STEALTH, false );
  4398. Real continueRange = weapon->getContinueAttackRange();
  4399. if (
  4400. continueRange > 0.0f &&
  4401. victim &&
  4402. (victim->isDestroyed() || victim->isEffectivelyDead() || (victim->isKindOf(KINDOF_MINE) && victim->testStatus(OBJECT_STATUS_MASKED)))
  4403. )
  4404. {
  4405. const Coord3D* originalVictimPos = m_att ? m_att->getOriginalVictimPos() : NULL;
  4406. if (originalVictimPos)
  4407. {
  4408. // note that it is important to use getLastCommandSource here; this allows
  4409. // dozers that were ordered to clear mines by the human to continue to autoacquire,
  4410. // but not if they were ordered by ai.
  4411. AIUpdateInterface* ai = obj->getAI();
  4412. CommandSourceType lastCmdSource = ai ? ai->getLastCommandSource() : CMD_FROM_AI;
  4413. PartitionFilterSamePlayer filterPlayer( victim->getControllingPlayer() );
  4414. PartitionFilterSameMapStatus filterMapStatus(obj);
  4415. PartitionFilterPossibleToAttack filterAttack(ATTACK_NEW_TARGET, obj, lastCmdSource);
  4416. PartitionFilter *filters[] = { &filterAttack, &filterPlayer, &filterMapStatus, NULL };
  4417. // note that we look around originalVictimPos, *not* the current victim's pos.
  4418. victim = ThePartitionManager->getClosestObject( originalVictimPos, continueRange, FROM_CENTER_2D, filters );// could be null. this is ok.
  4419. if (victim)
  4420. {
  4421. getMachine()->setGoalObject(victim);
  4422. m_att->notifyNewVictimChosen(victim);
  4423. }
  4424. }
  4425. }
  4426. }
  4427. else
  4428. {
  4429. obj->fireCurrentWeapon(getMachineGoalPosition());
  4430. // clear this, just in case.
  4431. obj->setStatus( OBJECT_STATUS_IGNORING_STEALTH, false );
  4432. }
  4433. m_att->notifyFired();
  4434. return STATE_SUCCESS;
  4435. }
  4436. //----------------------------------------------------------------------------------------------------------
  4437. /**
  4438. Stop firing.
  4439. */
  4440. void AIAttackFireWeaponState::onExit( StateExitType status )
  4441. {
  4442. // contained by AIAttackState, so no separate timer
  4443. Object *obj = getMachineOwner();
  4444. obj->setStatus( OBJECT_STATUS_IS_FIRING_WEAPON, false );
  4445. // clear this, just in case.
  4446. obj->setStatus( OBJECT_STATUS_IGNORING_STEALTH, false );
  4447. // this can occur if we start a preattack (eg, bayonet)
  4448. // and the target moves out range before we can actually "fire"...
  4449. // leaving us thinking we're still "pre attacking". cancel this state
  4450. // to avoid confusion. (srj)
  4451. Weapon* weapon = obj->getCurrentWeapon();
  4452. if (weapon && weapon->getStatus() == PRE_ATTACK)
  4453. {
  4454. weapon->setPreAttackFinishedFrame(0);
  4455. }
  4456. }
  4457. //----------------------------------------------------------------------------------------------------------
  4458. //----------------------------------------------------------------------------------------------------------
  4459. //----------------------------------------------------------------------------------------------------------
  4460. //----------------------------------------------------------------------------------------------------------
  4461. /**
  4462. * Do nothing for a period of time.
  4463. */
  4464. StateReturnType AIWaitState::update()
  4465. {
  4466. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  4467. return STATE_CONTINUE;
  4468. }
  4469. //----------------------------------------------------------------------------------------------------------
  4470. //----------------------------------------------------------------------------------------------------------
  4471. //----------------------------------------------------------------------------------------------------------
  4472. //----------------------------------------------------------------------------------------------------------
  4473. AIAttackState::AIAttackState( StateMachine *machine, Bool follow, Bool attackingObject, Bool forceAttacking, AttackExitConditionsInterface* attackParameters) :
  4474. State( machine , "AIAttackState"),
  4475. m_attackMachine(NULL),
  4476. m_attackParameters(attackParameters),
  4477. m_lockedWeaponOnEnter(NULL),
  4478. m_follow(follow),
  4479. m_isAttackingObject(attackingObject),
  4480. m_isForceAttacking(forceAttacking),
  4481. m_victimTeam( NULL )
  4482. {
  4483. m_originalVictimPos.zero();
  4484. }
  4485. //----------------------------------------------------------------------------------------------------------
  4486. AIAttackState::~AIAttackState()
  4487. {
  4488. // nope, don't do this, since we may well still have it targeted
  4489. // even though we're leaving this state.
  4490. // turn it off when we do setCurrentVictim(NULL).
  4491. //addSelfAsTargeter(false);
  4492. if (m_attackMachine)
  4493. {
  4494. m_attackMachine->halt();
  4495. m_attackMachine->deleteInstance();
  4496. }
  4497. }
  4498. // ------------------------------------------------------------------------------------------------
  4499. /** CRC */
  4500. // ------------------------------------------------------------------------------------------------
  4501. void AIAttackState::crc( Xfer *xfer )
  4502. {
  4503. } // end crc
  4504. // ------------------------------------------------------------------------------------------------
  4505. /** Xfer Method */
  4506. // ------------------------------------------------------------------------------------------------
  4507. void AIAttackState::xfer( Xfer *xfer )
  4508. {
  4509. // version
  4510. XferVersion currentVersion = 1;
  4511. XferVersion version = currentVersion;
  4512. xfer->xferVersion( &version, currentVersion );
  4513. Bool hasMachine = m_attackMachine!=NULL;
  4514. xfer->xferBool(&hasMachine);
  4515. xfer->xferCoord3D(&m_originalVictimPos);
  4516. if (hasMachine && m_attackMachine==NULL) {
  4517. // create new state machine for attack behavior
  4518. m_attackMachine = newInstance(AttackStateMachine)(getMachineOwner(), this, "AIAttackMachine", m_follow, m_isAttackingObject, m_isForceAttacking );
  4519. }
  4520. if (hasMachine) {
  4521. xfer->xferSnapshot(m_attackMachine); ///< state sub-machine for attack behavior
  4522. }
  4523. /* Not saved or loaded - passed in on creation.
  4524. Bool m_follow;
  4525. Bool m_isAttackingObject; // if false, attacking position
  4526. AttackExitConditionsInterface* m_attackParameters; ///< these are not owned by this, and will not be deleted on destruction
  4527. Bool m_isForceAttacking
  4528. */
  4529. } // end xfer
  4530. // ------------------------------------------------------------------------------------------------
  4531. /** Load post process */
  4532. // ------------------------------------------------------------------------------------------------
  4533. void AIAttackState::loadPostProcess( void )
  4534. {
  4535. Object* victim = getMachineGoalObject();
  4536. if (victim)
  4537. {
  4538. m_victimTeam = victim->getTeam();
  4539. }
  4540. Object* source = getMachineOwner();
  4541. m_lockedWeaponOnEnter = source->isCurWeaponLocked() ? source->getCurrentWeapon() : NULL;
  4542. } // end loadPostProcess
  4543. #ifdef STATE_MACHINE_DEBUG
  4544. //----------------------------------------------------------------------------------------------------------
  4545. AsciiString AIAttackState::getName( ) const
  4546. {
  4547. AsciiString name = m_name;
  4548. name.concat("/");
  4549. if (m_attackMachine) name.concat(m_attackMachine->getCurrentStateName());
  4550. else name.concat("*NULL m_attackMachine");
  4551. return name;
  4552. }
  4553. #endif
  4554. //----------------------------------------------------------------------------------------------------------
  4555. void AIAttackState::chooseWeapon()
  4556. {
  4557. Object* victim = getMachineGoalObject();
  4558. if (m_isAttackingObject && !victim)
  4559. return;
  4560. Object* source = getMachineOwner();
  4561. AIUpdateInterface *ai = source->getAI();
  4562. if (victim)
  4563. {
  4564. /*bool found =*/ source->chooseBestWeaponForTarget(victim, PREFER_MOST_DAMAGE, ai->getLastCommandSource());
  4565. //DEBUG_ASSERTLOG(found, ("unable to autochoose any weapon for %s\n",source->getTemplate()->getName().str()));
  4566. }
  4567. // Check if we need to update because of the weapon choice switch.
  4568. source->adjustModelConditionForWeaponStatus();
  4569. }
  4570. //----------------------------------------------------------------------------------------------------------
  4571. void AIAttackState::notifyNewVictimChosen(Object* victim)
  4572. {
  4573. // do NOT update m_originalVictimPos here. It's a new victim, not the original!
  4574. getMachine()->setGoalObject(victim);
  4575. if (m_attackMachine)
  4576. m_attackMachine->setGoalObject(victim);
  4577. }
  4578. //----------------------------------------------------------------------------------------------------------
  4579. /**
  4580. * Begin an attack on the machine's goal object.
  4581. * To do this complex behavior, instantiate another state machine as a "sub-machine" of
  4582. * the attack state.
  4583. */
  4584. DECLARE_PERF_TIMER(AIAttackState)
  4585. StateReturnType AIAttackState::onEnter()
  4586. {
  4587. USE_PERF_TIMER(AIAttackState)
  4588. //CRCDEBUG_LOG(("AIAttackState::onEnter() - start for object %d\n", getMachineOwner()->getID()));
  4589. Object* source = getMachineOwner();
  4590. AIUpdateInterface *ai = source->getAI();
  4591. // if we are in sleep mode, we will not attack
  4592. if ((ai->getMoodMatrixActionAdjustment(MM_Action_Attack) & MAA_Action_Ok) == 0)
  4593. return STATE_SUCCESS;
  4594. // if we've met the conditions specified by m_attackParameters, we consider ourselves "successful."
  4595. if (m_attackParameters && m_attackParameters->shouldExit(getMachine()))
  4596. return STATE_SUCCESS;
  4597. // if all of our weapons are out of ammo, can't attack.
  4598. // (this can happen for units which never auto-reload, like the Raptor)
  4599. if (source->isOutOfAmmo() && !source->isKindOf(KINDOF_PROJECTILE))
  4600. return STATE_FAILURE;
  4601. // create new state machine for attack behavior
  4602. //CRCDEBUG_LOG(("AIAttackState::onEnter() - constructing state machine for object %d\n", getMachineOwner()->getID()));
  4603. m_attackMachine = newInstance(AttackStateMachine)(source, this, "AIAttackMachine", m_follow, m_isAttackingObject, m_isForceAttacking );
  4604. // tell the attack machine who the victim of the attack is
  4605. if (m_isAttackingObject)
  4606. {
  4607. Object* victim = getMachineGoalObject();
  4608. if (victim == NULL || victim->isEffectivelyDead())
  4609. {
  4610. ai->notifyVictimIsDead();
  4611. return STATE_FAILURE; // we have nothing to attack!
  4612. }
  4613. m_victimTeam = victim->getTeam();
  4614. m_attackMachine->setGoalObject( victim );
  4615. m_originalVictimPos = *victim->getPosition();
  4616. }
  4617. else
  4618. {
  4619. m_attackMachine->setGoalPosition(getMachineGoalPosition());
  4620. m_originalVictimPos = *getMachineGoalPosition();
  4621. }
  4622. chooseWeapon();
  4623. Weapon* curWeapon = source->getCurrentWeapon();
  4624. if (curWeapon)
  4625. {
  4626. curWeapon->setMaxShotCount(NO_MAX_SHOTS_LIMIT);
  4627. // icky special case for ignoring stealth units we might be targeting, that are currently stealthed. (srj)
  4628. if (curWeapon->getContinueAttackRange() > 0.0f)
  4629. source->setStatus(OBJECT_STATUS_IGNORING_STEALTH, true);
  4630. }
  4631. m_lockedWeaponOnEnter = source->isCurWeaponLocked() ? curWeapon : NULL;
  4632. StateReturnType retType = m_attackMachine->initDefaultState();
  4633. if( retType == STATE_CONTINUE )
  4634. {
  4635. source->setStatus( OBJECT_STATUS_IS_ATTACKING, true );
  4636. source->setModelConditionState( MODELCONDITION_ATTACKING );
  4637. }
  4638. return retType;
  4639. }
  4640. //----------------------------------------------------------------------------------------------------------
  4641. /**
  4642. * Execute one frame of "attack enemy" behavior.
  4643. */
  4644. StateReturnType AIAttackState::update()
  4645. {
  4646. USE_PERF_TIMER(AIAttackState)
  4647. // if we've met the conditions specified by m_attackParameters, we consider ourselves "successful."
  4648. if (m_attackParameters && m_attackParameters->shouldExit(getMachine()))
  4649. {
  4650. return STATE_SUCCESS;
  4651. }
  4652. Object* source = getMachineOwner();
  4653. // if all of our weapons are out of ammo, can't attack.
  4654. // (this can happen for units which never auto-reload, like the Raptor)
  4655. if (source->isOutOfAmmo() && !source->isKindOf(KINDOF_PROJECTILE))
  4656. {
  4657. return STATE_FAILURE;
  4658. }
  4659. if (m_isAttackingObject)
  4660. {
  4661. Object* victim = getMachineGoalObject();
  4662. if (victim == NULL || victim->isEffectivelyDead())
  4663. {
  4664. source->getAI()->notifyVictimIsDead();
  4665. return STATE_SUCCESS; // my, that was easy
  4666. }
  4667. if (victim)
  4668. {
  4669. source->getAI()->setCurrentVictim(victim);
  4670. }
  4671. if( victim->getTeam() != m_victimTeam )
  4672. {
  4673. // If, while I have been attacking my victim, it has lost its ability to attack
  4674. //(a recently de-garrisoned building) I should bail here...
  4675. // We are not sure whether the problem occurs here or sometime before, but this is an edge case failsafe for it
  4676. // Steven calls this hack 'greasy,' and I agreesy.-Lorenzen
  4677. AIUpdateInterface *ai = source->getAI();
  4678. if (ai)
  4679. {
  4680. if ( (victim->getStatusBits() & OBJECT_STATUS_CAN_ATTACK) == 0 )
  4681. {
  4682. if ( victim->getContain() != NULL )
  4683. {
  4684. if (victim->getContain()->isGarrisonable() && (victim->getContain()->getContainCount() == 0) )
  4685. {
  4686. if ( source->getRelationship( victim ) == NEUTRAL )
  4687. {
  4688. ai->friend_setGoalObject(NULL);
  4689. if (victim==source->getTeam()->getTeamTargetObject()) {
  4690. source->getTeam()->setTeamTargetObject(NULL);
  4691. }
  4692. ai->notifyVictimIsDead(); // well, not "dead", but longer attackable
  4693. return STATE_FAILURE;
  4694. }
  4695. }
  4696. }
  4697. }
  4698. }
  4699. //The team of the victim has changed since we began attacking it. Evaluate
  4700. //whether or not we should keep attacking it.
  4701. // order matters: we want to know if I consider it to be an enemy, not vice versa
  4702. if( source->getRelationship( victim ) != ENEMIES)
  4703. {
  4704. ai->friend_setGoalObject(NULL);
  4705. if (victim==source->getTeam()->getTeamTargetObject()) {
  4706. source->getTeam()->setTeamTargetObject(NULL);
  4707. }
  4708. ai->notifyVictimIsDead(); // well, not "dead", but longer attackable
  4709. return STATE_FAILURE;
  4710. }
  4711. }
  4712. if (victim != m_attackMachine->getGoalObject())
  4713. {
  4714. // Our parent machine has changed the goal. We need to reset to the new goal. jba.
  4715. m_attackMachine->setGoalObject( victim );
  4716. }
  4717. }
  4718. // re-evaluate our weapon choice every frame, so the sub-states don't have to.
  4719. chooseWeapon();
  4720. Weapon* curWeapon = source->getCurrentWeapon();
  4721. // if we entered with a locked weapon (ie, a special weapon), then we will
  4722. // only keep attacking as long as that weapon remains the cur weapon...
  4723. // if anything ever changes that weapon, we exit attack mode immediately.
  4724. if (m_lockedWeaponOnEnter != NULL && m_lockedWeaponOnEnter != curWeapon)
  4725. return STATE_FAILURE;
  4726. // we've shot as many times as we are allowed to
  4727. if (curWeapon == NULL || curWeapon->getMaxShotCount() <= 0)
  4728. return STATE_FAILURE;
  4729. /**
  4730. * Run the attack state sub-machine.
  4731. * If the attack state machine returns anything other than CONTINUE,
  4732. * it has finished. Propagating the return code will cause
  4733. * the containing state machine to do the right thing.
  4734. * Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  4735. * sleeps, we still need to be called every frame.
  4736. */
  4737. return CONVERT_SLEEP_TO_CONTINUE(m_attackMachine->updateStateMachine());
  4738. }
  4739. //----------------------------------------------------------------------------------------------------------
  4740. void AIAttackState::onExit( StateExitType status )
  4741. {
  4742. USE_PERF_TIMER(AIAttackState)
  4743. // nope, don't do this, since we may well still have it targeted
  4744. // even though we're leaving this state. turn it off when we
  4745. // turn it off when we do setCurrentVictim(NULL).
  4746. //addSelfAsTargeter(false);
  4747. // destroy the attack machine
  4748. if (m_attackMachine)
  4749. {
  4750. m_attackMachine->deleteInstance();
  4751. m_attackMachine = NULL;
  4752. }
  4753. Object *obj = getMachineOwner();
  4754. obj->setStatus( OBJECT_STATUS_IS_FIRING_WEAPON, false );
  4755. obj->setStatus( OBJECT_STATUS_IS_AIMING_WEAPON, false );
  4756. obj->setStatus( OBJECT_STATUS_IS_ATTACKING, false );
  4757. obj->setStatus( OBJECT_STATUS_IGNORING_STEALTH, false );
  4758. obj->clearModelConditionState( MODELCONDITION_ATTACKING );
  4759. obj->clearLeechRangeModeForAllWeapons();
  4760. AIUpdateInterface *ai = obj->getAI();
  4761. if (ai)
  4762. {
  4763. //ai->notifyVictimIsDead(); no, do NOT do this here.
  4764. ai->setCurrentVictim(NULL);
  4765. for (int i = 0; i < MAX_TURRETS; ++i)
  4766. ai->setTurretTargetObject((WhichTurretType)i, NULL, 0);
  4767. ai->friend_setGoalObject(NULL);
  4768. }
  4769. }
  4770. //-------------------------------------------------------------------------------------------------
  4771. //-------------------------------------------------------------------------------------------------
  4772. //-------------------------------------------------------------------------------------------------
  4773. //-----------------------------------------------------------------------------------------------------------
  4774. class AIAttackThenIdleStateMachine : public StateMachine
  4775. {
  4776. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( AIAttackThenIdleStateMachine, "AIAttackThenIdleStateMachine" );
  4777. public:
  4778. AIAttackThenIdleStateMachine( Object *owner, AsciiString name );
  4779. protected:
  4780. // snapshot interface .
  4781. virtual void crc( Xfer *xfer );
  4782. virtual void xfer( Xfer *xfer );
  4783. virtual void loadPostProcess();
  4784. };
  4785. // ------------------------------------------------------------------------------------------------
  4786. /** CRC */
  4787. // ------------------------------------------------------------------------------------------------
  4788. void AIAttackThenIdleStateMachine::crc( Xfer *xfer )
  4789. {
  4790. StateMachine::crc(xfer);
  4791. } // end crc
  4792. // ------------------------------------------------------------------------------------------------
  4793. /** Xfer Method */
  4794. // ------------------------------------------------------------------------------------------------
  4795. void AIAttackThenIdleStateMachine::xfer( Xfer *xfer )
  4796. {
  4797. XferVersion cv = 1;
  4798. XferVersion v = cv;
  4799. xfer->xferVersion( &v, cv );
  4800. StateMachine::xfer(xfer);
  4801. } // end xfer
  4802. // ------------------------------------------------------------------------------------------------
  4803. /** Load post process */
  4804. // ------------------------------------------------------------------------------------------------
  4805. void AIAttackThenIdleStateMachine::loadPostProcess( void )
  4806. {
  4807. StateMachine::loadPostProcess();
  4808. } // end loadPostProcess
  4809. //-----------------------------------------------------------------------------------------------------------
  4810. AIAttackThenIdleStateMachine::AIAttackThenIdleStateMachine(Object *owner, AsciiString name) : StateMachine(owner, name)
  4811. {
  4812. // order matters: first state is the default state.
  4813. defineState( AI_ATTACK_OBJECT, newInstance(AIAttackState)(this, false, true, false, NULL ), AI_IDLE, AI_IDLE );
  4814. defineState( AI_PICK_UP_CRATE, newInstance(AIPickUpCrateState)( this ), AI_IDLE, AI_IDLE );
  4815. defineState( AI_IDLE, newInstance(AIIdleState)( this, AIIdleState::DO_NOT_LOOK_FOR_TARGETS ), AI_IDLE, AI_IDLE );
  4816. }
  4817. //----------------------------------------------------------------------------------------------------------
  4818. AIAttackThenIdleStateMachine::~AIAttackThenIdleStateMachine()
  4819. {
  4820. }
  4821. //----------------------------------------------------------------------------------------------------------
  4822. //----------------------------------------------------------------------------------------------------------
  4823. //----------------------------------------------------------------------------------------------------------
  4824. //----------------------------------------------------------------------------------------------------------
  4825. AIAttackSquadState::~AIAttackSquadState()
  4826. {
  4827. if (m_attackSquadMachine) {
  4828. m_attackSquadMachine->halt();
  4829. m_attackSquadMachine->deleteInstance();
  4830. }
  4831. }
  4832. // ------------------------------------------------------------------------------------------------
  4833. /** CRC */
  4834. // ------------------------------------------------------------------------------------------------
  4835. void AIAttackSquadState::crc( Xfer *xfer )
  4836. {
  4837. } // end crc
  4838. // ------------------------------------------------------------------------------------------------
  4839. /** Xfer Method */
  4840. // ------------------------------------------------------------------------------------------------
  4841. void AIAttackSquadState::xfer( Xfer *xfer )
  4842. {
  4843. // version
  4844. XferVersion currentVersion = 1;
  4845. XferVersion version = currentVersion;
  4846. xfer->xferVersion( &version, currentVersion );
  4847. Bool hasMachine = m_attackSquadMachine!=NULL;
  4848. xfer->xferBool(&hasMachine);
  4849. if (hasMachine && m_attackSquadMachine==NULL) {
  4850. // create new state machine for attack behavior
  4851. m_attackSquadMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackMachine" );
  4852. }
  4853. if (hasMachine) {
  4854. xfer->xferSnapshot(m_attackSquadMachine);
  4855. }
  4856. } // end xfer
  4857. // ------------------------------------------------------------------------------------------------
  4858. /** Load post process */
  4859. // ------------------------------------------------------------------------------------------------
  4860. void AIAttackSquadState::loadPostProcess( void )
  4861. {
  4862. } // end loadPostProcess
  4863. #ifdef STATE_MACHINE_DEBUG
  4864. //----------------------------------------------------------------------------------------------------------
  4865. AsciiString AIAttackSquadState::getName( ) const
  4866. {
  4867. AsciiString name = m_name;
  4868. name.concat("/");
  4869. if (m_attackSquadMachine) name.concat(m_attackSquadMachine->getCurrentStateName());
  4870. else name.concat("*NULL m_attackSquadMachine");
  4871. return name;
  4872. }
  4873. #endif
  4874. //----------------------------------------------------------------------------------------------------------
  4875. /**
  4876. * Begin an attack on the machine's goal team.
  4877. * To do this, we use a sub attack machine.
  4878. */
  4879. StateReturnType AIAttackSquadState::onEnter( void )
  4880. {
  4881. // create new state machine for attack behavior
  4882. m_attackSquadMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackMachine" );
  4883. Object *victim = chooseVictim();
  4884. // tell the attack machine who the victim of the attack is
  4885. m_attackSquadMachine->setGoalObject( victim );
  4886. // initial state of attack state machine
  4887. return m_attackSquadMachine->initDefaultState();
  4888. }
  4889. //----------------------------------------------------------------------------------------------------------
  4890. /**
  4891. * Execute one frame of "attack enemy" behavior.
  4892. */
  4893. StateReturnType AIAttackSquadState::update( void )
  4894. {
  4895. if( !m_attackSquadMachine )
  4896. {
  4897. return STATE_FAILURE;
  4898. }
  4899. /*
  4900. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  4901. sleeps, we still need to be called every frame.
  4902. */
  4903. StateReturnType attackStatus = CONVERT_SLEEP_TO_CONTINUE(m_attackSquadMachine->updateStateMachine());
  4904. // if we're in attack state,
  4905. if (m_attackSquadMachine->getCurrentStateID() != AI_IDLE)
  4906. {
  4907. return attackStatus;
  4908. }
  4909. // Check to see if we have created a crate we need to pick up.
  4910. AIUpdateInterface *ai = getMachineOwner()->getAI();
  4911. Object* crate = ai->checkForCrateToPickup();
  4912. if (crate)
  4913. {
  4914. m_attackSquadMachine->setGoalObject(crate);
  4915. m_attackSquadMachine->setState( AI_PICK_UP_CRATE );
  4916. return STATE_CONTINUE;
  4917. }
  4918. // choose a new target and start over.
  4919. Object *victim = chooseVictim();
  4920. if (!victim)
  4921. {
  4922. return STATE_SUCCESS;
  4923. }
  4924. m_attackSquadMachine->setGoalObject( victim );
  4925. m_attackSquadMachine->setState(AI_ATTACK_OBJECT);
  4926. return STATE_CONTINUE;
  4927. }
  4928. //----------------------------------------------------------------------------------------------------------
  4929. void AIAttackSquadState::onExit( StateExitType status )
  4930. {
  4931. if( m_attackSquadMachine )
  4932. {
  4933. // destroy the attack machine
  4934. m_attackSquadMachine->deleteInstance();
  4935. m_attackSquadMachine = NULL;
  4936. }
  4937. }
  4938. //----------------------------------------------------------------------------------------------------------
  4939. Object *AIAttackSquadState::chooseVictim(void)
  4940. {
  4941. Squad *victimSquad = ((AIStateMachine*)getMachine())->getGoalSquad();
  4942. if (!victimSquad)
  4943. {
  4944. return NULL;
  4945. }
  4946. Object *owner = getMachineOwner();
  4947. AIUpdateInterface *ai = owner->getAI();
  4948. UnsignedInt moodVal = ai->getMoodMatrixValue();
  4949. if (moodVal & MM_Controller_AI)
  4950. {
  4951. if (moodVal & MM_Mood_Sleep)
  4952. {
  4953. return NULL;
  4954. }
  4955. if (moodVal & MM_Mood_Passive)
  4956. {
  4957. BodyModuleInterface *bmi = owner->getBodyModule();
  4958. if (!bmi) {
  4959. return NULL;
  4960. }
  4961. const DamageInfo *di = bmi->getLastDamageInfo();
  4962. if (!di)
  4963. {
  4964. return NULL;
  4965. }
  4966. return TheGameLogic->findObjectByID(di->in.m_sourceID);
  4967. }
  4968. }
  4969. GameDifficulty difficulty = owner->getControllingPlayer()->getPlayerDifficulty();
  4970. const CommandSourceType cmdSource = ai->getLastCommandSource();
  4971. if (cmdSource == CMD_FROM_PLAYER)
  4972. {
  4973. // if a player did this, we want to always give them the Seek and obliterate method.
  4974. difficulty = DIFFICULTY_HARD;
  4975. }
  4976. if (TheScriptEngine->getChooseVictimAlwaysUsesNormal())
  4977. {
  4978. difficulty = DIFFICULTY_NORMAL;
  4979. }
  4980. switch(difficulty)
  4981. {
  4982. case DIFFICULTY_EASY:
  4983. {
  4984. // pick a random unit
  4985. VecObjectPtr objects = victimSquad->getLiveObjects();
  4986. Int numUnits = objects.size();
  4987. if (numUnits == 0)
  4988. {
  4989. return NULL;
  4990. }
  4991. Int unitToAttack = GameLogicRandomValue(0, numUnits - 1);
  4992. return objects[unitToAttack];
  4993. break;
  4994. }
  4995. case DIFFICULTY_NORMAL:
  4996. {
  4997. // pick the closest unit
  4998. PartitionFilterAcceptOnSquad f1(victimSquad);
  4999. PartitionFilterSameMapStatus filterMapStatus(getMachineOwner());
  5000. PartitionFilter *filters[] = { &f1, &filterMapStatus, NULL };
  5001. Object *victim = ThePartitionManager->getClosestObject(getMachineOwner(), HUGE_DIST, FROM_CENTER_2D, filters, NULL, NULL);
  5002. return victim;
  5003. break;
  5004. }
  5005. case DIFFICULTY_HARD:
  5006. {
  5007. // everyone picks the same unit
  5008. VecObjectPtr objects = victimSquad->getLiveObjects();
  5009. if (objects.size() > 0)
  5010. {
  5011. return objects[0];
  5012. }
  5013. return NULL;
  5014. break;
  5015. }
  5016. };
  5017. return NULL;
  5018. }
  5019. //----------------------------------------------------------------------------------------------------------
  5020. //----------------------------------------------------------------------------------------------------------
  5021. //----------------------------------------------------------------------------------------------------------
  5022. //----------------------------------------------------------------------------------------------------------
  5023. AIDockState::~AIDockState()
  5024. {
  5025. if (m_dockMachine) {
  5026. m_dockMachine->halt();
  5027. m_dockMachine->deleteInstance();
  5028. }
  5029. }
  5030. // ------------------------------------------------------------------------------------------------
  5031. /** CRC */
  5032. // ------------------------------------------------------------------------------------------------
  5033. void AIDockState::crc( Xfer *xfer )
  5034. {
  5035. } // end crc
  5036. // ------------------------------------------------------------------------------------------------
  5037. /** Xfer Method */
  5038. // ------------------------------------------------------------------------------------------------
  5039. void AIDockState::xfer( Xfer *xfer )
  5040. {
  5041. // version
  5042. XferVersion currentVersion = 1;
  5043. XferVersion version = currentVersion;
  5044. xfer->xferVersion( &version, currentVersion );
  5045. Bool hasMachine = m_dockMachine!=NULL;
  5046. xfer->xferBool(&hasMachine);
  5047. if (hasMachine && m_dockMachine==NULL) {
  5048. // create new state machine for attack behavior
  5049. m_dockMachine = newInstance(AIDockMachine)( getMachineOwner());
  5050. }
  5051. if (hasMachine) {
  5052. xfer->xferSnapshot(m_dockMachine);
  5053. }
  5054. xfer->xferBool(&m_usingPrecisionMovement);
  5055. } // end xfer
  5056. // ------------------------------------------------------------------------------------------------
  5057. /** Load post process */
  5058. // ------------------------------------------------------------------------------------------------
  5059. void AIDockState::loadPostProcess( void )
  5060. {
  5061. } // end loadPostProcess
  5062. #ifdef STATE_MACHINE_DEBUG
  5063. //----------------------------------------------------------------------------------------------------------
  5064. AsciiString AIDockState::getName( ) const
  5065. {
  5066. AsciiString name = m_name;
  5067. name.concat("/");
  5068. if (m_dockMachine) name.concat(m_dockMachine->getCurrentStateName());
  5069. else name.concat("*NULL m_dockMachine");
  5070. return name;
  5071. }
  5072. #endif
  5073. //----------------------------------------------------------------------------------------------
  5074. /**
  5075. * Dock with the GoalObject.
  5076. * When we enter the AI_DOCK state, create a docking state machine
  5077. * that implements the details of the docking behavior.
  5078. */
  5079. StateReturnType AIDockState::onEnter()
  5080. {
  5081. // who are we docking with?
  5082. Object *dockWithMe = getMachineGoalObject();
  5083. if (dockWithMe == NULL)
  5084. {
  5085. // we have nothing to dock with!
  5086. DEBUG_LOG(("No goal in AIDockState::onEnter - exiting.\n"));
  5087. return STATE_FAILURE;
  5088. }
  5089. DockUpdateInterface *dock = NULL;
  5090. dock = dockWithMe->getDockUpdateInterface();
  5091. // if we have nothing to dock with, fail
  5092. if (dock == NULL) {
  5093. DEBUG_LOG(("Goal is not a dock in AIDockState::onEnter - exiting.\n"));
  5094. return STATE_FAILURE;
  5095. }
  5096. // tell the pathfinder to ignore the object we are docking with, so it doesn't block us
  5097. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5098. if( ai )
  5099. {
  5100. ai->ignoreObstacle( dockWithMe );
  5101. }
  5102. // create new state machine for attack behavior
  5103. m_dockMachine = newInstance(AIDockMachine)( getMachineOwner());
  5104. // tell the docking machine what it is docking with
  5105. m_dockMachine->setGoalObject( dockWithMe );
  5106. // now that essential parameters are set, set the machine's initial state
  5107. return m_dockMachine->initDefaultState( );
  5108. }
  5109. /**
  5110. * For whatever reason, we are leaving the AI_DOCK state.
  5111. * Destroy the docking sub-machine.
  5112. */
  5113. void AIDockState::onExit( StateExitType status )
  5114. {
  5115. // destroy the dock machine
  5116. if (m_dockMachine) {
  5117. m_dockMachine->halt();// GS, you have to halt before you delete to do cleanup.
  5118. m_dockMachine->deleteInstance();
  5119. m_dockMachine = NULL;
  5120. } else {
  5121. DEBUG_LOG(("Dock exited immediately\n"));
  5122. }
  5123. // stop ignoring our goal object
  5124. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5125. if (ai)
  5126. {
  5127. ai->setCanPathThroughUnits(false);
  5128. ai->ignoreObstacle( NULL );
  5129. }
  5130. }
  5131. /**
  5132. * We are in the AI_DOCK state, execute the docking behavior.
  5133. */
  5134. StateReturnType AIDockState::update()
  5135. {
  5136. /**
  5137. * Run the docking state sub-machine.
  5138. * If the dock state machine returns anything other than CONTINUE,
  5139. * it has finished. propagating the return code will cause
  5140. * the containing state machine to do the right thing.
  5141. */
  5142. AIUpdateInterface *ai = getMachineOwner()->getAI();
  5143. if (ai)
  5144. {
  5145. ai->setCanPathThroughUnits(true);
  5146. //if (ai->isBlockedAndStuck()) {
  5147. //DEBUG_LOG(("Blocked and stuck.\n"));
  5148. //}
  5149. //if (ai->getNumFramesBlocked()>5) {
  5150. //DEBUG_LOG(("Blocked %d frames\n", ai->getNumFramesBlocked()));
  5151. //}
  5152. }
  5153. /*
  5154. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  5155. sleeps, we still need to be called every frame.
  5156. */
  5157. return CONVERT_SLEEP_TO_CONTINUE(m_dockMachine->updateStateMachine());
  5158. }
  5159. //----------------------------------------------------------------------------------------------------------
  5160. //----------------------------------------------------------------------------------------------------------
  5161. //----------------------------------------------------------------------------------------------------------
  5162. // ------------------------------------------------------------------------------------------------
  5163. /** CRC */
  5164. // ------------------------------------------------------------------------------------------------
  5165. void AIEnterState::crc( Xfer *xfer )
  5166. {
  5167. AIInternalMoveToState::crc(xfer);
  5168. } // end crc
  5169. // ------------------------------------------------------------------------------------------------
  5170. /** Xfer Method */
  5171. // ------------------------------------------------------------------------------------------------
  5172. void AIEnterState::xfer( Xfer *xfer )
  5173. {
  5174. // version
  5175. XferVersion currentVersion = 1;
  5176. XferVersion version = currentVersion;
  5177. xfer->xferVersion( &version, currentVersion );
  5178. AIInternalMoveToState::xfer(xfer);
  5179. xfer->xferObjectID(&m_entryToClear);
  5180. } // end xfer
  5181. // ------------------------------------------------------------------------------------------------
  5182. /** Load post process */
  5183. // ------------------------------------------------------------------------------------------------
  5184. void AIEnterState::loadPostProcess( void )
  5185. {
  5186. AIInternalMoveToState::loadPostProcess();
  5187. } // end loadPostProcess
  5188. //----------------------------------------------------------------------------------------------------------
  5189. StateReturnType AIEnterState::onEnter()
  5190. {
  5191. m_entryToClear = INVALID_ID;
  5192. Object* obj = getMachineOwner();
  5193. Object* goal = getMachineGoalObject();
  5194. if (goal)
  5195. {
  5196. if( !TheActionManager->canEnterObject( obj, goal, obj->getAI()->getLastCommandSource(), CHECK_CAPACITY ) )
  5197. return STATE_FAILURE;
  5198. m_goalPosition = *goal->getPosition();
  5199. ContainModuleInterface* contain = goal->getContain();
  5200. if (contain)
  5201. {
  5202. contain->onObjectWantsToEnterOrExit(obj, WANTS_TO_ENTER);
  5203. m_entryToClear = goal->getID();
  5204. }
  5205. }
  5206. else
  5207. {
  5208. return STATE_FAILURE;
  5209. }
  5210. // tell the pathfinder to ignore the enterable object
  5211. AIUpdateInterface *ai = obj->getAI();
  5212. ai->ignoreObstacle( getMachineGoalObject() );
  5213. if (ai->getCurLocomotor())
  5214. {
  5215. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  5216. }
  5217. setAdjustsDestination(false);
  5218. return AIInternalMoveToState::onEnter();
  5219. }
  5220. //----------------------------------------------------------------------------------------------------------
  5221. void AIEnterState::onExit( StateExitType status )
  5222. {
  5223. Object* obj = getMachineOwner();
  5224. AIInternalMoveToState::onExit( status );
  5225. // tell the pathfinder to stop ignoring the object
  5226. AIUpdateInterface *ai = obj->getAI();
  5227. if (ai)
  5228. {
  5229. ai->ignoreObstacle( NULL );
  5230. if (ai->getCurLocomotor())
  5231. {
  5232. ai->getCurLocomotor()->setAllowInvalidPosition(false);
  5233. }
  5234. }
  5235. // use this, rather than getMachineGoalObject, in case the goal
  5236. // is killed while we were waiting...
  5237. if (m_entryToClear != INVALID_ID)
  5238. {
  5239. Object* goal = TheGameLogic->findObjectByID(m_entryToClear);
  5240. if (goal)
  5241. {
  5242. ContainModuleInterface* contain = goal->getContain();
  5243. if (contain)
  5244. {
  5245. contain->onObjectWantsToEnterOrExit(obj, WANTS_NEITHER);
  5246. }
  5247. }
  5248. }
  5249. }
  5250. //----------------------------------------------------------------------------------------------------------
  5251. StateReturnType AIEnterState::update()
  5252. {
  5253. // update the goal position to coincide with the GoalObject
  5254. Object* obj = getMachineOwner();
  5255. Object* goal = getMachineGoalObject();
  5256. if (goal)
  5257. {
  5258. // if our goal is contained by something else, give up. this is for the following bug:
  5259. // -- tell some rangers to enter a humvee
  5260. // -- tell the humvee to enter a chinook
  5261. // -- fly the chinook around; the rangers follow the chinook like dopes
  5262. // this just bails in this case. (srj)
  5263. if (goal->getContainedBy() != NULL && goal->isAboveTerrain() && !obj->isAboveTerrain())
  5264. {
  5265. return STATE_FAILURE;
  5266. }
  5267. m_goalPosition = *goal->getPosition();
  5268. obj->getAI()->friend_setGoalObject(goal);
  5269. if (!TheActionManager->canEnterObject(obj, goal, obj->getAI()->getLastCommandSource(), CHECK_CAPACITY))
  5270. {
  5271. /*
  5272. special-case: if it's an enemy, try attacking it instead. this is to address this bug: (srj)
  5273. Bug: Units stop instead of attacking if building they were trying to garrison is taken by enemy units first.
  5274. 1. any game/any faction
  5275. 2. build infantry units that can garrison neutral buildings
  5276. 3. have infantry units garrison a neutral building, before they garrison the building have some enemy units garrison it first.
  5277. Expected result: Based on test plan: Instead of just stopping when enemy units garrison building first, they should continue and attack the building.
  5278. */
  5279. if( obj->getRelationship(goal) == ENEMIES && obj->getAI() )
  5280. {
  5281. CanAttackResult result = TheActionManager->getCanAttackObject(obj, goal, obj->getAI()->getLastCommandSource(), ATTACK_NEW_TARGET);
  5282. if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  5283. {
  5284. obj->getAI()->aiAttackObject(goal, NO_MAX_SHOTS_LIMIT, obj->getAI()->getLastCommandSource());
  5285. // weird but true. return state_continue, because if we're here, we're actually an attack state
  5286. // since we just changed the state, it doesn't really matter what we return here.
  5287. return STATE_CONTINUE;
  5288. }
  5289. return STATE_FAILURE;
  5290. }
  5291. return STATE_FAILURE;
  5292. }
  5293. // If we are held, then we must have entered the goal.
  5294. if( getMachineOwner()->isDisabledByType( DISABLED_HELD ) )
  5295. {
  5296. return STATE_SUCCESS;
  5297. }
  5298. }
  5299. else
  5300. {
  5301. return STATE_FAILURE;
  5302. }
  5303. StateReturnType code = AIInternalMoveToState::update();
  5304. // if it's airborne, wait for it to land
  5305. if (code == STATE_SUCCESS && goal->isAboveTerrain() && !obj->isAboveTerrain())
  5306. {
  5307. code = STATE_CONTINUE;
  5308. }
  5309. if (code == STATE_SUCCESS)
  5310. {
  5311. // Make sure we entered the container.
  5312. // srj sez: I don't think we want to restrict this to HELD items. See the intro of GLA02.map
  5313. // for an example of guys-off-the-border-but-not-held who need this check.
  5314. //if( obj->isDisabledByType( DISABLED_HELD ) )
  5315. {
  5316. if (goal)
  5317. {
  5318. // we didn't enter. See if we're close.
  5319. Real dx = (obj->getPosition()->x - goal->getPosition()->x);
  5320. Real dy = (obj->getPosition()->y - goal->getPosition()->y);
  5321. Real radius = goal->getGeometryInfo().getMinorRadius();
  5322. if (goal->getGeometryInfo().getGeomType()!=GEOMETRY_BOX) {
  5323. radius = goal->getGeometryInfo().getMajorRadius();
  5324. }
  5325. Bool closeEnough = dx*dx+dy*dy < sqr(radius);
  5326. if (closeEnough) {
  5327. // Grab the container and force ourselves into it.
  5328. // This case is primarily to handle transports on the map border for scripted setup.
  5329. // The partition manager doesn't generate collisions in the border area, so we have to
  5330. // add ourselves. jba.
  5331. ContainModuleInterface* contain = goal->getContain();
  5332. if (contain)
  5333. {
  5334. contain->addToContain(obj);
  5335. }
  5336. }
  5337. }
  5338. }
  5339. }
  5340. return code;
  5341. }
  5342. //----------------------------------------------------------------------------------------------------------
  5343. //----------------------------------------------------------------------------------------------------------
  5344. //----------------------------------------------------------------------------------------------------------
  5345. // ------------------------------------------------------------------------------------------------
  5346. /** CRC */
  5347. // ------------------------------------------------------------------------------------------------
  5348. void AIExitState::crc( Xfer *xfer )
  5349. {
  5350. } // end crc
  5351. // ------------------------------------------------------------------------------------------------
  5352. /** Xfer Method */
  5353. // ------------------------------------------------------------------------------------------------
  5354. void AIExitState::xfer( Xfer *xfer )
  5355. {
  5356. // version
  5357. XferVersion currentVersion = 1;
  5358. XferVersion version = currentVersion;
  5359. xfer->xferVersion( &version, currentVersion );
  5360. xfer->xferObjectID(&m_entryToClear);
  5361. } // end xfer
  5362. // ------------------------------------------------------------------------------------------------
  5363. /** Load post process */
  5364. // ------------------------------------------------------------------------------------------------
  5365. void AIExitState::loadPostProcess( void )
  5366. {
  5367. } // end loadPostProcess
  5368. //----------------------------------------------------------------------------------------------------------
  5369. StateReturnType AIExitState::onEnter()
  5370. {
  5371. m_entryToClear = INVALID_ID;
  5372. Object* obj = getMachineOwner();
  5373. Object* goal = getMachineGoalObject();
  5374. if (goal)
  5375. {
  5376. ContainModuleInterface* contain = goal->getContain();
  5377. if (contain)
  5378. {
  5379. contain->onObjectWantsToEnterOrExit(obj, WANTS_TO_EXIT);
  5380. m_entryToClear = goal->getID();
  5381. }
  5382. return STATE_CONTINUE;
  5383. }
  5384. else
  5385. {
  5386. return STATE_FAILURE;
  5387. }
  5388. }
  5389. //----------------------------------------------------------------------------------------------------------
  5390. StateReturnType AIExitState::update()
  5391. {
  5392. // update the goal position to coincide with the GoalObject
  5393. Object* obj = getMachineOwner();
  5394. Object* goal = getMachineGoalObject();
  5395. if (goal)
  5396. {
  5397. AIUpdateInterface* goalAI = goal->getAI();
  5398. if (goalAI && goalAI->getAiFreeToExit(obj) == WAIT_TO_EXIT)
  5399. return STATE_CONTINUE;
  5400. DEBUG_ASSERTCRASH(obj, ("obj must not be null here"));
  5401. //GS. The goal of unified ExitInterfaces dies a horrible death. I can't ask Object for the exit,
  5402. // as removeFromContain is only in the Contain type. I'm spliting the names in shame.
  5403. ExitInterface* goalExitInterface = goal->getContain() ? goal->getContain()->getContainExitInterface() : NULL;
  5404. if( goalExitInterface == NULL )
  5405. return STATE_FAILURE;
  5406. if( goalExitInterface->isExitBusy() )
  5407. return STATE_CONTINUE;// Just wait a sec.
  5408. ExitDoorType exitDoor = goalExitInterface ? goalExitInterface->reserveDoorForExit(obj->getTemplate(), obj) : DOOR_NONE_NEEDED;
  5409. if (exitDoor == DOOR_NONE_AVAILABLE)
  5410. return STATE_FAILURE;
  5411. goalExitInterface->exitObjectViaDoor(obj, exitDoor);
  5412. if( getMachine()->getCurrentStateID() != getID() )
  5413. return STATE_CONTINUE;// Not sucess, because exitViaDoor has changed us to FollowPath, and if we say Success, our machine will think FollowPath succeeded
  5414. else
  5415. return STATE_SUCCESS;
  5416. }
  5417. else
  5418. {
  5419. return STATE_FAILURE;
  5420. }
  5421. }
  5422. //----------------------------------------------------------------------------------------------------------
  5423. void AIExitState::onExit( StateExitType status )
  5424. {
  5425. Object* obj = getMachineOwner();
  5426. // use this, rather than getMachineGoalObject, in case the goal
  5427. // is killed while we were waiting...
  5428. if (m_entryToClear != INVALID_ID)
  5429. {
  5430. Object* goal = TheGameLogic->findObjectByID(m_entryToClear);
  5431. if (goal)
  5432. {
  5433. ContainModuleInterface* contain = goal->getContain();
  5434. if (contain)
  5435. {
  5436. contain->onObjectWantsToEnterOrExit(obj, WANTS_NEITHER);
  5437. }
  5438. }
  5439. }
  5440. }
  5441. //----------------------------------------------------------------------------------------------------------
  5442. //----------------------------------------------------------------------------------------------------------
  5443. //----------------------------------------------------------------------------------------------------------
  5444. //----------------------------------------------------------------------------------------------------------
  5445. AIGuardState::~AIGuardState()
  5446. {
  5447. if (m_guardMachine) {
  5448. m_guardMachine->halt();
  5449. m_guardMachine->deleteInstance();
  5450. }
  5451. }
  5452. #ifdef STATE_MACHINE_DEBUG
  5453. //----------------------------------------------------------------------------------------------------------
  5454. AsciiString AIGuardState::getName( ) const
  5455. {
  5456. AsciiString name = m_name;
  5457. name.concat("/");
  5458. if (m_guardMachine) name.concat(m_guardMachine->getCurrentStateName());
  5459. else name.concat("*NULL guardMachine");
  5460. return name;
  5461. }
  5462. #endif
  5463. // ------------------------------------------------------------------------------------------------
  5464. /** CRC */
  5465. // ------------------------------------------------------------------------------------------------
  5466. void AIGuardState::crc( Xfer *xfer )
  5467. {
  5468. } // end crc
  5469. // ------------------------------------------------------------------------------------------------
  5470. /** Xfer Method */
  5471. // ------------------------------------------------------------------------------------------------
  5472. void AIGuardState::xfer( Xfer *xfer )
  5473. {
  5474. // version
  5475. XferVersion currentVersion = 1;
  5476. XferVersion version = currentVersion;
  5477. xfer->xferVersion( &version, currentVersion );
  5478. Bool hasMachine = m_guardMachine!=NULL;
  5479. xfer->xferBool(&hasMachine);
  5480. if (hasMachine && m_guardMachine==NULL) {
  5481. // create new state machine for guard behavior
  5482. m_guardMachine = newInstance(AIGuardMachine)( getMachineOwner());
  5483. }
  5484. if (hasMachine) {
  5485. xfer->xferSnapshot(m_guardMachine);
  5486. }
  5487. } // end xfer
  5488. // ------------------------------------------------------------------------------------------------
  5489. /** Load post process */
  5490. // ------------------------------------------------------------------------------------------------
  5491. void AIGuardState::loadPostProcess( void )
  5492. {
  5493. } // end loadPostProcess
  5494. //----------------------------------------------------------------------------------------------------------
  5495. /**
  5496. * Guard location.
  5497. */
  5498. StateReturnType AIGuardState::onEnter()
  5499. {
  5500. Object *obj = getMachineOwner();
  5501. AIUpdateInterface *ai = obj->getAI();
  5502. m_guardMachine = newInstance(AIGuardMachine)( getMachineOwner());
  5503. // tell the guarding machine what it is guarding with
  5504. switch(ai->getGuardTargetType())
  5505. {
  5506. case GUARDTARGET_LOCATION: m_guardMachine->setTargetPositionToGuard( ai->getGuardLocation() ); break;
  5507. case GUARDTARGET_OBJECT: m_guardMachine->setTargetToGuard( TheGameLogic->findObjectByID(ai->getGuardObject()) ); break;
  5508. case GUARDTARGET_AREA: m_guardMachine->setAreaToGuard( ai->getAreaToGuard() ); break;
  5509. }
  5510. m_guardMachine->setGuardMode(ai->getGuardMode());
  5511. // now that essential parameters are set, set the machine's initial state
  5512. if (m_guardMachine->initDefaultState() == STATE_FAILURE)
  5513. return STATE_FAILURE;
  5514. return m_guardMachine->setState(AI_GUARD_RETURN);
  5515. }
  5516. //----------------------------------------------------------------------------------------------------------
  5517. void AIGuardState::onExit( StateExitType status )
  5518. {
  5519. m_guardMachine->deleteInstance();
  5520. m_guardMachine = NULL;
  5521. Object *obj = getMachineOwner();
  5522. obj->getAI()->clearGuardTargetType();
  5523. }
  5524. //----------------------------------------------------------------------------------------------------------
  5525. StateReturnType AIGuardState::update()
  5526. {
  5527. //DEBUG_LOG(("AIGuardState frame %d: %08lx\n",TheGameLogic->getFrame(),getMachineOwner()));
  5528. if (m_guardMachine == NULL)
  5529. {
  5530. return STATE_FAILURE; // We actually already exited.
  5531. }
  5532. // if all of our weapons are out of ammo, can't attack.
  5533. // (this can happen for units which never auto-reload, like the Raptor)
  5534. Object* owner = getMachineOwner();
  5535. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  5536. {
  5537. DEBUG_CRASH(("Hmm, this should probably never happen, since this case should be intercepted by JetAIUpdate\n"));
  5538. return STATE_FAILURE;
  5539. }
  5540. getMachine()->lock("AIGuardState::update"); // We don't want to switch out of guard during the update.
  5541. StateReturnType ret = m_guardMachine->updateStateMachine();
  5542. getMachine()->unlock();
  5543. return ret;
  5544. }
  5545. //----------------------------------------------------------------------------------------------------------
  5546. //----------------------------------------------------------------------------------------------------------
  5547. //----------------------------------------------------------------------------------------------------------
  5548. //----------------------------------------------------------------------------------------------------------
  5549. AITunnelNetworkGuardState::~AITunnelNetworkGuardState()
  5550. {
  5551. if (m_guardMachine) {
  5552. m_guardMachine->halt();
  5553. m_guardMachine->deleteInstance();
  5554. }
  5555. }
  5556. #ifdef STATE_MACHINE_DEBUG
  5557. //----------------------------------------------------------------------------------------------------------
  5558. AsciiString AITunnelNetworkGuardState::getName( ) const
  5559. {
  5560. AsciiString name = m_name;
  5561. name.concat("/");
  5562. if (m_guardMachine) name.concat(m_guardMachine->getCurrentStateName());
  5563. else name.concat("*NULL guardMachine");
  5564. return name;
  5565. }
  5566. #endif
  5567. // ------------------------------------------------------------------------------------------------
  5568. /** CRC */
  5569. // ------------------------------------------------------------------------------------------------
  5570. void AITunnelNetworkGuardState::crc( Xfer *xfer )
  5571. {
  5572. } // end crc
  5573. // ------------------------------------------------------------------------------------------------
  5574. /** Xfer Method */
  5575. // ------------------------------------------------------------------------------------------------
  5576. void AITunnelNetworkGuardState::xfer( Xfer *xfer )
  5577. {
  5578. // version
  5579. XferVersion currentVersion = 1;
  5580. XferVersion version = currentVersion;
  5581. xfer->xferVersion( &version, currentVersion );
  5582. Bool hasMachine = m_guardMachine!=NULL;
  5583. xfer->xferBool(&hasMachine);
  5584. if (hasMachine && m_guardMachine==NULL) {
  5585. // create new state machine for guard behavior
  5586. m_guardMachine = newInstance(AITNGuardMachine)( getMachineOwner());
  5587. }
  5588. if (hasMachine) {
  5589. xfer->xferSnapshot(m_guardMachine);
  5590. }
  5591. } // end xfer
  5592. // ------------------------------------------------------------------------------------------------
  5593. /** Load post process */
  5594. // ------------------------------------------------------------------------------------------------
  5595. void AITunnelNetworkGuardState::loadPostProcess( void )
  5596. {
  5597. } // end loadPostProcess
  5598. //----------------------------------------------------------------------------------------------------------
  5599. /**
  5600. * Guard location.
  5601. */
  5602. StateReturnType AITunnelNetworkGuardState::onEnter()
  5603. {
  5604. Object *obj = getMachineOwner();
  5605. AIUpdateInterface *ai = obj->getAI();
  5606. m_guardMachine = newInstance(AITNGuardMachine)( getMachineOwner());
  5607. // tell the guarding machine what it is guarding with
  5608. m_guardMachine->setTargetPositionToGuard( ai->getGuardLocation() );
  5609. m_guardMachine->setGuardMode(ai->getGuardMode());
  5610. // now that essential parameters are set, set the machine's initial state
  5611. if (m_guardMachine->initDefaultState() == STATE_FAILURE)
  5612. return STATE_FAILURE;
  5613. return m_guardMachine->setState(AI_GUARD_RETURN);
  5614. }
  5615. //----------------------------------------------------------------------------------------------------------
  5616. void AITunnelNetworkGuardState::onExit( StateExitType status )
  5617. {
  5618. m_guardMachine->deleteInstance();
  5619. m_guardMachine = NULL;
  5620. Object *obj = getMachineOwner();
  5621. obj->getAI()->clearGuardTargetType();
  5622. }
  5623. //----------------------------------------------------------------------------------------------------------
  5624. StateReturnType AITunnelNetworkGuardState::update()
  5625. {
  5626. //DEBUG_LOG(("AITunnelNetworkGuardState frame %d: %08lx\n",TheGameLogic->getFrame(),getMachineOwner()));
  5627. if (m_guardMachine == NULL)
  5628. {
  5629. return STATE_FAILURE; // We actually already exited.
  5630. }
  5631. // if all of our weapons are out of ammo, can't attack.
  5632. // (this can happen for units which never auto-reload, like the Raptor)
  5633. Object* owner = getMachineOwner();
  5634. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  5635. {
  5636. DEBUG_CRASH(("Hmm, this should probably never happen, since this case should be intercepted by JetAIUpdate\n"));
  5637. return STATE_FAILURE;
  5638. }
  5639. getMachine()->lock("AITunnelNetworkGuardState::update"); // We don't want to switch out of guard during the update.
  5640. StateReturnType ret = m_guardMachine->updateStateMachine();
  5641. getMachine()->unlock();
  5642. return ret;
  5643. }
  5644. //-------------------------------------------------------------------------------------------------
  5645. //-------------------------------------------------------------------------------------------------
  5646. //-------------------------------------------------------------------------------------------------
  5647. //----------------------------------------------------------------------------------------------------------
  5648. //----------------------------------------------------------------------------------------------------------
  5649. //----------------------------------------------------------------------------------------------------------
  5650. //----------------------------------------------------------------------------------------------------------
  5651. AIHuntState::~AIHuntState()
  5652. {
  5653. if (m_huntMachine)
  5654. {
  5655. m_huntMachine->halt();
  5656. m_huntMachine->deleteInstance();
  5657. }
  5658. }
  5659. // ------------------------------------------------------------------------------------------------
  5660. /** CRC */
  5661. // ------------------------------------------------------------------------------------------------
  5662. void AIHuntState::crc( Xfer *xfer )
  5663. {
  5664. } // end crc
  5665. // ------------------------------------------------------------------------------------------------
  5666. /** Xfer Method */
  5667. // ------------------------------------------------------------------------------------------------
  5668. void AIHuntState::xfer( Xfer *xfer )
  5669. {
  5670. // version
  5671. XferVersion currentVersion = 1;
  5672. XferVersion version = currentVersion;
  5673. xfer->xferVersion( &version, currentVersion );
  5674. Bool hasMachine = m_huntMachine!=NULL;
  5675. xfer->xferBool(&hasMachine);
  5676. if (hasMachine && m_huntMachine==NULL) {
  5677. // create new state machine for hunt behavior
  5678. m_huntMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  5679. }
  5680. if (hasMachine) {
  5681. xfer->xferSnapshot(m_huntMachine);
  5682. }
  5683. xfer->xferUnsignedInt(&m_nextEnemyScanTime);
  5684. } // end xfer
  5685. // ------------------------------------------------------------------------------------------------
  5686. /** Load post process */
  5687. // ------------------------------------------------------------------------------------------------
  5688. void AIHuntState::loadPostProcess( void )
  5689. {
  5690. } // end loadPostProcess
  5691. //----------------------------------------------------------------------------------------------------------
  5692. /**
  5693. * Hunt (seek and destroy).
  5694. */
  5695. StateReturnType AIHuntState::onEnter()
  5696. {
  5697. // create new state machine for hunt behavior
  5698. m_huntMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  5699. // first time thru, use a random amount so that everyone doesn't scan on the same frame,
  5700. // to avoid "spikes".
  5701. UnsignedInt sleepTime = GameLogicRandomValue(0, ENEMY_SCAN_RATE);
  5702. UnsignedInt now = TheGameLogic->getFrame();
  5703. m_nextEnemyScanTime = now + sleepTime;
  5704. // initial state of hunt state machine
  5705. return m_huntMachine->initDefaultState();
  5706. }
  5707. //----------------------------------------------------------------------------------------------------------
  5708. void AIHuntState::onExit( StateExitType status )
  5709. {
  5710. // destroy the hunt machine
  5711. m_huntMachine->deleteInstance();
  5712. m_huntMachine = NULL;
  5713. Object *obj = getMachineOwner();
  5714. if (obj)
  5715. {
  5716. obj->releaseWeaponLock(LOCKED_TEMPORARILY); // release any temporary locks.
  5717. }
  5718. }
  5719. #ifdef STATE_MACHINE_DEBUG
  5720. //----------------------------------------------------------------------------------------------------------
  5721. AsciiString AIHuntState::getName( ) const
  5722. {
  5723. AsciiString name = m_name;
  5724. name.concat("/");
  5725. if (m_huntMachine) name.concat(m_huntMachine->getCurrentStateName());
  5726. else name.concat("*NULL huntMachine");
  5727. return name;
  5728. }
  5729. #endif
  5730. //----------------------------------------------------------------------------------------------------------
  5731. StateReturnType AIHuntState::update()
  5732. {
  5733. // look around for better victims every so often
  5734. UnsignedInt now = TheGameLogic->getFrame();
  5735. if (now >= m_nextEnemyScanTime)
  5736. {
  5737. Object* owner = getMachineOwner();
  5738. // if all of our weapons are out of ammo, can't hunt.
  5739. // (this can happen for units which never auto-reload, like the Raptor)
  5740. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  5741. return STATE_FAILURE;
  5742. // Check to see if we have created a crate we need to pick up.
  5743. AIUpdateInterface *ai = owner->getAI();
  5744. Object* crate = ai->checkForCrateToPickup();
  5745. if (crate)
  5746. {
  5747. m_huntMachine->setGoalObject(crate);
  5748. m_huntMachine->setState( AI_PICK_UP_CRATE );
  5749. return STATE_CONTINUE;
  5750. }
  5751. m_nextEnemyScanTime = now + ENEMY_SCAN_RATE;
  5752. const AttackPriorityInfo *info = NULL;
  5753. info = ai->getAttackInfo();
  5754. // Check if team auto targets same victim.
  5755. Object* teamVictim = NULL;
  5756. if (owner->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget)
  5757. {
  5758. teamVictim = owner->getTeam()->getTeamTargetObject();
  5759. }
  5760. Object* victim = NULL;
  5761. if (teamVictim && info==NULL)
  5762. {
  5763. victim = teamVictim;
  5764. }
  5765. else
  5766. {
  5767. // do NOT do line of sight check - we want to find everything
  5768. victim = TheAI->findClosestEnemy( owner, 9999.9f, AI::CAN_ATTACK, info );
  5769. if (victim==NULL && owner->getControllingPlayer() && owner->getControllingPlayer()->getUnitsShouldHunt()) {
  5770. // If we are doing an all hunt, try hunting without the attack priority info. jba.
  5771. victim = TheAI->findClosestEnemy(owner, 9999.9f, AI::CAN_ATTACK, NULL);
  5772. }
  5773. if (owner->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget)
  5774. {
  5775. // Check priorities.
  5776. if (teamVictim && info) {
  5777. if (victim==NULL) {
  5778. DEBUG_LOG(("Couldnt' find victim. hmm."));
  5779. victim = teamVictim;
  5780. }
  5781. Int teamVictimPriority = info->getPriority(teamVictim->getTemplate());
  5782. Int victimPriority;
  5783. if( victim )
  5784. victimPriority = info->getPriority(victim->getTemplate());
  5785. else
  5786. victimPriority = 0;
  5787. if (teamVictimPriority>=victimPriority) {
  5788. victim = teamVictim;
  5789. }
  5790. }
  5791. owner->getTeam()->setTeamTargetObject(victim);
  5792. }
  5793. }
  5794. m_huntMachine->setGoalObject( victim );
  5795. if (m_huntMachine->getCurrentStateID() == AI_IDLE && victim)
  5796. {
  5797. m_huntMachine->setState( AI_ATTACK_OBJECT );
  5798. }
  5799. if (owner->getControllingPlayer() && owner->getControllingPlayer()->getUnitsShouldHunt()==FALSE) {
  5800. // If we are not doing an all hunt, then exit hunt state - no more victims.
  5801. if (m_huntMachine->getCurrentStateID() == AI_IDLE && victim==NULL) {
  5802. return STATE_SUCCESS; // we killed everything :) jba.
  5803. }
  5804. }
  5805. }
  5806. getMachine()->lock("AIHuntState::update"); // The idle state in the sub machine can sometimes acquire targets.
  5807. // It is important to not switch out of this state via a sub machine call. jba.
  5808. /*
  5809. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  5810. sleeps, we still need to be called every frame.
  5811. */
  5812. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  5813. StateReturnType ret = CONVERT_SLEEP_TO_CONTINUE(m_huntMachine->updateStateMachine());
  5814. getMachine()->unlock();
  5815. return ret;
  5816. }
  5817. //----------------------------------------------------------------------------------------------------------
  5818. //----------------------------------------------------------------------------------------------------------
  5819. //----------------------------------------------------------------------------------------------------------
  5820. //----------------------------------------------------------------------------------------------------------
  5821. AIAttackAreaState::~AIAttackAreaState()
  5822. {
  5823. if (m_attackMachine) {
  5824. m_attackMachine->halt();
  5825. m_attackMachine->deleteInstance();
  5826. }
  5827. }
  5828. // ------------------------------------------------------------------------------------------------
  5829. /** CRC */
  5830. // ------------------------------------------------------------------------------------------------
  5831. void AIAttackAreaState::crc( Xfer *xfer )
  5832. {
  5833. } // end crc
  5834. // ------------------------------------------------------------------------------------------------
  5835. /** Xfer Method */
  5836. // ------------------------------------------------------------------------------------------------
  5837. void AIAttackAreaState::xfer( Xfer *xfer )
  5838. {
  5839. // version
  5840. XferVersion currentVersion = 1;
  5841. XferVersion version = currentVersion;
  5842. xfer->xferVersion( &version, currentVersion );
  5843. Bool hasMachine = m_attackMachine!=NULL;
  5844. xfer->xferBool(&hasMachine);
  5845. if (hasMachine && m_attackMachine==NULL) {
  5846. // create new state machine for hunt behavior
  5847. m_attackMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  5848. }
  5849. if (hasMachine) {
  5850. xfer->xferSnapshot(m_attackMachine);
  5851. }
  5852. xfer->xferUnsignedInt(&m_nextEnemyScanTime);
  5853. } // end xfer
  5854. // ------------------------------------------------------------------------------------------------
  5855. /** Load post process */
  5856. // ------------------------------------------------------------------------------------------------
  5857. void AIAttackAreaState::loadPostProcess( void )
  5858. {
  5859. } // end loadPostProcess
  5860. #ifdef STATE_MACHINE_DEBUG
  5861. //----------------------------------------------------------------------------------------------------------
  5862. AsciiString AIAttackAreaState::getName( ) const
  5863. {
  5864. AsciiString name = m_name;
  5865. name.concat("/");
  5866. if (m_attackMachine) name.concat(m_attackMachine->getCurrentStateName());
  5867. else name.concat("*NULL m_attackMachine");
  5868. return name;
  5869. }
  5870. #endif
  5871. //----------------------------------------------------------------------------------------------------------
  5872. StateReturnType AIAttackAreaState::onEnter()
  5873. {
  5874. // create new state machine for hunt behavior
  5875. m_attackMachine = newInstance(AIAttackThenIdleStateMachine)( getMachineOwner(), "AIAttackThenIdleStateMachine");
  5876. // first time thru, use a random amount so that everyone doesn't scan on the same frame,
  5877. // to avoid "spikes".
  5878. UnsignedInt now = TheGameLogic->getFrame();
  5879. m_nextEnemyScanTime = now + GameLogicRandomValue(0, ENEMY_SCAN_RATE);
  5880. // initial state of hunt state machine
  5881. return m_attackMachine->initDefaultState();
  5882. }
  5883. //----------------------------------------------------------------------------------------------------------
  5884. void AIAttackAreaState::onExit( StateExitType status )
  5885. {
  5886. // destroy the hunt machine
  5887. m_attackMachine->deleteInstance();
  5888. m_attackMachine = NULL;
  5889. }
  5890. //----------------------------------------------------------------------------------------------------------
  5891. StateReturnType AIAttackAreaState::update()
  5892. {
  5893. // look around for better victims every so often
  5894. UnsignedInt now = TheGameLogic->getFrame();
  5895. if (now >= m_nextEnemyScanTime)
  5896. {
  5897. Object* owner = getMachineOwner();
  5898. // if all of our weapons are out of ammo, can't hunt.
  5899. // (this can happen for units which never auto-reload, like the Raptor)
  5900. if (owner->isOutOfAmmo() && !owner->isKindOf(KINDOF_PROJECTILE))
  5901. return STATE_FAILURE;
  5902. // first time thru, add a random amount so that everyone doesn't scan on the same frame,
  5903. // to avoid "spikes". Note that this implementation ensures that this unit checks immediately
  5904. // upon entering this state, then wait a possibly-longer-than-usual time (due to randomness),
  5905. // then settle into a regular schedule.
  5906. m_nextEnemyScanTime = now + ENEMY_SCAN_RATE;
  5907. AIUpdateInterface *ai = owner->getAI();
  5908. if (ai->getAreaToGuard() == NULL)
  5909. return STATE_FAILURE;
  5910. const AttackPriorityInfo *info = NULL;
  5911. info = ai->getAttackInfo();
  5912. PartitionFilterPolygonTrigger polyFilter(ai->getAreaToGuard());
  5913. // do NOT do line of sight check - we want to find everything
  5914. Object *victim = TheAI->findClosestEnemy( owner, 9999.9f, AI::CAN_ATTACK, info, &polyFilter );
  5915. m_attackMachine->setGoalObject( victim );
  5916. if (m_attackMachine->getCurrentStateID() == AI_IDLE && victim)
  5917. {
  5918. m_attackMachine->setState( AI_ATTACK_OBJECT );
  5919. }
  5920. if (victim==NULL) {
  5921. return STATE_SUCCESS;
  5922. }
  5923. }
  5924. getMachine()->lock("AIAttackAreaState::update"); // The idle state in the sub machine can sometimes acquire targets.
  5925. // It is important to not switch out of this state via a sub machine call. jba.
  5926. /*
  5927. Note the use of CONVERT_SLEEP_TO_CONTINUE; even if the sub-machine
  5928. sleeps, we still need to be called every frame.
  5929. */
  5930. /// @todo srj -- find a way to sleep for a number of frames here, if possible
  5931. StateReturnType ret = CONVERT_SLEEP_TO_CONTINUE(m_attackMachine->updateStateMachine());
  5932. getMachine()->unlock();
  5933. return ret;
  5934. }
  5935. //----------------------------------------------------------------------------------------------------------
  5936. //----------------------------------------------------------------------------------------------------------
  5937. //----------------------------------------------------------------------------------------------------------
  5938. // ------------------------------------------------------------------------------------------------
  5939. /** CRC */
  5940. // ------------------------------------------------------------------------------------------------
  5941. void AIFaceState::crc( Xfer *xfer )
  5942. {
  5943. } // end crc
  5944. // ------------------------------------------------------------------------------------------------
  5945. /** Xfer Method */
  5946. // ------------------------------------------------------------------------------------------------
  5947. void AIFaceState::xfer( Xfer *xfer )
  5948. {
  5949. // version
  5950. XferVersion currentVersion = 1;
  5951. XferVersion version = currentVersion;
  5952. xfer->xferVersion( &version, currentVersion );
  5953. xfer->xferBool(&m_canTurnInPlace);
  5954. } // end xfer
  5955. // ------------------------------------------------------------------------------------------------
  5956. /** Load post process */
  5957. // ------------------------------------------------------------------------------------------------
  5958. void AIFaceState::loadPostProcess( void )
  5959. {
  5960. // empty. jba.
  5961. } // end loadPostProcess
  5962. //----------------------------------------------------------------------------------------------------------
  5963. StateReturnType AIFaceState::onEnter()
  5964. {
  5965. Object* source = getMachineOwner();
  5966. AIUpdateInterface* ai = source->getAI();
  5967. Locomotor* curLoco = ai->getCurLocomotor();
  5968. m_canTurnInPlace = curLoco ? curLoco->getMinSpeed() == 0.0f : false;
  5969. Object* target = getMachineGoalObject();
  5970. if (m_obj && target == NULL )
  5971. {
  5972. // Nothing to face...
  5973. return STATE_FAILURE;
  5974. }
  5975. return STATE_CONTINUE;
  5976. }
  5977. //----------------------------------------------------------------------------------------------------------
  5978. void AIFaceState::onExit( StateExitType status )
  5979. {
  5980. }
  5981. //----------------------------------------------------------------------------------------------------------
  5982. StateReturnType AIFaceState::update()
  5983. {
  5984. Object *obj = getMachineOwner();
  5985. AIUpdateInterface *ai = obj->getAI();
  5986. const Coord3D* pos = getMachineGoalPosition();
  5987. if (m_obj)
  5988. {
  5989. Object *target = getMachineGoalObject();
  5990. if (!target)
  5991. {
  5992. // Nothing to face.
  5993. return STATE_FAILURE;
  5994. }
  5995. pos = target->getPosition();
  5996. }
  5997. Real relAngle = ThePartitionManager->getRelativeAngle2D( obj, pos );
  5998. const Real REL_THRESH = 0.035f; // about 2 degrees. (getRelativeAngle2D is current only accurate to about 1.25 degrees)
  5999. if( fabs( relAngle ) < REL_THRESH )
  6000. {
  6001. return STATE_SUCCESS;
  6002. }
  6003. // turnDelta = yawRate() NO, do not get this, it is not useful. (srj)
  6004. if (m_canTurnInPlace)
  6005. {
  6006. Real desiredAngle = obj->getOrientation() + relAngle;
  6007. ai->setLocomotorGoalOrientation( desiredAngle );
  6008. }
  6009. else
  6010. {
  6011. ai->setLocomotorGoalPositionExplicit(*pos);
  6012. }
  6013. return STATE_CONTINUE;
  6014. }